summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoredwin <edwin@99606f1f-bbb2-4562-8e6b-387ddef1dc61>2010-01-03 01:43:19 (GMT)
committer edwin <edwin@99606f1f-bbb2-4562-8e6b-387ddef1dc61>2010-01-03 01:43:19 (GMT)
commitcc833cf8907586819d6ed2f5d5230258a13af906 (patch)
tree4672ff85f531d4d91e1f36e67079920408664853
inital commit
git-svn-id: https://open.syn3.nl/syn3/svndav/default/trunk/projects/synapse@159 99606f1f-bbb2-4562-8e6b-387ddef1dc61
-rw-r--r--CMakeLists.txt25
-rw-r--r--COPYING340
-rw-r--r--Doxyfile311
-rw-r--r--README30
-rw-r--r--ccall.cpp31
-rw-r--r--ccall.h37
-rw-r--r--ccallman.cpp128
-rw-r--r--ccallman.h40
-rw-r--r--cevent.cpp125
-rw-r--r--cevent.h54
-rw-r--r--cgroup.cpp33
-rw-r--r--cgroup.h35
-rw-r--r--clog.cpp16
-rw-r--r--clog.h62
-rw-r--r--cmessageman.cpp540
-rw-r--r--cmessageman.h99
-rw-r--r--cmodule.cpp229
-rw-r--r--cmodule.h84
-rw-r--r--cmsg.cpp30
-rw-r--r--cmsg.h78
-rw-r--r--cnet.cpp279
-rw-r--r--cnet.h103
-rw-r--r--cnetman.cpp228
-rw-r--r--cnetman.h74
-rw-r--r--common.h17
-rw-r--r--csession.cpp71
-rw-r--r--csession.h50
-rw-r--r--cuser.cpp96
-rw-r--r--cuser.h46
-rw-r--r--cuserman.cpp243
-rw-r--r--cuserman.h53
-rw-r--r--cvar.cpp140
-rw-r--r--cvar.h52
-rw-r--r--main.cpp20
-rw-r--r--modules/CMakeLists.txt12
-rw-r--r--modules/core.module/CMakeLists.txt28
-rw-r--r--modules/core.module/module.cpp566
-rw-r--r--modules/lirc.module/CMakeLists.txt28
-rw-r--r--modules/lirc.module/module.cpp98
-rw-r--r--modules/net.module/CMakeLists.txt28
-rw-r--r--modules/net.module/module.cpp171
-rw-r--r--modules/test.module/CMakeLists.txt28
-rw-r--r--modules/test.module/module.cpp62
-rw-r--r--modules/test_net_loop.module/CMakeLists.txt28
-rw-r--r--modules/test_net_loop.module/module.cpp200
-rw-r--r--modules/timer.module/CMakeLists.txt28
-rw-r--r--modules/timer.module/module.cpp73
-rw-r--r--synapse.h128
-rw-r--r--synapse.kdevelop232
-rw-r--r--synapse.kdevelop.filelist66
-rw-r--r--synapse.kdevses50
51 files changed, 5625 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..3699d0e
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 2.6)
+
+PROJECT(synapse)
+
+#uncomment this for releases or debugs
+#SET(CMAKE_BUILD_TYPE Release)
+SET(CMAKE_BUILD_TYPE Debug)
+
+#if you don't want the full compiler output, remove the following line
+SET(CMAKE_VERBOSE_MAKEFILE ON)
+
+#add definitions, compiler switches, etc.
+ADD_DEFINITIONS(-Wall -O2 -pthread)
+
+#list all source files here
+file(GLOB sources *.cpp)
+MESSAGE(STATUS "Detected source files: ${sources}")
+ADD_EXECUTABLE(synapse ${sources})
+
+
+#need to link to some other libraries ? just add them here
+TARGET_LINK_LIBRARIES(synapse boost_thread-mt dl boost_regex-mt boost_system-mt)
+
+
+SUBDIRS(modules)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..da6e0fd
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,311 @@
+# Doxyfile 1.5.5-KDevelop
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = synapse
+PROJECT_NUMBER = $VERSION$
+OUTPUT_DIRECTORY =
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = /home/psy/
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+TYPEDEF_HIDES_STRUCT = NO
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = YES
+SHOW_FILES = YES
+SHOW_NAMESPACES = YES
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = /home/psy/svnhobbybop/framework/synapse
+INPUT_ENCODING = UTF-8
+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 \
+ *.vhd \
+ *.vhdl \
+ *.C \
+ *.CC \
+ *.C++ \
+ *.II \
+ *.I++ \
+ *.H \
+ *.HH \
+ *.H++ \
+ *.CS \
+ *.PHP \
+ *.PHP3 \
+ *.M \
+ *.MM \
+ *.PY \
+ *.F90 \
+ *.F \
+ *.VHD \
+ *.VHDL \
+ *.C \
+ *.H \
+ *.tlh \
+ *.diff \
+ *.patch \
+ *.moc \
+ *.xpm \
+ *.dox
+RECURSIVE = yes
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+HTML_DYNAMIC_SECTIONS = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NONE
+TREEVIEW_WIDTH = 250
+FORMULA_FONTSIZE = 10
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = YES
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = yes
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE = synapse.tag
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+MSCGEN_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+DOT_FONTNAME = FreeSans
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/README b/README
new file mode 100644
index 0000000..1a96a1e
--- /dev/null
+++ b/README
@@ -0,0 +1,30 @@
+-----------------------------------------------
+Simple C++ Hello World template based on cmake
+QStart
+Author: Anne-Marie Mahfouf
+Date: 2006-12-06
+-----------------------------------------------
+
+This README file explains you basic things for starting with
+this application template.
+
+-----------------------------------------------
+* REQUIREMENTS *
+- Qt version might be 3.3.4 or 3.3.5
+- kdelibs 3.5 and kdelibs headers 3.5 (devel package) in order to build this template.
+- cmake (http://www.cmake.org/) version 2.1 or 2.2 in your PATH
+-----------------------------------------------
+
+-----------------------------------------------
+* Building and running *
+- cmake will run after the template is loaded provided cmake is in your PATH. If not, you will see an error message in the terminal
+and you will need to install cmake in your PATH.
+- In the Build menu in KDevelop, click on Build Project (or use the F8 shortcut) in order to build your project.
+- Run your project using the Build menu -> Execute Program. Note that default makes your program run in KDevelop integrated terminal. You can run your program in an external terminal by changing the project options (Project -> Project Options -> Run options and check at the bottom "Start in external terminal")
+-----------------------------------------------
+
+-----------------------------------------------
+* Useful link *
+
+CMake Documentation: http://www.cmake.org/HTML/Documentation.html
+
diff --git a/ccall.cpp b/ccall.cpp
new file mode 100644
index 0000000..56faaf5
--- /dev/null
+++ b/ccall.cpp
@@ -0,0 +1,31 @@
+//
+// C++ Implementation: ccall
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "ccall.h"
+
+Ccall::~Ccall()
+{
+}
+
+Ccall::Ccall()
+{
+ started=false;
+}
+
+Ccall::Ccall(const CmsgPtr & msg,const CsessionPtr & dst, FsoHandler soHandler)
+{
+ started=false;
+ this->msg=msg;
+ this->dst=dst;
+ this->soHandler=soHandler;
+}
+
+
diff --git a/ccall.h b/ccall.h
new file mode 100644
index 0000000..8df53d2
--- /dev/null
+++ b/ccall.h
@@ -0,0 +1,37 @@
+//
+// C++ Interface: ccall
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CCALL_H
+#define CCALL_H
+#include "csession.h"
+#include "cmsg.h"
+#include <boost/thread/thread.hpp>
+
+typedef shared_ptr<thread> CthreadPtr;
+
+/**
+ @author
+*/
+class Ccall{
+public:
+ Ccall(const CmsgPtr & msg,const CsessionPtr & dst, FsoHandler soHandler);
+ Ccall();
+
+ ~Ccall();
+ CsessionPtr dst;
+ CmsgPtr msg;
+ FsoHandler soHandler;
+ bool started;
+ CthreadPtr threadPtr;
+
+};
+
+#endif
diff --git a/ccallman.cpp b/ccallman.cpp
new file mode 100644
index 0000000..50acd97
--- /dev/null
+++ b/ccallman.cpp
@@ -0,0 +1,128 @@
+//
+// C++ Implementation: ccallman
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "ccallman.h"
+#include "clog.h"
+using namespace boost;
+
+CcallMan::CcallMan()
+{
+ statsTotal=0;
+}
+
+
+CcallMan::~CcallMan()
+{
+}
+
+
+
+
+/*!
+ \fn CcallMan::addCall(CmsgPtr msg, CsessionPtr dst)
+ */
+bool CcallMan::addCall(const CmsgPtr & msg, const CsessionPtr & dst, FsoHandler soHandler)
+{
+ callList.push_back(Ccall(msg,dst,soHandler));
+ statsTotal++;
+// DEB( "(" << callList.size() << ")" << " " << msg->event << " FROM " << msg->src << " TO " << msg->dst << " CALLDST " << dst->id);
+}
+
+
+
+
+
+
+/*!
+ \fn CcallMan::popCall()
+ */
+CcallList::iterator CcallMan::startCall(const CthreadPtr & threadPtr)
+{
+ //find a call thats ready to go and return it
+ //TODO:optimize
+ for (CcallList::iterator callI=callList.begin(); callI!=callList.end(); callI++)
+ {
+ if (!callI->started && callI->dst->startThread())
+ {
+ callI->threadPtr=threadPtr;
+ callI->started=1;
+// DEB( callI->msg->event << " FROM " << callI->msg->src << " TO " << callI->msg->dst << " CALLDST " << callI->dst->id);
+
+ return callI;
+ }
+ }
+ return CcallList::iterator();
+}
+
+void CcallMan::endCall(CcallList::iterator callI)
+{
+ callI->dst->endThread();
+// DEB( callI->msg->event << " FROM " << callI->msg->src << " TO " << callI->msg->dst << " CALLDST " << callI->dst->id);
+
+ callList.erase(callI);
+// DEB("calls left: " << callList.size());
+}
+
+
+/*!
+ \fn CcallMan::print()
+ */
+void CcallMan::print()
+{
+ DEB( statsTotal << " calls processed, " << callList.size() << " calls queued" );
+ string status;
+ for (CcallList::iterator callI=callList.begin(); callI!=callList.end(); callI++)
+ {
+ if (callI->started)
+ status="RUNNING";
+ else
+ status="QUEUED ";
+
+ DEB(" |" << status << " " << callI->msg->event << " FROM " << callI->msg->src << " TO " <<
+ callI->dst->id << ":" << callI->dst->user->getName() << "@" << callI->dst->module->name
+ << callI->msg->getPrint(" |")
+ );
+ }
+
+ statsTotal=0;
+
+}
+
+bool CcallMan::interruptCall(string event, int src, int dst)
+{
+ for (CcallList::iterator callI=callList.begin(); callI!=callList.end(); callI++)
+ {
+ if (callI->msg->event==event)
+ {
+ if (callI->msg->src==src)
+ {
+ if (dst==0 || dst==callI->dst->id)
+ {
+ //send interrupt
+ if (callI->started && callI->threadPtr)
+ {
+ DEB("Interrupting call: " << event << " FROM " << src << " TO " << dst);
+ callI->threadPtr->interrupt();
+ return (true);
+ }
+ //not started yet, we can just delete it from the queue
+ {
+ DEB("Cancelling call: " << event << " FROM " << src << " TO " << dst);
+ callList.erase(callI);
+ return (true);
+
+ }
+ }
+ }
+ }
+ }
+ return false;
+} \ No newline at end of file
diff --git a/ccallman.h b/ccallman.h
new file mode 100644
index 0000000..b64efa5
--- /dev/null
+++ b/ccallman.h
@@ -0,0 +1,40 @@
+//
+// C++ Interface: ccallman
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CCALLMAN_H
+#define CCALLMAN_H
+#include "cmsg.h"
+#include "csession.h"
+#include "ccall.h"
+
+/**
+ @author
+*/
+
+typedef list<Ccall> CcallList;
+
+class CcallMan{
+public:
+ CcallMan();
+
+ ~CcallMan();
+ bool addCall(const CmsgPtr & msg, const CsessionPtr & dst, FsoHandler soHandler);
+ CcallList::iterator startCall(const CthreadPtr & threadPtr);
+ void endCall(CcallList::iterator callI);
+ bool interruptCall(string event, int src, int dst);
+ void print();
+ int statsTotal;
+
+ CcallList callList;
+
+};
+
+#endif
diff --git a/cevent.cpp b/cevent.cpp
new file mode 100644
index 0000000..5371681
--- /dev/null
+++ b/cevent.cpp
@@ -0,0 +1,125 @@
+//
+// C++ Implementation: cevent
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "clog.h"
+#include "cevent.h"
+#include <iostream>
+
+
+Cevent::Cevent(const CgroupPtr & modifyGroup, const CgroupPtr & sendGroup, const CgroupPtr & recvGroup )
+{
+ this->modifyGroup=modifyGroup;
+ this->sendGroup=sendGroup;
+ this->recvGroup=recvGroup;
+}
+
+
+Cevent::~Cevent()
+{
+}
+
+
+
+
+
+bool Cevent::isSendAllowed(const CuserPtr & user)
+{
+ return (
+ user &&
+ (
+ (sendGroup && user->isMemberGroup(sendGroup))
+ )
+ );
+}
+
+bool Cevent::isSendAllowed(const CgroupPtr & group)
+{
+ return (group && sendGroup && group==sendGroup);
+}
+
+bool Cevent::isRecvAllowed(const CuserPtr & user)
+{
+
+ return (
+ user &&
+ (
+ (recvGroup && user->isMemberGroup(recvGroup))
+ )
+ );
+}
+
+bool Cevent::isRecvAllowed(const CgroupPtr & group)
+{
+ return (group && recvGroup && group==recvGroup);
+}
+
+
+bool Cevent::isModifyAllowed(const CuserPtr & user)
+{
+ return (
+ user &&
+ (
+ (modifyGroup && user->isMemberGroup(modifyGroup))
+ )
+ );
+}
+
+
+/*!
+ \fn Cevent::setSendGroup(CgroupPtr group)
+ */
+void Cevent::setSendGroup(const CgroupPtr & group)
+{
+ sendGroup=group;
+}
+
+
+/*!
+ \fn Cevent::setRecvGroup(CgroupPtr group)
+ */
+void Cevent::setRecvGroup(const CgroupPtr & group)
+{
+ recvGroup=group;
+}
+
+void Cevent::setModifyGroup(const CgroupPtr & group)
+{
+ modifyGroup=group;
+}
+
+
+/*!
+ \fn Cevent::setOwner(CuserPtr user)
+ */
+// void Cevent::setOwner(const CuserPtr & user)
+// {
+// owner=user;
+// }
+
+
+/*!
+ \fn Cevent::isOwner(const CuserPtr user)
+ */
+// bool Cevent::isOwner(const CuserPtr user)
+// {
+// return (owner==user);
+// }
+
+
+/*!
+ \fn Cevent::print()
+ */
+void Cevent::print()
+{
+ DEB("recvGroup =" << recvGroup->getName());
+ DEB("sendGroup =" << sendGroup->getName());
+ DEB("modifyGroup=" << modifyGroup->getName());
+}
diff --git a/cevent.h b/cevent.h
new file mode 100644
index 0000000..6281180
--- /dev/null
+++ b/cevent.h
@@ -0,0 +1,54 @@
+//
+// C++ Interface: cevent
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CEVENT_H
+#define CEVENT_H
+#include <string>
+#include "cgroup.h"
+#include "cuser.h"
+
+#include <boost/shared_ptr.hpp>
+using namespace boost;
+using namespace std;
+
+
+
+/**
+ @author
+*/
+class Cevent{
+public:
+ Cevent(const CgroupPtr & modifyGroup, const CgroupPtr & sendGroup, const CgroupPtr & recvGroup );
+
+ ~Cevent();
+ bool isSendAllowed(const CuserPtr & user);
+ bool isRecvAllowed(const CuserPtr & user);
+ bool isSendAllowed(const CgroupPtr & group);
+ bool isRecvAllowed(const CgroupPtr & group);
+ bool isModifyAllowed(const CuserPtr & user);
+
+ void setRecvGroup(const CgroupPtr & group);
+ void setSendGroup(const CgroupPtr & group);
+ void setModifyGroup(const CgroupPtr & group);
+ void print();
+
+
+private:
+
+ CgroupPtr sendGroup;
+ CgroupPtr recvGroup;
+ CgroupPtr modifyGroup;
+
+};
+
+typedef shared_ptr<Cevent> CeventPtr;
+
+#endif
diff --git a/cgroup.cpp b/cgroup.cpp
new file mode 100644
index 0000000..7f95536
--- /dev/null
+++ b/cgroup.cpp
@@ -0,0 +1,33 @@
+//
+// C++ Implementation: cgroup
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "cgroup.h"
+
+Cgroup::Cgroup(const string & name)
+{
+ this->name=name;
+}
+
+
+Cgroup::~Cgroup()
+{
+}
+
+
+
+
+/*!
+ \fn Cgroup::getName()
+ */
+string Cgroup::getName()
+{
+ return (name);
+}
diff --git a/cgroup.h b/cgroup.h
new file mode 100644
index 0000000..31193a7
--- /dev/null
+++ b/cgroup.h
@@ -0,0 +1,35 @@
+//
+// C++ Interface: cgroup
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CGROUP_H
+#define CGROUP_H
+#include <boost/shared_ptr.hpp>
+#include <string>
+using namespace boost;
+using namespace std;
+
+/**
+ @author
+*/
+class Cgroup{
+public:
+ Cgroup(const string & name);
+
+ ~Cgroup();
+ string getName();
+private:
+ string name;
+
+};
+
+typedef shared_ptr<Cgroup> CgroupPtr;
+
+#endif
diff --git a/clog.cpp b/clog.cpp
new file mode 100644
index 0000000..0036b38
--- /dev/null
+++ b/clog.cpp
@@ -0,0 +1,16 @@
+//
+// C++ Implementation: clog
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "clog.h"
+#include <iostream>
+#include <boost/thread/mutex.hpp>
+
+boost::mutex logMutex;
diff --git a/clog.h b/clog.h
new file mode 100644
index 0000000..fbd0da7
--- /dev/null
+++ b/clog.h
@@ -0,0 +1,62 @@
+//
+// C++ Interface: clog
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CLOG_H
+#define CLOG_H
+
+
+#include <string>
+#include <iostream>
+#include <boost/thread/thread.hpp>
+
+extern boost::mutex logMutex;
+
+//colors and ansi stuff (we dont want ncurses YET)
+#define TERM_BACK_UP "\033[1K\033[0G"
+#define TERM_NORMAL "\033[0m"
+#define TERM_WARN "\033[33;1m"
+#define TERM_BAD "\033[31;1m"
+#define TERM_SEND_MESSAGE "\033[32;1m"
+#define TERM_RECV_MESSAGE "\033[34;1m"
+#define TERM_BOLD "\033[1m"
+
+
+//thread-safe 'wrapper' around cout:
+#define LOG(s) \
+ { \
+ boost::lock_guard<boost::mutex> lock(logMutex); \
+ cout << s; \
+ }
+
+//debug output with extra info:
+#ifndef NDEBUG
+#define DEB(s) LOG (boost::this_thread::get_id() << " " << "DEB: " << __PRETTY_FUNCTION__ << " - " << s << endl)
+#else
+#define DEB(s)
+#endif
+
+//normal info:
+#define INFO(s) LOG(boost::this_thread::get_id() << " " << TERM_BOLD << "INFO: " << s << TERM_NORMAL << endl)
+
+//errors:
+#define ERROR(s) LOG(boost::this_thread::get_id() << " " << TERM_BAD << "ERROR: " << s << TERM_NORMAL << endl)
+
+//warnings:
+#define WARNING(s) LOG(boost::this_thread::get_id() << " " << TERM_WARN << "WARNING: " << s << TERM_NORMAL << endl)
+
+//messages:
+#define LOG_SEND(s) LOG(boost::this_thread::get_id() << " " << TERM_SEND_MESSAGE << s << TERM_NORMAL << endl)
+#define LOG_RECV(s) LOG(boost::this_thread::get_id() << " " << TERM_RECV_MESSAGE << s << TERM_NORMAL << endl)
+
+
+
+
+#endif
diff --git a/cmessageman.cpp b/cmessageman.cpp
new file mode 100644
index 0000000..33a2af2
--- /dev/null
+++ b/cmessageman.cpp
@@ -0,0 +1,540 @@
+//
+// C++ Implementation: cmessageman
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "cmessageman.h"
+#include "cmsg.h"
+#include "clog.h"
+#include "ccall.h"
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/bind.hpp>
+#include <dlfcn.h>
+#include "csession.h"
+#include "cmodule.h"
+
+using namespace boost;
+
+CmessageMan::CmessageMan()
+{
+ logSends=true;
+ logReceives=true;
+// defaultOwner=userMan.getUser("module");
+ defaultSendGroup=userMan.getGroup("modules");
+ defaultModifyGroup=userMan.getGroup("modules");
+ defaultRecvGroup=userMan.getGroup("everyone");
+
+ activeThreads=0;
+ currentThreads=0;
+ maxActiveThreads=0;
+ wantCurrentThreads=1;
+ maxThreads=1000;
+ shutdown=false;
+}
+
+
+CmessageMan::~CmessageMan()
+{
+}
+
+
+
+
+/*!
+ \fn CmessageMan::sendMessage(const Cmsg & msg) */
+bool CmessageMan::sendMessage(const CmodulePtr &module, const CmsgPtr & msg)
+{
+ // -module is a pointer thats set by the core and can be trusted
+ // -msg is set by the user and only containts direct objects, and NO pointers. it cant be trusted yet!
+ // -our job is to verify if everything is ok and populate the call queue
+ // -internally the core only works with smartpointers, so most stuff thats not in msg will be a smartpointer.
+
+
+ //no src session specified means use default session of module:
+ //NOTE: this is the only case where modify the actual msg object.
+ if (!msg->src)
+ msg->src=module->defaultSessionId;
+
+
+ //resolve source session id to session a pointer
+ //(its mandatory to have a valid session when sending stuff!)
+ CsessionPtr src;
+ src=userMan.getSession(msg->src);
+ if (!src)
+ {
+ //not found. we cant send an error back yet, so just return false
+ ERROR("send: in module " << module->name << " session " << msg->src << " does not exist");
+ return false;
+ }
+
+ //source session belongs to this module?
+ if (src->module!=module)
+ {
+ //module is not the session owner. we cant send an error back yet, so just return false
+ ERROR("send: module " << module->name << " does not own session " << msg->src );
+ return false;
+ }
+
+
+ //resolve or create the event:
+ CeventPtr event=getEvent(msg->event);
+
+ //check if src is allowed to SEND:
+ if (!event->isSendAllowed(src->user))
+ {
+ ERROR("send: session " << msg->src << " with user " << src->user->getName() << " is not allowed to send event " << msg->event);
+ return false;
+ }
+
+
+ stringstream msgStr;
+ if (logSends)
+ {
+ //build a text-representaion of whats happening:
+ msgStr << "SEND " << msg->event <<
+ " FROM " << msg->src << ":" << src->user->getName() << "@" << module->name <<
+ " TO ";
+ }
+
+
+ //check if destination(s) are allowed to RECEIVE:
+ FsoHandler soHandler;
+
+ //destination specified:
+ if (msg->dst!=0)
+ {
+ CsessionPtr dst;
+ dst=userMan.getSession(msg->dst);
+ //found it?
+ if (!dst)
+ {
+ ERROR("send: destination session " << msg->dst << " not found");
+ return false;
+ }
+
+ //get the handler, and does it exist?
+ soHandler=dst->module->getHandler(msg->event);
+ if (soHandler==NULL)
+ {
+ WARNING("send ignored message: no handler for " << msg->event << " found in " << dst->module->name );
+ return false;
+ }
+
+ //is specified destination allowed?
+ if (!event->isRecvAllowed(dst->user))
+ {
+ ERROR("send: session " << msg->dst << " with user " << dst->user->getName() << " is not allowed to receive event " << msg->event);
+ return false;
+ }
+
+ if (logSends)
+ {
+ msgStr << msg->dst << ":" << dst->user->getName() << "@" << dst->module->name <<
+ msg->getPrint(" |");
+ LOG_SEND(msgStr.str());
+ }
+
+ //all checks ok:
+ //make a copy of the message and add the destionation + handler to the call queue
+ callMan.addCall(msg, dst, soHandler);
+
+ //wake up a thread that calls the actual handler
+ threadCond.notify_one();
+
+
+ return true;
+ }
+ //no destination specified == broadcast
+ else
+ {
+ if (logSends)
+ {
+ msgStr << "broadcast (";
+ }
+
+ //make a copy of the message object and keep the pointer:
+ CmsgPtr msgPtr(new Cmsg(*msg));
+ //TODO:optimize these broadcasting algoritms
+ CsessionPtr dst;
+ bool delivered=false;
+ for (int sessionId=0; sessionId<MAX_SESSIONS; sessionId++)
+ {
+ dst=userMan.getSession(sessionId);
+ //session exists and is still active?
+ if (dst && dst->isEnabled())
+ {
+ //session owner is allowed to receive the event?
+ if (event->isRecvAllowed(dst->user))
+ {
+ //modules always receive the event on the defaultsession
+ //OR on all sessions when broadcastMulti is true
+ if (dst->module->defaultSessionId==sessionId || dst->module->broadcastMulti)
+ {
+ //get the handler, and does it exist?
+ soHandler=dst->module->getHandler(msg->event);
+ if (soHandler!=NULL)
+ {
+ if (logSends)
+ msgStr << dst->id << ":" << dst->user->getName() << "@" << dst->module->name << " ";
+
+
+ callMan.addCall(msg, dst, soHandler);
+ threadCond.notify_one();
+ delivered=true;
+ }
+ }
+ }
+ }
+ }
+ if (logSends)
+ {
+ msgStr << ")" <<
+ msg->getPrint(" |");
+ LOG_SEND(msgStr.str());
+ }
+
+ if (!delivered)
+ WARNING("broadcast " << msg->event << " was not received by anyone.")
+ return (true);
+ }
+}
+
+void CmessageMan::operator()()
+{
+ CthreadPtr threadPtr;
+ //init thread
+ {
+ lock_guard<mutex> lock(threadMutex);
+ DEB("thread started");
+ activeThread();
+ //get a pointer to our own thread object and remove it from the threadmap
+ threadPtr=threadMap[this_thread::get_id()];
+ threadMap.erase(this_thread::get_id());
+ }
+
+ CcallList::iterator callI;
+
+ //thread main-loop
+ while(1)
+ {
+ //locking and call getting stuff...
+ {
+ //no interrupts here
+ boost::this_thread::disable_interruption di;
+
+ //lock core
+ unique_lock<mutex> lock(threadMutex);
+
+
+ //end previous call
+ if (callI!=CcallList::iterator())
+ {
+ callMan.endCall(callI);
+ }
+
+ //get next call
+ while ((callI=callMan.startCall(threadPtr)) == CcallList::iterator() || shutdown)
+ {
+ //no call ready...
+ //indicate we're idle
+ if (!idleThread())
+ {
+ //we need to die :(
+ DEB("thread ending");
+ return;
+ }
+ //unlock+sleep until we get signalled
+ threadCond.wait(lock);
+
+ //indicate we're active
+ activeThread();
+ }
+
+ //check if we need more threads
+ checkThread();
+
+ } //unlock core
+
+ if (logReceives)
+ {
+
+ stringstream msgStr;
+ msgStr << "RECV " << callI->msg->event <<
+ " FROM " << callI->msg->src <<
+ " BY " << callI->dst->id << ":" << callI->dst->user->getName() << "@" << callI->dst->module->name <<
+ callI->msg->getPrint(" |");
+
+ LOG_RECV(msgStr.str());
+ }
+
+ //handle call
+ try
+ {
+ callI->soHandler(*(callI->msg), callI->dst->id);
+ }
+ catch (std::exception& e)
+ {
+ //return std::exceptions as error events
+ lock_guard<mutex> lock(threadMutex);
+
+ ERROR("exception while handling " << callI->msg->event << ": " << e.what());
+ CmsgPtr error(new Cmsg);
+ (*error).event="module_Error";
+ (*error).dst=callI->msg->src;
+ (*error).src=callI->dst->id;
+ (*error)["event"]=callI->msg->event;
+ (*error)["description"]="Exception: " + string(e.what());
+ (*error)["parameters"]=(*callI->msg);
+ sendMessage(callI->dst->module, error);
+ }
+ catch(...)
+ {
+ //return other exceptions as error events
+ lock_guard<mutex> lock(threadMutex);
+
+ ERROR("unknown exception while handling " << callI->msg->event);
+ CmsgPtr error(new Cmsg);
+ (*error).event="module_Error";
+ (*error).dst=callI->msg->src;
+ (*error).src=callI->dst->id;
+ (*error)["event"]=callI->msg->event;
+ (*error)["description"]="Unknown exception";
+ (*error)["parameters"]=(*callI->msg);
+ sendMessage(callI->dst->module, error);
+
+ }
+ }
+}
+
+/*!
+ \fn CmessageMan::startThread()
+ called when thread is getting active
+ */
+void CmessageMan::activeThread()
+{
+ activeThreads++;
+ //keep maximum active threads, so the reaper knows when there are too much threads
+ if (activeThreads>maxActiveThreads)
+ maxActiveThreads=activeThreads;
+
+}
+
+
+
+/*!
+ \fn CmessageMan::endThread()
+ called when thread is ready and does nothing
+ */
+bool CmessageMan::idleThread()
+{
+ activeThreads--;
+ //we want less threads? let this one die by returning false
+ if (wantCurrentThreads<currentThreads || shutdown)
+ {
+ currentThreads--;
+ return false;
+ }
+ return true;
+}
+
+
+/*!
+ \fn CmessageMan::checkThread()
+ called while thread is active to see if we need more threads
+ */
+void CmessageMan::checkThread()
+{
+ if (shutdown)
+ return;
+
+ //if all threads are active, indicate that we want one want one more
+ //(there always should be a least one idle thread)
+ if (activeThreads>=wantCurrentThreads)
+ {
+ wantCurrentThreads=activeThreads+1;
+ }
+
+ //we want more threads? start another one
+ while (wantCurrentThreads>currentThreads && currentThreads<maxThreads)
+ {
+ //then start a new thread
+ DEB(activeThreads << "/" << currentThreads << " threads active, starting one more...");
+ currentThreads++;
+
+ CthreadPtr threadPtr(new thread(boost::ref(*this)));
+ threadMap[threadPtr->get_id()]=threadPtr;
+ //note: the new thread will execute this->operator()
+ }
+}
+
+
+
+
+/*!
+ \fn CmessageMan::run()
+ */
+int CmessageMan::run(string coreName, string moduleName)
+{
+// test();
+
+ //Cmodule module;
+
+
+ //load the first module as user core UNLOCKED!
+ loadModule(coreName, "core");
+ this->firstModuleName=moduleName;
+
+ //start first thread:
+ checkThread();
+
+ //thread manager loop
+ while (1)
+ {
+ sleep(10);
+
+ //lock core and do our stuff
+ {
+ lock_guard<mutex> lock(threadMutex);
+ DEB(maxActiveThreads << "/" << wantCurrentThreads << " threads active.");
+ callMan.print();
+ userMan.print();
+
+ if (shutdown)
+ break;
+
+ if (maxActiveThreads<wantCurrentThreads-1)
+ {
+ wantCurrentThreads--;
+ threadCond.notify_one();
+
+ DEB("maxActiveThreads was " << maxActiveThreads << " so deceasing wantCurrentThreads to " << wantCurrentThreads);
+ }
+ maxActiveThreads=activeThreads;
+ }
+
+ }
+
+ //shutdown loop
+ while(1)
+ {
+
+ {
+ lock_guard<mutex> lock(threadMutex);
+ if (currentThreads)
+ {
+ INFO("shutting down - waiting for threads to end:" << currentThreads);
+ threadCond.notify_all();
+ }
+ else
+ {
+ break;
+ }
+ }
+ sleep(1);
+ }
+
+ //FIXME: are all threads really ended? its possible they still exist for a very short time, after they decreased the currentThread-counter.
+ sleep(1);
+ INFO("all threads ended, cleaning up...");
+ return(exit);
+}
+
+
+
+
+/*!
+ \fn CmessageMan::loadModule(string name)
+ */
+CsessionPtr CmessageMan::loadModule(string path, string userName)
+{
+ CmodulePtr module(new Cmodule);
+
+ //modules get unloaded automaticly when the module-object is deleted:
+ if (module->load(path))
+ {
+ CuserPtr user(userMan.getUser(userName));
+ if (user)
+ {
+ //we need a session for the init function of the core-module:
+ CsessionPtr session(new Csession(user,module));
+ module->defaultSessionId=userMan.addSession(session);
+
+ DEB("Init module " << module->name);
+ if (module->soInit(this ,module))
+ {
+ DEB("Init " << module->name << " complete");
+ return session;
+ }
+ userMan.delSession(module->defaultSessionId);
+ ERROR("Error while initalizing module");
+ }
+ }
+
+ return CsessionPtr();
+}
+
+
+/*!
+ \fn CmessageMan::getEvent(const & string name)
+ */
+CeventPtr CmessageMan::getEvent(const string & name)
+{
+ CeventHashMap::iterator eventI;
+ eventI=events.find(name);
+ //not found?
+ if (eventI==events.end())
+ {
+ DEB("adding new event: " << name);
+ CeventPtr event(new Cevent(defaultModifyGroup, defaultSendGroup, defaultRecvGroup));
+ events[name]=event;
+ return (event);
+ }
+ else
+ {
+ return eventI->second;
+ }
+}
+
+
+
+
+
+/*!
+ \fn CmessageMan::isModuleReady(string name)
+ */
+bool CmessageMan::isModuleReady(string path)
+{
+ CsessionPtr session;
+ string name;
+ name=Cmodule().getName(path);
+
+ for (int sessionId=0; sessionId<MAX_SESSIONS; sessionId++)
+ {
+ session=userMan.getSession(sessionId);
+ //session exists and is still active, and its the module?
+ if (session && session->isEnabled() && session->module->name==name)
+ {
+ return (session->module->ready);
+ }
+ }
+ return false;
+}
+
+
+/*!
+ \fn CmessageMan::doShutdown()
+ */
+void CmessageMan::doShutdown(int exit=0)
+{
+ WARNING("Shutdown requested, exit code="<<exit);
+ shutdown=1;
+ this->exit=exit;
+ threadCond.notify_all();
+}
diff --git a/cmessageman.h b/cmessageman.h
new file mode 100644
index 0000000..5e7adf7
--- /dev/null
+++ b/cmessageman.h
@@ -0,0 +1,99 @@
+//
+// C++ Interface: cmessageman
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CMESSAGEMAN_H
+#define CMESSAGEMAN_H
+
+
+#include <string>
+#include <map>
+#include "cevent.h"
+#include "common.h"
+#include <hash_map.h>
+#include "cuserman.h"
+//#include "cmodule.h"
+#include "cmsg.h"
+#include "ccallman.h"
+#include <boost/thread/thread.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+
+/*
+ This is the main object.
+ All the thread magic and locking happens in here.
+ The other classes are not threadsafe!
+*/
+
+
+using namespace std;
+using namespace boost;
+
+/**
+ @author
+*/
+
+
+class CmessageMan{
+public:
+ CmessageMan();
+
+ ~CmessageMan();
+ bool sendMessage(const CmodulePtr & modulePtr, const CmsgPtr & msg);
+ //these are the threads:
+ void operator()();
+ int run(string coreName,string moduleName);
+ void checkThread();
+ CsessionPtr loadModule(string path, string userName);
+ CeventPtr getEvent(const string & name);
+ bool isModuleReady(string path);
+ void doShutdown(int exit);
+
+ mutex threadMutex;
+ CuserMan userMan;
+ CcallMan callMan;
+
+ bool logSends;
+ bool logReceives;
+
+ //initial module that user want to start, after the coremodule is started:
+ string firstModuleName;
+
+private:
+ condition_variable threadCond;
+
+
+ //TODO: we COULD do this with a hash map, but stl doesnt has a good one and boost only has Unordered from 1.36 or higher. but its fast enough for now. (tested with 10000)
+ typedef map<string, CeventPtr> CeventHashMap;
+ CeventHashMap events;
+
+
+ map<thread::id,CthreadPtr> threadMap;
+ int currentThreads; //number of threads in memory
+ int wantCurrentThreads; //number of threads we want. threads will be added/deleted accordingly.
+ int maxThreads; //max number of threads. system will never create more then this many
+ int activeThreads; //threads that are actually executing actively
+ int maxActiveThreads; //max number of active threads seen (reset every X seconds by reaper)
+ bool shutdown; //program shutdown: end all threads
+ int exit; //shutdown exit code
+
+ bool idleThread();
+ void activeThread();
+
+ CgroupPtr defaultRecvGroup;
+ CgroupPtr defaultSendGroup;
+ CgroupPtr defaultModifyGroup;
+ //CuserPtr defaultOwner;
+
+};
+
+
+
+#endif
diff --git a/cmodule.cpp b/cmodule.cpp
new file mode 100644
index 0000000..570dac3
--- /dev/null
+++ b/cmodule.cpp
@@ -0,0 +1,229 @@
+//
+// C++ Implementation: cmodule
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "cmodule.h"
+#include "clog.h"
+#include <dlfcn.h>
+#include <boost/regex.hpp>
+
+
+
+
+Cmodule::Cmodule()
+{
+ maxThreads=1;
+ currentThreads=0;
+ broadcastMulti=false;
+ soHandle=NULL;
+ defaultSessionId=SESSION_DISABLED;
+ soDefaultHandler=NULL;
+ ready=false;
+
+}
+
+
+Cmodule::~Cmodule()
+{
+ //unload the module on destruction.
+ //Destruction only happens when nobody is using the Cmodule object anymore, since we only
+ //use shared_ptrs.
+ if (soHandle)
+ {
+ DEB(name << " is unused - auto unloading");
+ unload();
+ }
+}
+
+
+
+
+/*!
+ \fn Cmodule::startThread()
+ */
+bool Cmodule::startThread()
+{
+ if (currentThreads<maxThreads)
+ {
+ currentThreads++;
+ return true;
+ }
+ return false;
+}
+
+
+/*!
+ \fn Cmodule::endThread()
+ */
+void Cmodule::endThread()
+{
+ currentThreads--;
+ assert(currentThreads>=0);
+}
+
+
+/*!
+ \fn Cmodule::load(string name)
+ */
+bool Cmodule::load(string path)
+{
+ this->name=getName(path);
+ this->path=path;
+ INFO("Loading module " << name << " from: " << path );
+ soHandle=dlopen(path.c_str(),RTLD_NOW);
+ if (soHandle==NULL)
+ {
+ ERROR("Error loading module " << name << ": " << dlerror());
+ }
+ else
+ {
+ //check api version of the module
+ FsoVersion version;
+ version=(FsoVersion)resolve("synapseVersion");
+ if (version!=NULL)
+ {
+ if (version()!=SYNAPSE_API_VERSION)
+ {
+ ERROR("Module " << name << " has API version " << version() << " instead of : " << SYNAPSE_API_VERSION);
+ }
+ else
+ {
+ //init function is MANDATORY
+ soInit=(FsoInit)resolve("synapseInit");
+ if (soInit!=NULL)
+ {
+ INFO("Module loading of " << name << " complete.");
+ return true;
+ }
+ }
+ }
+
+ DEB("Unloading because of previous error");
+ dlclose(soHandle);
+ soHandle=NULL;
+ }
+ return false;
+}
+
+
+/*!
+ \fn Cmodule::unload()
+ */
+bool Cmodule::unload()
+{
+ if (soHandle!=NULL)
+ {
+ INFO("Unloading module " << name);
+
+ FsoCleanup soCleanup;
+ soCleanup=(FsoCleanup)resolve("synapseCleanup");
+ if (soCleanup!=NULL)
+ {
+ DEB("Calling cleanup");
+ soCleanup();
+ }
+
+ DEB("Calling dlclose on " << soHandle);
+ if (dlclose(soHandle))
+ {
+ ERROR("Error unloading module " << name << ": " << dlerror());
+ }
+ DEB("Unload success");
+ }
+ return true;
+}
+
+
+/*!
+ \fn Cmodule::getHandler(string name)
+ */
+FsoHandler Cmodule::getHandler(string eventName)
+{
+ ChandlerHashMap::iterator handlerI;
+ handlerI=handlers.find(eventName);
+ //not found?
+ if (handlerI==handlers.end())
+ {
+ //return default handler
+ return(soDefaultHandler);
+ }
+ else
+ {
+ return (handlerI->second);
+ }
+}
+
+bool Cmodule::setHandler(const string & eventName, const string & functionName)
+{
+ FsoHandler soHandler;
+ soHandler=(FsoHandler)resolve("synapse_"+functionName);
+ if (soHandler!=NULL)
+ {
+ DEB(eventName << " -> " << functionName << "@" << name );
+ handlers[eventName]=soHandler;
+
+ return true;
+ }
+
+ return false;
+
+}
+
+
+/*!
+ \fn Cmodule::resolve(const string * functionName)
+ */
+void * Cmodule::resolve(const string & functionName)
+{
+ if (soHandle==NULL)
+ {
+ ERROR("Cannot resolve function " << functionName << ". There is no module loaded! (yet?)");
+ return NULL;
+ }
+
+ void * function;
+ function=dlsym(soHandle, functionName.c_str());
+ if (function==NULL)
+ {
+ ERROR("Could not find function " << functionName << " in module " << name << ": " << dlerror());
+ }
+ return (function);
+}
+
+
+/*!
+ \fn Cmodule::isLoaded(string path)
+ */
+bool Cmodule::isLoaded(string path)
+{
+ return (dlopen(path.c_str(),RTLD_NOW|RTLD_NOLOAD)!=NULL);
+
+}
+
+
+/*!
+ \fn Cmodule::getName(string path)
+ */
+string Cmodule::getName(string path)
+{
+ //calculate the name from a module path
+ regex expression(".*/lib(.*).so$");
+ cmatch what;
+ if(!regex_match(path.c_str(), what, expression))
+ {
+ ERROR("Cannot determine module name of path " << path);
+ return (path);
+ }
+ else
+ {
+ return (what[1]);
+ }
+
+}
diff --git a/cmodule.h b/cmodule.h
new file mode 100644
index 0000000..6955c49
--- /dev/null
+++ b/cmodule.h
@@ -0,0 +1,84 @@
+//
+// C++ Interface: cmodule
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CMODULE_H
+#define CMODULE_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/bind.hpp>
+#include <hash_map.h>
+#include "common.h"
+
+using namespace boost;
+using namespace std;
+
+typedef shared_ptr<class Cmodule> CmodulePtr;
+
+#include "cmsg.h"
+#include "csession.h"
+
+
+//MODULE STUFF
+#define SYNAPSE_API_VERSION 2
+
+//defition of the default handler functions that modules have:
+//TODO: can we optimize this be preventing the copy of msg? by using something const Cmsg & msg perhaps? we tried this but then msg["bla"] gave a compiler error.
+#define SYNAPSE_HANDLER(s) extern "C" void synapse_##s( Cmsg msg, int dst )
+
+typedef void (*FsoHandler) ( Cmsg msg , int dst );
+typedef int (*FsoVersion)();
+typedef bool (*FsoInit)(class CmessageMan * initMessageMan, CmodulePtr initModule);
+typedef void (*FsoCleanup)();
+
+
+//TODO: we COULD do this with a hash map, but stl doesnt has a stable good one and boost only has Unordered from 1.36 or higher. but its fast enough for now. (tested with 10000)
+typedef map<string, FsoHandler> ChandlerHashMap;
+
+
+
+/**
+ @author
+*/
+class Cmodule{
+public:
+ Cmodule();
+
+ ~Cmodule();
+ void endThread();
+ bool startThread();
+ bool load(string name);
+ bool unload();
+ int maxThreads;
+ int currentThreads;
+ bool broadcastMulti;
+ int defaultSessionId;
+ string name;
+ string path;
+ bool ready;
+
+ //event handling stuff,
+ //converting an event string into an actual function call.
+ FsoHandler soDefaultHandler;
+ bool setHandler(const string & eventName, const string & functionName);
+ FsoHandler getHandler(string eventName);
+ void * resolve(const string & functionName);
+ bool isLoaded(string path);
+ string getName(string path);
+ FsoInit soInit;
+ void *soHandle;
+ ChandlerHashMap handlers;
+
+
+};
+
+
+
+#endif
diff --git a/cmsg.cpp b/cmsg.cpp
new file mode 100644
index 0000000..3e840a2
--- /dev/null
+++ b/cmsg.cpp
@@ -0,0 +1,30 @@
+//
+// C++ Implementation: cmsg
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "cmsg.h"
+#include "clog.h"
+#include <stdarg.h>
+
+
+
+
+Cmsg::Cmsg()
+{
+ dst=0;
+ src=0;
+}
+
+
+Cmsg::~Cmsg()
+{
+}
+
+
diff --git a/cmsg.h b/cmsg.h
new file mode 100644
index 0000000..7d8cc38
--- /dev/null
+++ b/cmsg.h
@@ -0,0 +1,78 @@
+//
+// C++ Interface: cmsg
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CMSG_H
+#define CMSG_H
+#include <string>
+#include <map>
+#include <boost/any.hpp>
+#include <boost/variant.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "cvar.h"
+//#include "cmessageman.h"
+
+using namespace std;
+using namespace boost;
+
+typedef variant<int,float,string> anyType;
+
+//extern CMessageMan * messageManPtr;
+//extern weak_ptr<Cmodule> modulePtr;
+
+/*
+typical route of a cmsg object
+
+1. Sendmessage is called with a shared_ptr to a Cmsg object:
+ [Cmsg object] -smart_ptr-> Sendmessage()
+
+2. This creates one or more Ccalls that point to it:
+ [Ccall objects] -shared_ptr-> [Cmsg object]
+
+3. A operator() thread fetches a Iterator to a call object:
+ operator() -iterator-> [Ccall object] --shared_ptr-> [Cmsg object]
+
+4. The operator calls the apropriate handler with a reference to the message object:
+ [Cmsg object] -reference-> soHander()
+
+5. The Ccall objects are deleted after the operators() are done:
+ *poof* shared_ptr automaticly deletes [Cmsg object] after everyone is one.
+ INCLUDING the original sender of the message.
+
+
+
+*/
+
+
+/**
+ @author
+*/
+class Cmsg : public Cvar {
+public:
+ Cmsg();
+ ~Cmsg();
+ int src;
+ int dst;
+ string event;
+
+ //this function is only implemented in .so object module
+ //so if you use it in the core you will get linker errors :)
+ bool send();
+ void returnError(string description);
+ void returnWarning(string description);
+ bool returnIfOtherThan(char * keys, ...);
+
+};
+
+typedef shared_ptr<Cmsg> CmsgPtr;
+
+
+#endif
diff --git a/cnet.cpp b/cnet.cpp
new file mode 100644
index 0000000..5ea8a43
--- /dev/null
+++ b/cnet.cpp
@@ -0,0 +1,279 @@
+//
+// C++ Implementation: cnet
+//
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "cnet.h"
+#include "clog.h"
+
+//client mode: construct the net-object and start resolving immeadiatly
+Cnet::Cnet(CnetMan & netManRef, int id, string host, int port, int reconnectTime)
+ :netMan(netManRef), tcpSocket(ioService), tcpResolver(ioService), readBuffer(65535), connectTimer(ioService)
+{
+ this->id=id;
+ this->host=host;
+ this->port=port;
+ this->reconnectTime=reconnectTime;
+
+ doConnect();
+}
+
+//Used in client mode to actually do the connect-stuff
+void Cnet::doConnect()
+{
+ //in case of a reconnect we need some extra cleaning
+ tcpResolver.cancel();
+ tcpSocket.close();
+
+ stringstream portStr;
+ portStr << port;
+ ioService.post(bind(&CnetMan::connecting,&netMan,id,host,port));
+
+ //start the resolver
+ DEB("Starting resolver for id " << id << ", resolving: " << host<<":"<<port);
+ tcp::resolver::query connectQuery(host, portStr.str());
+ tcpResolver.async_resolve(connectQuery,
+ bind(&Cnet::resolveHandler,this, _1 ,_2)
+ );
+
+ //start the timerout timer
+ connectTimer.expires_from_now(boost::posix_time::seconds(CONNECT_TIMEOUT));
+ connectTimer.async_wait(boost::bind(&Cnet::connectTimerHandler, this,_1));
+
+}
+
+//a connect timeout happend
+void Cnet::connectTimerHandler(
+ const boost::system::error_code& ec
+)
+{
+ if (!ec)
+ {
+ //A connect-timeout happend, so cancel all operations.
+ //the other handlers will reconnect if neccesary
+ tcpResolver.cancel();
+ tcpSocket.close();
+ }
+}
+
+//Called on disconnect: Checks if we need to reconnect.
+void Cnet::doReconnect()
+{
+ if (reconnectTime)
+ {
+ DEB("Will reconnect id " << id << ", after " << reconnectTime << " seconds...");
+ sleep(reconnectTime);
+ doConnect();
+ }
+}
+
+//server mode: construct the net-object from a new connection that comes from the acceptor.
+Cnet::Cnet(CnetMan & netManRef, int id, CacceptorPtr acceptorPtr)
+ :netMan(netManRef), tcpSocket(ioService), tcpResolver(ioService), readBuffer(65535), connectTimer(ioService)
+{
+ this->id=id;
+
+ //inform the world we're trying to accept a new connection
+ ioService.post(bind(
+ &CnetMan::accepting,
+ &netMan,
+ acceptorPtr->local_endpoint().port(),
+ id)
+ );
+
+ reconnectTime=0;
+ DEB("Starting acceptor for port " << acceptorPtr->local_endpoint().port()<< " into id " << id);
+ //start the accept
+
+ asio::io_service::work work(ioService);
+ acceptorPtr->async_accept(
+ tcpSocket,
+ bind(&Cnet::acceptHandler,this,asio::io_service::work(ioService),_1)
+ );
+
+}
+
+void Cnet::acceptHandler(
+ asio::io_service::work work,
+ const boost::system::error_code& ec
+)
+{
+ if (ec)
+ {
+ DEB("Accepting for id " << id << " failed: " <<ec.message());
+ disconnected(ec);
+ return;
+ }
+
+ //when an acception has succeeded, we also use the connected-callback.
+ //this ways its easy to change existing code between server and client mode.
+ netMan.connected(id);
+
+ //start reading the incoming data
+ asio::async_read_until(tcpSocket,
+ readBuffer,
+ "\n",
+ bind(&Cnet::readHandler, this, _1, _2)
+ );
+
+}
+
+Cnet::~Cnet ()
+{
+ DEB("net object " << id << " destroyed");
+}
+
+
+
+//handle the results of the resolver and start connecting to the first endpoint:
+void Cnet::resolveHandler(
+ const boost::system::error_code& ec,
+ asio::ip::tcp::resolver::iterator endpointI)
+{
+ if (ec)
+ {
+ DEB("Resolver for id " << id << " failed: " <<ec.message());
+ disconnected(ec);
+ return;
+ }
+
+ //start connecting to first endpoint:
+ tcp::endpoint endpoint = *endpointI;
+ DEB("Resolved id " << id << ", starting connect to " << endpoint.address() << ":" << endpoint.port());
+ tcpSocket.async_connect(endpoint,
+ bind(&Cnet::connectHandler, this, ++endpointI, _1)
+ );
+}
+
+//handle the results of the connect:
+//-try connecting to the next endpoints in case of failure
+//-start waiting for data in case of succes
+void Cnet::connectHandler(
+ asio::ip::tcp::resolver::iterator endpointI,
+ const boost::system::error_code& ec
+ )
+{
+ if (ec)
+ {
+ //we still have other endpoints we can try to connect?
+ if (endpointI != tcp::resolver::iterator())
+ {
+ tcpSocket.close();
+ tcp::endpoint endpoint = *endpointI;
+ DEB("Connection for id " << id << " failed, trying next endpoint: " << endpoint.address());
+ tcpSocket.async_connect(endpoint,
+ bind(&Cnet::connectHandler, this, ++endpointI, _1)
+ );
+ }
+ //failure
+ else
+ {
+ disconnected(ec);
+ }
+ return;
+ }
+
+ //connection succeeded
+ connectTimer.cancel();
+ netMan.connected(id);
+
+ //start reading the incoming data
+ asio::async_read_until(tcpSocket,
+ readBuffer,
+ "\n",
+ bind(&Cnet::readHandler, this, _1, _2)
+ );
+
+
+}
+
+//handle the results of a read (incoming data)
+void Cnet::readHandler(
+ const boost::system::error_code& ec,
+ std::size_t bytesTransferred)
+{
+ if (ec)
+ {
+ disconnected(ec);
+ return;
+ }
+
+ netMan.read(id, readBuffer, bytesTransferred);
+ readBuffer.consume(bytesTransferred);
+
+ //start reading the next incoming data
+ asio::async_read_until(tcpSocket,
+ readBuffer,
+ "\n",
+ bind(&Cnet::readHandler, this, _1, _2)
+ );
+
+}
+
+void Cnet::doDisconnectHandler()
+{
+ DEB("Initiating permanent disconnect for id " << id);
+ reconnectTime=0;
+ tcpResolver.cancel();
+ tcpSocket.close();
+}
+
+void Cnet::writeHandler(
+ shared_ptr<string> stringPtr,
+ const boost::system::error_code& ec,
+ std::size_t bytesTransferred)
+{
+ if (ec)
+ {
+ disconnected(ec);
+ return;
+ }
+
+ //no use to call this yet?
+ //netMan.wrote(id, stringPtr);
+
+}
+
+
+void Cnet::doDisconnect()
+{
+ ioService.post(bind(&Cnet::doDisconnectHandler,this));
+}
+
+void Cnet::doWrite(string & data)
+{
+ //copy string into a buffer and pass it to the ioService
+ shared_ptr<string> stringPtr(new string(data));
+ asio::async_write(
+ tcpSocket,
+ asio::buffer(*stringPtr),
+ bind(&Cnet::writeHandler, this, stringPtr, _1, _2)
+ );
+
+}
+
+void Cnet::run()
+{
+ ioService.run();
+}
+
+void Cnet::disconnected(const boost::system::error_code& ec)
+{
+ //we probably got disconnected or had some kind of error,
+ //just cancel and close everything to be sure.
+ connectTimer.cancel();
+ tcpResolver.cancel();
+ tcpSocket.close();
+
+ //callback to netmanager
+ netMan.disconnected(id, ec);
+
+ //check if we need to reconnect
+ doReconnect();
+}
+
diff --git a/cnet.h b/cnet.h
new file mode 100644
index 0000000..2360b0d
--- /dev/null
+++ b/cnet.h
@@ -0,0 +1,103 @@
+//
+// C++ Interface: cnet
+//
+// Description: the Cnet class that handles a networking session. Its used to implement both servers and clients.
+// Threadsafe because we only post stuff with io_serivce::post()
+// The CnetMan class is responsible for handling the creation of these Cnet-objects.
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CNET_H
+#define CNET_H
+
+#include <boost/bind.hpp>
+#include <boost/asio.hpp>
+#include <string>
+#include <boost/shared_ptr.hpp>
+/*
+
+
+
+
+
+*/
+
+using namespace std;
+using namespace boost;
+using asio::ip::tcp;
+
+#define CONNECT_TIMEOUT 60
+
+typedef shared_ptr<class Cnet> CnetPtr;
+typedef shared_ptr<tcp::acceptor> CacceptorPtr;
+#include "cnetman.h"
+
+class CnetMan;
+
+class Cnet
+{
+ public:
+
+ Cnet(CnetMan & netManRef, int id, string host, int port, int reconnectTime=0);
+ Cnet(CnetMan & netManRef, int id, CacceptorPtr acceptorPtr);
+ virtual ~Cnet();
+
+ void doDisconnect();
+ void doConnect();
+ void doReconnect();
+ void doWrite(string & data);
+ void run();
+
+ private:
+ int id;
+ CnetMan &netMan;
+ asio::io_service ioService;
+ int reconnectTime;
+
+ tcp::socket tcpSocket;
+ tcp::resolver tcpResolver;
+ asio::streambuf readBuffer;
+ asio::deadline_timer connectTimer;
+ string host;
+ int port;
+
+ void acceptHandler(
+ asio::io_service::work work,
+ const boost::system::error_code& ec
+ );
+
+ void resolveHandler(
+ const boost::system::error_code& ec,
+ asio::ip::tcp::resolver::iterator endpointI);
+
+ void connectHandler(
+ asio::ip::tcp::resolver::iterator endpointI,
+ const boost::system::error_code& ec
+ );
+
+ void readHandler(
+ const boost::system::error_code& ec,
+ std::size_t bytesTransferred);
+
+ void writeHandler(
+ shared_ptr<string> stringPtr,
+ const boost::system::error_code& ec,
+ std::size_t bytesTransferred);
+
+ void connectTimerHandler(
+ const boost::system::error_code& ec
+ );
+
+ void doDisconnectHandler();
+
+ void disconnected(const boost::system::error_code& ec);
+
+};
+
+
+
+#endif
diff --git a/cnetman.cpp b/cnetman.cpp
new file mode 100644
index 0000000..a135ed8
--- /dev/null
+++ b/cnetman.cpp
@@ -0,0 +1,228 @@
+//
+// C++ Implementation: cnet
+//
+
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "cnetman.h"
+#include "clog.h"
+
+CnetMan::CnetMan()
+{
+
+}
+
+CnetMan::~CnetMan()
+{
+
+}
+
+bool CnetMan::runConnect(int id, string host, int port, int reconnectTime)
+{
+ CnetPtr netPtr;
+ {
+ lock_guard<mutex> lock(threadMutex);
+ if (nets.find(id)!=nets.end())
+ {
+ ERROR("id " << id << " is already busy, ignoring connect-request");
+ return false;
+ }
+
+ //add a new object to the list
+ netPtr=(CnetPtr(new Cnet(*this,id,host,port,reconnectTime)));
+ nets[id]=netPtr;
+ }
+
+ //let the ioservice run, until the connection is closed again:
+ netPtr->run();
+ DEB("ioservice finished for id " << id);
+
+ {
+ lock_guard<mutex> lock(threadMutex);
+ //we're done, remove the Cnetobject from the list
+ nets.erase(id);
+ }
+
+ return true;
+}
+
+bool CnetMan::runListen(int port)
+{
+ asio::io_service ioService;
+ {
+ lock_guard<mutex> lock(threadMutex);
+ if (acceptors.find(port)!=acceptors.end())
+ {
+ ERROR("port " << port << " is already listening, ignoring listen-request");
+ return false;
+ }
+
+ //listen on the port and add to the list
+ acceptors[port]=CacceptorPtr(new tcp::acceptor(ioService,tcp::endpoint(tcp::v4(), port)));
+
+ //inform the world we're listening
+ acceptors[port]->get_io_service().post(bind(&CnetMan::listening,this,port));
+ INFO("Listening on tcp port " << port);
+ }
+ //at this point the ioservice has no work yet, so make sure it keeps running:
+ asio::io_service::work work(ioService);
+
+ //let the ioservice run, until the acceptor is closed
+ ioService.run();
+ DEB("ioservice finished for port " << port);
+
+ {
+ lock_guard<mutex> lock(threadMutex);
+ //we're done, remove the acceptor from the list
+ acceptors.erase(port);
+ }
+ closed(port);
+
+ return true;
+}
+
+bool CnetMan::runAccept(int port, int id)
+{
+ CnetPtr netPtr;
+ {
+ lock_guard<mutex> lock(threadMutex);
+ if (acceptors.find(port)==acceptors.end())
+ {
+ ERROR("port " << port << " is not listening, ignoring accept-request");
+ return false;
+ }
+
+ if (nets.find(id)!=nets.end())
+ {
+ ERROR("id " << id << " is already busy, ignoring accept-request on port " << port);
+ return false;
+ }
+ //create a new net-object that will async_accept the next connection from acceptors[port]
+ netPtr=(CnetPtr(new Cnet(*this,id,acceptors[port])));
+ nets[id]=netPtr;
+
+ }
+
+ //let the ioservice run, until the connection is closed again:
+ netPtr->run();
+ DEB("ioservice finished for port " << port << " into " << id);
+
+ {
+ lock_guard<mutex> lock(threadMutex);
+ //we're done, remove the Cnetobject from the list
+ nets.erase(id);
+ }
+
+ return true;
+}
+
+bool CnetMan::doClose(int port)
+{
+ {
+ lock_guard<mutex> lock(threadMutex);
+ if (acceptors.find(port)==acceptors.end())
+ {
+ ERROR("port " << port << " is not listening, ignoring close-request");
+ return false;
+ }
+
+ //post via ioservice because acceptor is not threadsafe
+ DEB("Posting close request for port " << port);
+ acceptors[port]->get_io_service().post(bind(&CnetMan::closeHandler,this,port));
+ }
+ return true;
+}
+
+//called from the doListen->ioService->run() thread:
+void CnetMan::closeHandler(int port)
+{
+ acceptors[port]->close();
+ acceptors[port]->get_io_service().stop();
+ //after cancelling all pending accepts, doListen will now return
+}
+
+bool CnetMan::doDisconnect(int id)
+{
+ {
+ lock_guard<mutex> lock(threadMutex);
+ if (nets.find(id)==nets.end())
+ {
+ ERROR("id " << id << " does not exist, ignoring disconnect request");
+ return false;
+ }
+ nets[id]->doDisconnect();
+ }
+ return true;
+}
+
+bool CnetMan::doWrite(int id, string & data)
+{
+ {
+ lock_guard<mutex> lock(threadMutex);
+ if (nets.find(id)==nets.end())
+ {
+ ERROR("id " << id << " does not exist, ignoring write request");
+ return false;
+ }
+ nets[id]->doWrite(data);
+ }
+ return true;
+}
+
+
+
+void CnetMan::listening(int port)
+{
+ //dummy
+ DEB("Listening on port " << port);
+}
+
+void CnetMan::accepting(int port, int id)
+{
+ //dummy
+ DEB("Accepting connection on " << port << " into id " << id);
+}
+
+// void CnetMan::accepted(int port, int id, string ip)
+// {
+// //dummy
+// DEB("Accepted new connection on port " << port << " to id " << id << ". ip adress = " << ip);
+// }
+
+void CnetMan::closed(int port)
+{
+ //dummy
+ DEB("Stopped listening on port " << port);
+}
+
+void CnetMan::connecting(int id, string host, int port)
+{
+ //dummy
+ DEB("Connecting " << id << " to " << host << ":" << port);
+}
+
+void CnetMan::connected(int id)
+{
+ //dummy
+ DEB("Connected " << id);
+}
+
+void CnetMan::disconnected(int id, const boost::system::error_code& error)
+{
+ //dummy
+ DEB("Disconnected " << id << ":" << error.message());
+}
+
+
+
+void CnetMan::read(int id, asio::streambuf &readBuffer, std::size_t bytesTransferred)
+{
+ //dummy
+ DEB("Read data " << id << ":" << &readBuffer);
+}
+
diff --git a/cnetman.h b/cnetman.h
new file mode 100644
index 0000000..8f74944
--- /dev/null
+++ b/cnetman.h
@@ -0,0 +1,74 @@
+//
+// C++ Interface: cnet
+//
+// Description: Generic thread-safe networking class for synapse modules.
+// Creates and handles Cnet-sessions.
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CNETMAN_H
+#define CNETMAN_H
+
+#include <boost/bind.hpp>
+#include <boost/asio.hpp>
+#include <boost/thread/thread.hpp>
+#include <string>
+
+using namespace std;
+using namespace boost;
+using asio::ip::tcp;
+
+typedef shared_ptr<tcp::acceptor> CacceptorPtr;
+#include "cnet.h"
+
+class CnetMan
+{
+ friend class Cnet;
+
+ public:
+ CnetMan ();
+ virtual ~CnetMan();
+
+ //for server: call runListen to listen on a port.
+ //It returns when doClose is called.
+ //Add ids that will accept the new connections with runAccept. (runAccept returns when connection is closed)
+ bool runListen(int port);
+ bool doClose(int port);
+ bool runAccept(int port, int id);
+
+ //for client: call runConnect(returns when connection is closed)
+ bool runConnect(int id, string host, int port, int reconnectTime=0);
+
+ //for both client and server:
+ bool doDisconnect(int id);
+ bool doWrite(int id, string & data);
+
+ private:
+ map<int, CnetPtr> nets;
+ map<int, CacceptorPtr> acceptors;
+ mutex threadMutex;
+
+ void closeHandler(int port);
+
+ //callbacks for server
+ virtual void listening(int port);
+ virtual void accepting(int port, int id);
+ virtual void closed(int port);
+
+ //callbacks for client
+ virtual void connecting(int id, string host, int port);
+
+ //callbacks for client and server
+ virtual void connected(int id);
+ virtual void disconnected(int id, const boost::system::error_code& error);
+ virtual void read(int id, asio::streambuf &readBuffer, std::size_t bytesTransferred);
+
+
+};
+
+
+#endif
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..8f5c8a0
--- /dev/null
+++ b/common.h
@@ -0,0 +1,17 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <string>
+
+using namespace std;
+
+struct eqstr
+{
+ bool operator()(string s1, string s2) const
+ {
+ return s1==s2;
+ }
+};
+
+
+#endif
diff --git a/csession.cpp b/csession.cpp
new file mode 100644
index 0000000..5a8de20
--- /dev/null
+++ b/csession.cpp
@@ -0,0 +1,71 @@
+//
+// C++ Implementation: csession
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "csession.h"
+#include "cuser.h"
+#include "cmodule.h"
+#include <iostream>
+
+Csession::Csession(const CuserPtr &user, const CmodulePtr &module)
+{
+ this->user=user;
+ this->module=module;
+ id=SESSION_DISABLED;
+ maxThreads=1;
+ currentThreads=0;
+
+}
+
+
+Csession::~Csession()
+{
+}
+
+
+
+
+
+
+/*!
+ \fn Csession::isEnabled()
+ */
+bool Csession::isEnabled()
+{
+ return (id!=SESSION_DISABLED);
+}
+
+
+/*!
+ \fn Csession::startThread()
+ */
+bool Csession::startThread()
+{
+ if (currentThreads<maxThreads)
+ {
+ if (module->startThread())
+ {
+ currentThreads++;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/*!
+ \fn Csession::endThread()
+ */
+void Csession::endThread()
+{
+ module->endThread();
+ currentThreads--;
+ assert(currentThreads>=0);
+}
diff --git a/csession.h b/csession.h
new file mode 100644
index 0000000..1e82ad8
--- /dev/null
+++ b/csession.h
@@ -0,0 +1,50 @@
+//
+// C++ Interface: csession
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CSESSION_H
+#define CSESSION_H
+
+#include <boost/shared_ptr.hpp>
+using namespace boost;
+using namespace std;
+
+typedef shared_ptr<class Csession> CsessionPtr;
+
+#include "cmodule.h"
+#include "cuser.h"
+
+
+#define SESSION_DISABLED -1
+
+/**
+ @author
+*/
+class Csession{
+public:
+ Csession(const CuserPtr &user, const CmodulePtr &module);
+
+ ~Csession();
+ bool isEnabled();
+ void endThread();
+ bool startThread();
+ CuserPtr user;
+ CmodulePtr module;
+ int id;
+ int maxThreads;
+ int currentThreads;
+
+
+private:
+
+};
+
+
+#endif
diff --git a/cuser.cpp b/cuser.cpp
new file mode 100644
index 0000000..5c28c73
--- /dev/null
+++ b/cuser.cpp
@@ -0,0 +1,96 @@
+//
+// C++ Implementation: cuser
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "cuser.h"
+#include "clog.h"
+
+Cuser::Cuser(const string &name, const string &password="")
+{
+ this->name=name;
+ this->password=password;
+}
+
+
+Cuser::~Cuser()
+{
+}
+
+
+
+
+/*!
+ \fn Cuser::addMemberGroup(CgroupPtr group)
+ */
+bool Cuser::addMemberGroup(const CgroupPtr & group)
+{
+ if (group)
+ {
+ memberGroups.push_back(group);
+ return true;
+ }
+ return false;
+}
+
+
+/*!
+ \fn Cuser::isMemberGroup(CgroupPtr group)
+ */
+bool Cuser::isMemberGroup(const CgroupPtr & group)
+{
+ if (!group)
+ return false;
+
+ list<CgroupPtr>::iterator groupI;
+ for (groupI=memberGroups.begin(); groupI!=memberGroups.end(); groupI++)
+ {
+ if ((*groupI)==(group))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/*!
+ \fn Cuser::getName()
+ */
+string Cuser::getName()
+{
+ return (name);
+}
+
+
+/*!
+ \fn Cuser::isPassword(string password)
+ */
+bool Cuser::isPassword(const string & password)
+{
+ if (password!="" && this->password!="")
+ return (this->password==password);
+ else
+ return false;
+}
+
+
+/*!
+ \fn Cuser::print()
+ */
+void Cuser::print()
+{
+ list<CgroupPtr>::iterator groupI;
+ DEB(name << " with password '" << password << "' is member of:");
+ for (groupI=memberGroups.begin(); groupI!=memberGroups.end(); groupI++)
+ {
+ DEB( (*groupI)->getName());
+ }
+
+}
diff --git a/cuser.h b/cuser.h
new file mode 100644
index 0000000..1c523ab
--- /dev/null
+++ b/cuser.h
@@ -0,0 +1,46 @@
+//
+// C++ Interface: cuser
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CUSER_H
+#define CUSER_H
+#include "cgroup.h"
+#include <string>
+#include <list>
+#include <boost/shared_ptr.hpp>
+using namespace boost;
+using namespace std;
+
+
+/**
+ @author
+*/
+class Cuser{
+public:
+ Cuser(const string &name, const string &password);
+
+ ~Cuser();
+ bool addMemberGroup(const CgroupPtr & group);
+ bool isMemberGroup(const CgroupPtr & group);
+ string getName();
+ bool isPassword(const string & password);
+ void print();
+
+private:
+ string name;
+ string password;
+ list<CgroupPtr > memberGroups;
+
+};
+
+typedef shared_ptr<Cuser> CuserPtr;
+
+
+#endif
diff --git a/cuserman.cpp b/cuserman.cpp
new file mode 100644
index 0000000..c38eb97
--- /dev/null
+++ b/cuserman.cpp
@@ -0,0 +1,243 @@
+//
+// C++ Implementation: cuserman
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "cuserman.h"
+#include <boost/shared_ptr.hpp>
+#include <iostream>
+
+#include "cmodule.h"
+#include "clog.h"
+
+
+using namespace std;
+CuserMan::CuserMan()
+{
+ sessionCounter=0;
+ sessionMaxPerUser=1000;
+
+ addGroup(CgroupPtr(new Cgroup("core")));
+ addGroup(CgroupPtr(new Cgroup("modules")));
+ addGroup(CgroupPtr(new Cgroup("users")));
+ addGroup(CgroupPtr(new Cgroup("everyone")));
+
+ CuserPtr user;
+ user=CuserPtr(new Cuser("core",""));
+ user->addMemberGroup(getGroup("core"));
+ user->addMemberGroup(getGroup("modules"));
+ user->addMemberGroup(getGroup("everyone"));
+ addUser(user);
+
+ user=CuserPtr(new Cuser("module",""));
+ user->addMemberGroup(getGroup("modules"));
+ user->addMemberGroup(getGroup("everyone"));
+ addUser(user);
+
+ //anonymous isnt member of anything
+ user=CuserPtr(new Cuser("anonymous",""));
+ addUser(user);
+
+ //testusers
+ user=CuserPtr(new Cuser("psy","as"));
+ user->addMemberGroup(getGroup("users"));
+ user->addMemberGroup(getGroup("everyone"));
+ addUser(user);
+
+ user=CuserPtr(new Cuser("admin","bs"));
+ user->addMemberGroup(getGroup("users"));
+ user->addMemberGroup(getGroup("core"));
+ user->addMemberGroup(getGroup("modules"));
+ user->addMemberGroup(getGroup("everyone"));
+ addUser(user);
+
+// for (int i=0; i<MAX_SESSIONS; i++)
+// sessions[i]=CsessionPtr();
+
+}
+
+
+CuserMan::~CuserMan()
+{
+}
+
+
+
+
+/*!
+ \fn CuserMan::getUser(string username)
+ */
+CuserPtr CuserMan::getUser(const string & userName)
+{
+ list<CuserPtr>::iterator userI;
+ for (userI=users.begin(); userI!=users.end(); userI++)
+ {
+ if ((**userI).getName()==userName)
+ {
+ return(*userI);
+ }
+ }
+ ERROR("User " << userName << " not found!");
+ return (CuserPtr());
+}
+
+
+
+
+
+/*!
+ \fn CuserMan::addUser(CuserPtr user)
+ */
+bool CuserMan::addUser(const CuserPtr & user)
+{
+ if (user)
+ {
+ users.push_back(user);
+ return true;
+ }
+ return false;
+}
+
+
+/*!
+ \fn CuserMan::addGroup(CgroupPtr group)
+ */
+bool CuserMan::addGroup(const CgroupPtr &group)
+{
+ if (group)
+ {
+ groups.push_back(group);
+ return true;
+ }
+ return false;
+}
+
+
+/*!
+ \fn CuserMan::getGroup(string groupName)
+ */
+CgroupPtr CuserMan::getGroup(const string &groupName)
+{
+ list<CgroupPtr>::iterator groupI;
+ for (groupI=groups.begin(); groupI!=groups.end(); groupI++)
+ {
+ if ((**groupI).getName()==groupName)
+ {
+ return(*groupI);
+ }
+ }
+ return (CgroupPtr());
+}
+
+
+/*!
+ \fn CuserMan::addSession(CsessionPtr session)
+ */
+int CuserMan::addSession( CsessionPtr session)
+{
+ //too much for this user already?
+ int userSessions=0;
+ for (int sessionId=0; sessionId<MAX_SESSIONS; sessionId++)
+ {
+ CsessionPtr chkSession;
+ chkSession=getSession(sessionId);
+ if (chkSession && chkSession->user==session->user)
+ {
+ userSessions++;
+ if (userSessions>=sessionMaxPerUser)
+ {
+ ERROR("User " << session->user->getName() << " has reached max sessions of " << sessionMaxPerUser);
+ return (SESSION_DISABLED);
+ }
+ }
+ }
+
+ //find free session ID. Start at the counter position, to prevent that we use the same numbers
+ //all the time. (which will be confusing)
+ int startId=sessionCounter;
+ do
+ {
+ sessionCounter++;
+ if (sessionCounter>=MAX_SESSIONS)
+ sessionCounter=1;
+
+ if (!sessions[sessionCounter])
+ {
+ //its free, store it here and return the ID.
+ sessions[sessionCounter]=session;
+ session->id=sessionCounter;
+ DEB("added session " << sessionCounter << " with user " << session->user->getName());
+ return (sessionCounter);
+ }
+ }
+ while(startId!=sessionCounter);
+ ERROR("Out of sessions, max=" << MAX_SESSIONS);
+ return (SESSION_DISABLED);
+}
+
+
+/*!
+ \fn CuserMan::getSession(int sessionId)
+ */
+CsessionPtr CuserMan::getSession(const int &sessionId)
+{
+ if (sessionId>=0 && sessionId<MAX_SESSIONS && sessions[sessionId] )
+ {
+ if (sessions[sessionId]->isEnabled())
+ {
+ return (sessions[sessionId]);
+ }
+ }
+ return (CsessionPtr());
+}
+
+
+/*!
+ \fn CuserMan::delSession(int id)
+ */
+bool CuserMan::delSession(const int sessionId)
+{
+ if (sessionId>=0 && sessionId<MAX_SESSIONS && sessions[sessionId] )
+ {
+ //this is the default session of some module?
+ if (sessions[sessionId]->module->defaultSessionId==sessionId)
+ {
+ //remove this session as default session from this module
+ sessions[sessionId]->module->defaultSessionId=SESSION_DISABLED;
+
+ }
+ //reset shared ptr.
+ //as soon as nobody uses the session object anymore it will be destroyed.
+//NIET: sessions[sessionId]->id=SESSION_DISABLED;
+ sessions[sessionId].reset();
+ return (true);
+ }
+ else
+ {
+ return (false);
+ }
+}
+
+
+
+
+/*!
+ \fn CuserMan::print()
+ */
+void CuserMan::print()
+{
+ for (int sessionId=0; sessionId<MAX_SESSIONS; sessionId++)
+ {
+ if (sessions[sessionId])
+ {
+ DEB("session " << sessionId << " = " << sessions[sessionId]->user->getName() << "@" << sessions[sessionId]->module->name );
+ }
+ }
+
+}
diff --git a/cuserman.h b/cuserman.h
new file mode 100644
index 0000000..d2410f0
--- /dev/null
+++ b/cuserman.h
@@ -0,0 +1,53 @@
+//
+// C++ Interface: cuserman
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CUSERMAN_H
+#define CUSERMAN_H
+
+#include "cuser.h"
+#include "cgroup.h"
+#include "csession.h"
+
+#include <boost/shared_ptr.hpp>
+#include <list>
+using namespace std;
+using namespace boost;
+
+#define MAX_SESSIONS 1000
+
+/**
+ @author
+*/
+class CuserMan{
+public:
+ CuserMan();
+
+ ~CuserMan();
+ CuserPtr getUser(const string & userName);
+ bool addUser(const CuserPtr & user);
+ CgroupPtr getGroup(const string & groupName);
+ bool addGroup(const CgroupPtr &group);
+ int addSession( CsessionPtr session);
+ CsessionPtr getSession(const int & sessionId);
+ bool delSession(const int id);
+ void print();
+
+private:
+ list<CuserPtr> users;
+ list<CgroupPtr> groups;
+ //performance: we use an oldskool array, so session lookups are quick
+ int sessionCounter;
+ CsessionPtr sessions[MAX_SESSIONS];
+ int sessionMaxPerUser;
+
+};
+
+#endif
diff --git a/cvar.cpp b/cvar.cpp
new file mode 100644
index 0000000..6eb8a3d
--- /dev/null
+++ b/cvar.cpp
@@ -0,0 +1,140 @@
+//
+// C++ Implementation: cvar
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "cvar.h"
+#include <iostream>
+#include <boost/lexical_cast.hpp>
+#include "clog.h"
+
+Cvar::Cvar()
+{
+}
+
+
+Cvar::~Cvar()
+{
+}
+
+
+
+
+/*!
+ \fn Cvar::operator=
+ */
+void Cvar::operator=(const string & value)
+{
+ this->value=value;
+}
+
+// Cvar::operator string ()
+// {
+// try
+// {
+// if (value.which()==CVAR_LONG_DOUBLE)
+// return (lexical_cast<string>(get<long double>(value)));
+// else if (value.which()==CVAR_STRING)
+// return (get<string>(value));
+// else
+// return (string(""));
+// }
+// catch(exception e)
+// {
+// return ("");
+// }
+// }
+
+Cvar::operator string & ()
+{
+ try
+ {
+ if (value.which()==CVAR_LONG_DOUBLE)
+ {
+ //convert value to a permanent string
+ value=lexical_cast<string>(get<long double>(value));
+ }
+ }
+ catch(exception e)
+ {
+ value="";
+ }
+ return (get<string&>(value));
+}
+
+string & Cvar::str()
+{
+ return((string &)*this);
+}
+
+void Cvar::operator=(const long double & value)
+{
+ this->value=value;
+}
+
+Cvar::operator long double()
+{
+ try
+ {
+ if (value.which()==CVAR_LONG_DOUBLE)
+ return (get<long double>(value));
+ else if (value.which()==CVAR_STRING)
+ return (lexical_cast<long double>(get<string>(value)));
+ else
+ return 0;
+ }
+ catch(exception e)
+ {
+ return 0;
+ }
+}
+
+
+
+
+
+
+int Cvar::which()
+{
+ return (value.which());
+}
+
+
+/*!
+ \fn Cvar::print(string s)
+ */
+string Cvar::getPrint(string prefix)
+{
+ stringstream print;
+ for (Cvar::iterator varI=begin(); varI!=end(); varI++)
+ {
+ //asume that a user doesnt apply a value in case of another dimention:
+ if (!varI->second.empty())
+ {
+ print << endl << prefix << varI->first << " :";
+ print << varI->second.getPrint(prefix+" |");
+ }
+ else if (varI->second.which()==CVAR_LONG_DOUBLE)
+ print << endl << prefix << varI->first << " = " << (long double)varI->second;
+ else if (varI->second.which()==CVAR_STRING)
+ print << endl << prefix << varI->first << " = " << (string)varI->second;
+ else
+ print << endl << prefix << varI->first << " ? ";
+ }
+ return print.str();
+}
+
+
+/*!
+ \fn Cvar::isSet(string key)
+ */
+bool Cvar::isSet(string key)
+{
+ return (find(key)!=end());
+}
diff --git a/cvar.h b/cvar.h
new file mode 100644
index 0000000..03d68d6
--- /dev/null
+++ b/cvar.h
@@ -0,0 +1,52 @@
+//
+// C++ Interface: cvar
+//
+// Description:
+//
+//
+// Author: <>, (C) 2009
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CVAR_H
+#define CVAR_H
+
+#include "clog.h"
+#include <string>
+#include "boost/variant.hpp"
+#include <map>
+using namespace std;
+using namespace boost;
+
+/**
+ @author
+*/
+
+//this has to corospond with the variant order in the Cvar class below:
+#define CVAR_LONG_DOUBLE 0
+#define CVAR_STRING 1
+
+class Cvar : public map<const string,Cvar >{
+public:
+ Cvar();
+
+ ~Cvar();
+ void operator=(const string & value);
+// operator string ();
+ operator string &();
+ string & str();
+
+ void operator=(const long double & value);
+ operator long double ();
+ string getPrint(string prefix);
+ int which();
+ bool isSet(string key);
+
+
+private:
+
+ variant <long double,string> value;
+};
+
+#endif
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..17c2388
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,20 @@
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "cmessageman.h"
+
+int main(int argc, char *argv[])
+{
+ CmessageMan messageMan;
+ if (argc==2)
+ {
+ return (messageMan.run("modules/core.module/libcore.so",argv[1]));
+ }
+ else
+ {
+ printf("Usage: ./synapse <initialmodule.so>\n");
+ return (1);
+ }
+}
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
new file mode 100644
index 0000000..0a40fc8
--- /dev/null
+++ b/modules/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 2.6)
+
+PROJECT(modules)
+
+#if you don't want the full compiler output, remove the following line
+
+SET(CMAKE_VERBOSE_MAKEFILE ON)
+
+file(GLOB modules *.module)
+MESSAGE(STATUS "Detected synapse modules: ${modules}")
+SUBDIRS(${modules})
+
diff --git a/modules/core.module/CMakeLists.txt b/modules/core.module/CMakeLists.txt
new file mode 100644
index 0000000..58de7a5
--- /dev/null
+++ b/modules/core.module/CMakeLists.txt
@@ -0,0 +1,28 @@
+#this is just a basic CMakeLists.txt, for more information see the cmake manpage
+
+cmake_minimum_required(VERSION 2.6)
+
+#add definitions, compiler switches, etc.
+ADD_DEFINITIONS(-Wall -O2)
+
+#Determine name of the .so module:
+#A module should always be in a modulename.module directory!.
+string(REGEX REPLACE ".*/([^/]*).module$" "\\1" module_name "${CMAKE_CURRENT_BINARY_DIR}")
+MESSAGE(STATUS "Module name of ${CMAKE_CURRENT_BINARY_DIR} is: '${module_name}'")
+
+#automaticly add all sourcefiles to current module
+file(GLOB sources *.cpp)
+ADD_LIBRARY(${module_name} MODULE ${sources})
+
+#need to link to some other libraries ? just add them here
+#TARGET_LINK_LIBRARIES(test)
+
+INCLUDE_DIRECTORIES(../..)
+
+#add an install target here
+#INSTALL_FILES(...)
+#INSTALL_PROGRAMS(...)
+#INSTALL_TARGET(...)
+
+
+
diff --git a/modules/core.module/module.cpp b/modules/core.module/module.cpp
new file mode 100644
index 0000000..829ab38
--- /dev/null
+++ b/modules/core.module/module.cpp
@@ -0,0 +1,566 @@
+#define SYNAPSE_HAS_INIT
+#include "synapse.h"
+
+//Dont forget you can only do things to core-objects after locking the core!
+//Also dont forget you CANT send() while holding the core-lock. (it will deadlock)
+
+//this is THE core module - we need a bootstrap function:
+void init()
+{
+ //We have no core lock, but there are no threads yet, so its no problem.
+ //What this means is that we can do everything we want AND use the send() without causing a deadlock.
+
+ INFO("Synapse core v1.0 starting up...");
+
+ //call the normal module-init to do the rest:
+ Cmsg out;
+ out.event="module_Init";
+ out.send();
+
+}
+
+
+SYNAPSE_REGISTER(module_Init)
+{
+
+ DEB("Core init start");
+ Cmsg out;
+
+ if (dst!=1)
+ {
+ ERROR("This core-module should be started as the first and only one.");
+ return;
+ }
+
+ ///module_Error
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="module_Error";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="modules";
+ out["recvGroup"]="everyone";
+ out.send();
+
+
+ ///set permissions on these important core features
+ //The handlers where already registered by init()
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="core_ChangeEvent";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="modules";
+ out["recvGroup"]="core";
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="core_Register";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="modules";
+ out["recvGroup"]="core";
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="module_Init";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="core";
+ out["recvGroup"]="modules";
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="core_LoadModule";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="modules";
+ out["recvGroup"]="core";
+ out.send();
+
+
+ /// core_Login
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="module_SessionStart";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="core";
+ out["recvGroup"]="everyone";
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="module_SessionStarted";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="core";
+ out["recvGroup"]="everyone";
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="module_Login";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="core";
+ out["recvGroup"]="modules";
+ out.send();
+
+
+ /// core_NewSession
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="core_NewSession";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="modules";
+ out["recvGroup"]="core";
+ out.send();
+
+ /// core_Logout
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="core_Logout";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="everyone";
+ out["recvGroup"]="core";
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="module_SessionEnd";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="core";
+ out["recvGroup"]="everyone";
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="module_SessionEnded";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="core";
+ out["recvGroup"]="everyone";
+ out.send();
+
+ /// core_ChangeModule
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="core_ChangeModule";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="modules";
+ out["recvGroup"]="core";
+ out.send();
+
+ /// core_ChangeSession
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="core_ChangeSession";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="modules";
+ out["recvGroup"]="core";
+ out.send();
+
+ /// core_Ready
+ out.clear();
+ out.event="core_ChangeEvent";
+ out["event"]="core_Ready";
+ out["modifyGroup"]="core";
+ out["sendGroup"]="modules";
+ out["recvGroup"]="core";
+ out.send();
+
+
+
+ //we're done with our stuff,
+ //load the first application module:
+ out.clear();
+ out.event="core_LoadModule";
+ out["path"]=messageMan->firstModuleName;
+ out.send();
+
+
+ DEB("Core init complete");
+}
+
+
+SYNAPSE_REGISTER(module_Error)
+{
+ //ignore errors for now..
+}
+
+
+SYNAPSE_REGISTER(core_LoadModule)
+{
+ string error;
+ Cmsg out;
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+ CsessionPtr session;
+ Cmodule module;
+
+ //its already loaded?
+ if (module.isLoaded(msg["path"]))
+ {
+ DEB("module " << (string)msg["path"] << " is already loaded");
+ //is it ready as well?
+ if (!messageMan->isModuleReady(msg["path"]))
+ return;
+ else
+ {
+ //send out a modulename_ready to the requesting session to inform its already ready:
+ out.event=module.getName((string)msg["path"])+"_Ready";
+ DEB("module is already ready, sending a " << out.event);
+ out.dst=msg.src;
+ }
+ }
+ else
+ {
+ session=messageMan->loadModule(msg["path"],"module");
+ if (!session)
+ error="Error while loading module.";
+ else
+ {
+ out.event="module_Init";
+ out.dst=session->id;
+ }
+ }
+ }
+
+ if (error!="")
+ msg.returnError(error);
+ else
+ {
+ out.send();
+ }
+}
+
+
+
+SYNAPSE_REGISTER(core_Register)
+{
+ string error;
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+
+ CsessionPtr session=messageMan->userMan.getSession(msg.src);
+ if (!session)
+ error="Can't find session";
+ else
+ {
+ string handler;
+ if (msg.isSet("handler"))
+ handler=(string)msg["handler"];
+ else
+ handler=(string)msg["event"];
+
+ if (!session->module->setHandler(msg["event"], handler))
+ error="Can't find handler "+handler+" in module "+session->module->name;
+ else
+ return;
+ }
+ }
+ msg.returnError(error);
+}
+
+
+SYNAPSE_REGISTER(core_ChangeEvent)
+{
+ //since permissions are very imporatant, make sure the user didnt make a typo.
+ //(normally we dont care about typo's since then something just wouldn't work, but this function will work if the user doesnt specify one or more parameters.)
+ if (msg.returnIfOtherThan("sendGroup","event","recvGroup","modifyGroup",NULL))
+ return;
+
+ string error;
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+ CsessionPtr session=messageMan->userMan.getSession(msg.src);
+ if (!session)
+ error="Session not found";
+ else
+ {
+ CeventPtr event=messageMan->getEvent(msg["event"]);
+ if (!event)
+ error="Event not found?";
+ else
+ {
+ if (!event->isModifyAllowed(session->user))
+ error="You're not allowed to modify this event.";
+ else
+ {
+ CgroupPtr group;
+
+ if (msg.isSet("modifyGroup"))
+ if (!(group=messageMan->userMan.getGroup(msg["modifyGroup"])))
+ error+="Cant find modifygroup " +(string)msg["modifyGroup"]+ " ";
+ else
+ event->setModifyGroup(group);
+
+ if (msg.isSet("recvGroup"))
+ if (!(group=messageMan->userMan.getGroup(msg["recvGroup"])))
+ error="Cant find recvgroup " + (string)msg["recvGroup"]+ " ";
+ else
+ event->setRecvGroup(group);
+
+ if (msg.isSet("sendGroup"))
+ if (!(group=messageMan->userMan.getGroup(msg["sendGroup"])))
+ error+="Cant find sendgroup " + (string)msg["sendGroup"]+ " ";
+ else
+ event->setSendGroup(group);
+
+ }
+ }
+ }
+ }
+
+ if (error!="")
+ msg.returnError(error);
+}
+
+/** core_Login
+ * Check username and password and starts new session.
+ * Sends: module_SessionStart to new session
+ * Sends: module_SessionStarted to broadcast
+ * Sends: module_Login to src
+ */
+SYNAPSE_REGISTER(core_Login)
+{
+ string error;
+ Cmsg startmsg;
+ Cmsg loginmsg;
+
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+ CsessionPtr session=messageMan->userMan.getSession(msg.src);
+ if (!session)
+ error="Session not found";
+ else
+ {
+ CuserPtr user(messageMan->userMan.getUser(msg["username"]));
+ if (!user || !user->isPassword(msg["password"]))
+ error="Login invalid";
+ else
+ {
+ CsessionPtr newSession=CsessionPtr(new Csession(user,session->module));
+ int sessionId=messageMan->userMan.addSession(newSession);
+ if (sessionId==SESSION_DISABLED)
+ error="cant create new session";
+ else
+ {
+ //set max threads?
+ if (msg["maxThreads"] > 0)
+ newSession->maxThreads=msg["maxThreads"];
+
+ //send startmessage to the new session:
+ startmsg.event="module_SessionStart";
+ startmsg.dst=sessionId;
+ startmsg["username"]=msg["username"];
+
+ //send login message to the session that was requesting the login
+ loginmsg.event="module_Login";
+ loginmsg.dst=msg.src;
+ loginmsg["username"]=msg["username"];
+ }
+ }
+ }
+ }
+
+ if (error!="")
+ msg.returnError(error);
+ else
+ {
+ loginmsg.send();
+ startmsg.send();
+ //also broadcast module_SessionStarted, so other modules know that a session is started
+ startmsg.event="module_SessionStarted";
+ startmsg["session"]=startmsg.dst;
+ startmsg.dst=0;
+ startmsg.send();
+ }
+}
+
+/** core_NewSession
+ * Starts new session with the src user as owner
+ * Sends: module_SessionStart to new session
+ * Sends: module_SessionStarted to broadcast
+ */
+SYNAPSE_REGISTER(core_NewSession)
+{
+ string error;
+ Cmsg startmsg;
+
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+ CsessionPtr session=messageMan->userMan.getSession(msg.src);
+ if (!session)
+ error="Session not found";
+ else
+ {
+ CsessionPtr newSession=CsessionPtr(new Csession(session->user,session->module));
+ int sessionId=messageMan->userMan.addSession(newSession);
+ if (sessionId==SESSION_DISABLED)
+ error="cant create new session";
+ else
+ {
+ //set max threads?
+ if (msg["maxThreads"] > 0)
+ newSession->maxThreads=msg["maxThreads"];
+
+ //send startmessage to the new session:
+ startmsg.event="module_SessionStart";
+ startmsg.dst=sessionId;
+ if (msg.isSet("pars"))
+ {
+ startmsg["pars"]=msg["pars"];
+ }
+ startmsg["username"]=session->user->getName();
+ }
+ }
+ }
+
+ if (error!="")
+ msg.returnError(error);
+ else
+ {
+ startmsg.send();
+ //also broadcast module_SessionStarted, so other modules know that a session is started
+ startmsg.event="module_SessionStarted";
+ startmsg["session"]=startmsg.dst;
+ startmsg.dst=0;
+ startmsg.send();
+ }
+}
+
+
+SYNAPSE_REGISTER(core_Logout)
+{
+ string error;
+ Cmsg endmsg;
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+ CsessionPtr session=messageMan->userMan.getSession(msg.src);
+ if (!session)
+ error="Session not found";
+ }
+
+ if (error!="")
+ msg.returnError(error);
+ else
+ {
+ //send endmessage to the (still existing ) session:
+ endmsg.event="module_SessionEnd";
+ endmsg.dst=msg.src;
+ endmsg.send();
+
+ endmsg.event="module_SessionEnded";
+ endmsg["session"]=endmsg.dst;
+ endmsg.dst=0;
+ endmsg.send();
+
+ //now actually delete the session
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+ if (!messageMan->userMan.delSession(msg.src))
+ ERROR("cant delete session");
+ }
+ }
+}
+
+
+SYNAPSE_REGISTER(core_ChangeModule)
+{
+ string error;
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+
+ CsessionPtr session=messageMan->userMan.getSession(msg.src);
+ if (!session)
+ error="Can't find session";
+ else
+ {
+ if (msg["maxThreads"] > 0)
+ session->module->maxThreads=msg["maxThreads"];
+ }
+ }
+ if (error!="")
+ msg.returnError(error);
+}
+
+
+SYNAPSE_REGISTER(core_ChangeSession)
+{
+ string error;
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+
+ CsessionPtr session=messageMan->userMan.getSession(msg.src);
+ if (!session)
+ error="Can't find session";
+ else
+ {
+ if (msg["maxThreads"] > 0)
+ session->maxThreads=msg["maxThreads"];
+ }
+ }
+ if (error!="")
+ msg.returnError(error);
+}
+
+//Indicates the module is ready with its init stuff.
+//This results in a modulename_ready-broadcast to inform the other modules this one is ready to be used.
+SYNAPSE_REGISTER(core_Ready)
+{
+ Cmsg out;
+ string error;
+
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+
+ CsessionPtr session=messageMan->userMan.getSession(msg.src);
+ if (!session)
+ error="Can't find session";
+ else
+ {
+ out.event=session->module->name+"_Ready";
+ session->module->ready=true;
+ }
+ }
+
+ if (error!="")
+ msg.returnError(error);
+ else
+ out.send();
+}
+
+//Sends a thread.interrupt() to a executing call, or removes it from the call queue if its not executing yet.
+SYNAPSE_REGISTER(core_Interrupt)
+{
+ Cmsg out;
+ string error;
+
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+ if (!messageMan->callMan.interruptCall(msg["event"], msg.src, msg["dst"]))
+ error="Cannot find call, or call has already ended";
+ out.dst=msg.src;
+ out.event="core_InterruptSent";
+ out["pars"]=msg;
+ }
+
+
+ if (error!="")
+ msg.returnError(error);
+ else
+ out.send();
+}
+
+SYNAPSE_REGISTER(core_Shutdown)
+{
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+ messageMan->doShutdown((int)msg["exit"]);
+ }
+}
+
+SYNAPSE_REGISTER(core_ChangeLogging)
+{
+ {
+ lock_guard<mutex> lock(messageMan->threadMutex);
+ messageMan->logSends=msg["logSends"];
+ messageMan->logReceives=msg["logReceives"];
+ }
+}
diff --git a/modules/lirc.module/CMakeLists.txt b/modules/lirc.module/CMakeLists.txt
new file mode 100644
index 0000000..3e39c01
--- /dev/null
+++ b/modules/lirc.module/CMakeLists.txt
@@ -0,0 +1,28 @@
+#this is just a basic CMakeLists.txt, for more information see the cmake manpage
+
+cmake_minimum_required(VERSION 2.6)
+
+#add definitions, compiler switches, etc.
+ADD_DEFINITIONS(-Wall -O2)
+
+#Determine name of the .so module:
+#A module should always be in a modulename.module directory!.
+string(REGEX REPLACE ".*/([^/]*).module$" "\\1" module_name "${CMAKE_CURRENT_BINARY_DIR}")
+MESSAGE(STATUS "Module name of ${CMAKE_CURRENT_BINARY_DIR} is: '${module_name}'")
+
+#automaticly add all sourcefiles to current module
+file(GLOB sources *.cpp)
+ADD_LIBRARY(${module_name} MODULE ${sources})
+
+#need to link to some other libraries ? just add them here
+TARGET_LINK_LIBRARIES(${module_name})
+
+INCLUDE_DIRECTORIES(../..)
+
+#add an install target here
+#INSTALL_FILES(...)
+#INSTALL_PROGRAMS(...)
+#INSTALL_TARGET(...)
+
+
+
diff --git a/modules/lirc.module/module.cpp b/modules/lirc.module/module.cpp
new file mode 100644
index 0000000..38c5684
--- /dev/null
+++ b/modules/lirc.module/module.cpp
@@ -0,0 +1,98 @@
+#include "cnet.h"
+#include "synapse.h"
+#include <boost/regex.hpp>
+
+SYNAPSE_REGISTER(module_Init)
+{
+ Cmsg out;
+
+ out.clear();
+ out.event="core_ChangeModule";
+ out["maxThreads"]=10;
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeSession";
+ out["maxThreads"]=10;
+ out.send();
+
+ ///tell the rest of the world we are ready for duty
+ out.clear();
+ out.event="core_Ready";
+ out.send();
+}
+
+class CnetModule : public CnetMan
+{
+ void connected(int id)
+ {
+ Cmsg out;
+ out.dst=id;
+ out.event="lirc_Connected";
+ out.send();
+ }
+
+ void read(int id, asio::streambuf &readBuffer, std::size_t bytesTransferred)
+ {
+ //convert streambuf to string
+ string s(boost::asio::buffer_cast<const char*>(readBuffer.data()), bytesTransferred);
+
+
+ /* Example lirc output:
+ 0000000000001010 00 sys_00_command_10 PHILIPS_RC-5
+ 0000000000001010 01 sys_00_command_10 PHILIPS_RC-5
+ 0000000000001010 02 sys_00_command_10 PHILIPS_RC-5
+ 0000000000001010 03 sys_00_command_10 PHILIPS_RC-5
+ 0000000000001011 00 sys_00_command_11 PHILIPS_RC-5
+ 0000000000001011 01 sys_00_command_11 PHILIPS_RC-5
+ 0000000000001011 02 sys_00_command_11 PHILIPS_RC-5
+ */
+ //parse lirc output
+ smatch what;
+ if (regex_match(
+ s,
+ what,
+ boost::regex("(.*?) (.*?) (.*?) (.*?)\n")
+ ))
+ {
+ //TODO: make a dynamicly configurable mapper, which maps lirc-events to other events.
+ //(we'll do that probably after the gui-stuff is done)
+ Cmsg out;
+ out.event="lirc_Read";
+ out["code"] =what[1];
+ out["repeat"] =what[2];
+ out["key"] =what[3];
+ out["remote"] =what[4];
+ out.send();
+ }
+ else
+ {
+ ERROR("Cant parse lirc output: " << s);
+ }
+
+ }
+
+ void disconnected(int id, const boost::system::error_code& ec)
+ {
+ Cmsg out;
+ out.dst=id;
+ out.event="lirc_Disconnected";
+ out["reason"]=ec.message();
+ out.send();
+ }
+
+
+};
+
+CnetModule net;
+
+SYNAPSE_REGISTER(lirc_Connect)
+{
+ net.runConnect(msg.src, msg["host"], msg["port"], 5);
+}
+
+SYNAPSE_REGISTER(lirc_Disconnect)
+{
+ net.doDisconnect(msg.src);
+}
+
diff --git a/modules/net.module/CMakeLists.txt b/modules/net.module/CMakeLists.txt
new file mode 100644
index 0000000..3e39c01
--- /dev/null
+++ b/modules/net.module/CMakeLists.txt
@@ -0,0 +1,28 @@
+#this is just a basic CMakeLists.txt, for more information see the cmake manpage
+
+cmake_minimum_required(VERSION 2.6)
+
+#add definitions, compiler switches, etc.
+ADD_DEFINITIONS(-Wall -O2)
+
+#Determine name of the .so module:
+#A module should always be in a modulename.module directory!.
+string(REGEX REPLACE ".*/([^/]*).module$" "\\1" module_name "${CMAKE_CURRENT_BINARY_DIR}")
+MESSAGE(STATUS "Module name of ${CMAKE_CURRENT_BINARY_DIR} is: '${module_name}'")
+
+#automaticly add all sourcefiles to current module
+file(GLOB sources *.cpp)
+ADD_LIBRARY(${module_name} MODULE ${sources})
+
+#need to link to some other libraries ? just add them here
+TARGET_LINK_LIBRARIES(${module_name})
+
+INCLUDE_DIRECTORIES(../..)
+
+#add an install target here
+#INSTALL_FILES(...)
+#INSTALL_PROGRAMS(...)
+#INSTALL_TARGET(...)
+
+
+
diff --git a/modules/net.module/module.cpp b/modules/net.module/module.cpp
new file mode 100644
index 0000000..058e9f9
--- /dev/null
+++ b/modules/net.module/module.cpp
@@ -0,0 +1,171 @@
+
+/** Generic line based network client module.
+ * Use this module as an example to build your own network cabable modules. (like lirc)
+ * Connections are related to the session id that sended the message.
+ * So:
+ * -Every session has only 1 unique connection. If you want another connecting, start another session frist.
+ * -Other sessions (thus users) cannot influence the conneciton.
+ * -Received data will be send only to the session.
+ *
+ * The framework gives you the freedom to implement network-modules anyway you like: You could also decide to
+ * automaticly create new sessions in this module, when someone wants to make a connection.
+ *
+ */
+
+
+
+#include <string>
+
+#include "cnet.h"
+#include "synapse.h"
+
+/** module_Init - called first, set up basic stuff here
+ */
+SYNAPSE_REGISTER(module_Init)
+{
+ Cmsg out;
+
+ //max number of parallel threads
+ out.clear();
+ out.event="core_ChangeModule";
+ out["maxThreads"]=3000;
+ out.send();
+
+ //The default session will be used to call the run-functions.
+ //Every new connection needs a seperate thread.
+ out.clear();
+ out.event="core_ChangeSession";
+ out["maxThreads"]=1000;
+ out.send();
+
+ //Make a new session that only uses one thread to do the actual data-sending.
+ //This way we make sure all messages are received by us and send over the network in order.
+ //if you dont care about order and need better performance, change it to a higher number.
+ out.clear();
+ out.event="core_NewSession";
+ out["maxThreads"]=1;
+ out.send();
+
+}
+
+int dataSessionId;
+SYNAPSE_REGISTER(module_SessionStart)
+{
+ dataSessionId=msg.dst;
+ ///tell the rest of the world we are ready for duty
+ Cmsg out;
+ out.event="core_Ready";
+ out.send();
+}
+
+// We extent the CnetMan class with our own network handlers.
+// As soon as something with a network connection 'happens', these handlers will be called.
+// In the case of this generic module, the data is assume to be readable text and is sended with a net_Read message.
+class CnetModule : public CnetMan
+{
+ /** Connection 'id' is trying to connect to host:port
+ * Sends: net_Connecting
+ */
+ void connecting(int id, string host, string port)
+ {
+ Cmsg out;
+ out.dst=id;
+ out.event="net_Connecting";
+ out["host"]=host;
+ out["port"]=port;
+ out.send();
+ }
+
+ /** Connection 'id' is established.
+ * Sends: net_Connected
+ */
+ void connected(int id)
+ {
+ Cmsg out;
+ out.dst=id;
+ out.src=dataSessionId;
+ out.event="net_Connected";
+ out.send();
+ }
+
+ /** Connection 'id' has received new data.
+ * Sends: net_Read
+ */
+ void read(int id, asio::streambuf &readBuffer, std::size_t bytesTransferred)
+ {
+ Cmsg out;
+ //TODO: isnt there a more efficient way to convert the streambuf to string?
+ const char* s=boost::asio::buffer_cast<const char*>(readBuffer.data());
+ //remove newline..
+ out["data"].str().erase();
+ out["data"].str().append(s,bytesTransferred-1);
+ out.event="net_Read";
+ out.dst=id;
+ out.src=dataSessionId;
+ out.send();
+ }
+
+ /** Connection 'id' is disconnected, or a connect-attempt has failed.
+ * Sends: net_Disconnected
+ */
+ void disconnected(int id, const boost::system::error_code& ec)
+ {
+ Cmsg out;
+ out.dst=id;
+ out.event="net_Disconnected";
+ out["reason"]=ec.message();
+ out.send();
+ }
+};
+
+CnetModule net;
+
+
+/** Client-only: Create a new connection, connects to host:port for session src
+ */
+SYNAPSE_REGISTER(net_Connect)
+{
+ net.runConnect(msg.src, msg["host"], msg["port"]);
+}
+
+/** Server only: Creates a new server and listens specified port
+ */
+SYNAPSE_REGISTER(net_Listen)
+{
+ net.runListen(msg["port"]);
+}
+
+/** Server only: Accepts a connection on port and for session src
+ */
+SYNAPSE_REGISTER(net_Accept)
+{
+ net.runAccept(msg["port"], msg.src);
+
+}
+
+/** Server only: Stop listening on a port
+ */
+SYNAPSE_REGISTER(net_Close)
+{
+ net.doClose(msg["port"]);
+}
+
+/** Disconnections the connection related to src
+ */
+SYNAPSE_REGISTER(net_Disconnect)
+{
+ net.doDisconnect(msg.src);
+}
+
+/** Write data to the connection related to src
+ * If you care about data-ordering, send this to session-id that sended you the net_Connected.
+ */
+SYNAPSE_REGISTER(net_Write)
+{
+ //linebased, so add a newline
+ msg["data"].str()+="\n";
+ net.doWrite(msg.src, msg["data"]);
+}
+
+
+
diff --git a/modules/test.module/CMakeLists.txt b/modules/test.module/CMakeLists.txt
new file mode 100644
index 0000000..3e39c01
--- /dev/null
+++ b/modules/test.module/CMakeLists.txt
@@ -0,0 +1,28 @@
+#this is just a basic CMakeLists.txt, for more information see the cmake manpage
+
+cmake_minimum_required(VERSION 2.6)
+
+#add definitions, compiler switches, etc.
+ADD_DEFINITIONS(-Wall -O2)
+
+#Determine name of the .so module:
+#A module should always be in a modulename.module directory!.
+string(REGEX REPLACE ".*/([^/]*).module$" "\\1" module_name "${CMAKE_CURRENT_BINARY_DIR}")
+MESSAGE(STATUS "Module name of ${CMAKE_CURRENT_BINARY_DIR} is: '${module_name}'")
+
+#automaticly add all sourcefiles to current module
+file(GLOB sources *.cpp)
+ADD_LIBRARY(${module_name} MODULE ${sources})
+
+#need to link to some other libraries ? just add them here
+TARGET_LINK_LIBRARIES(${module_name})
+
+INCLUDE_DIRECTORIES(../..)
+
+#add an install target here
+#INSTALL_FILES(...)
+#INSTALL_PROGRAMS(...)
+#INSTALL_TARGET(...)
+
+
+
diff --git a/modules/test.module/module.cpp b/modules/test.module/module.cpp
new file mode 100644
index 0000000..8ae90cd
--- /dev/null
+++ b/modules/test.module/module.cpp
@@ -0,0 +1,62 @@
+#include "cnet.h"
+#include "synapse.h"
+
+SYNAPSE_REGISTER(module_Init)
+{
+ Cmsg out;
+
+ out.clear();
+ out.event="core_ChangeModule";
+ out["maxThreads"]=10;
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeSession";
+ out["maxThreads"]=10;
+ out.send();
+
+ ///tell the rest of the world we are ready for duty
+ out.clear();
+ out.event="core_Ready";
+ out.send();
+
+ out.clear();
+ out.event="core_LoadModule";
+ out["path"]="modules/lirc.module/liblirc.so";
+// out["path"]="modules/net.module/libnet.so";
+ out.send();
+
+}
+
+
+
+SYNAPSE_REGISTER(lirc_Ready)
+{
+ Cmsg out;
+ out.clear();
+ out.event="lirc_Connect";
+ out["host"]="192.168.13.1";
+ out["port"]="8765";
+ out.send();
+
+
+}
+
+SYNAPSE_REGISTER(net_Ready)
+{
+ Cmsg out;
+ out.clear();
+ out.event="net_Connect";
+ out["host"]="192.168.13.1";
+ out["port"]="8765";
+ out.send();
+
+
+}
+
+SYNAPSE_REGISTER(net_Read)
+{
+}
+SYNAPSE_REGISTER(lirc_Read)
+{
+} \ No newline at end of file
diff --git a/modules/test_net_loop.module/CMakeLists.txt b/modules/test_net_loop.module/CMakeLists.txt
new file mode 100644
index 0000000..58de7a5
--- /dev/null
+++ b/modules/test_net_loop.module/CMakeLists.txt
@@ -0,0 +1,28 @@
+#this is just a basic CMakeLists.txt, for more information see the cmake manpage
+
+cmake_minimum_required(VERSION 2.6)
+
+#add definitions, compiler switches, etc.
+ADD_DEFINITIONS(-Wall -O2)
+
+#Determine name of the .so module:
+#A module should always be in a modulename.module directory!.
+string(REGEX REPLACE ".*/([^/]*).module$" "\\1" module_name "${CMAKE_CURRENT_BINARY_DIR}")
+MESSAGE(STATUS "Module name of ${CMAKE_CURRENT_BINARY_DIR} is: '${module_name}'")
+
+#automaticly add all sourcefiles to current module
+file(GLOB sources *.cpp)
+ADD_LIBRARY(${module_name} MODULE ${sources})
+
+#need to link to some other libraries ? just add them here
+#TARGET_LINK_LIBRARIES(test)
+
+INCLUDE_DIRECTORIES(../..)
+
+#add an install target here
+#INSTALL_FILES(...)
+#INSTALL_PROGRAMS(...)
+#INSTALL_TARGET(...)
+
+
+
diff --git a/modules/test_net_loop.module/module.cpp b/modules/test_net_loop.module/module.cpp
new file mode 100644
index 0000000..a280e7d
--- /dev/null
+++ b/modules/test_net_loop.module/module.cpp
@@ -0,0 +1,200 @@
+#include "synapse.h"
+#include <boost/preprocessor/cat.hpp>
+#include <map>
+#include <string>
+
+using namespace std;
+using namespace boost;
+
+mutex threadMutex;
+
+
+SYNAPSE_REGISTER(module_Init)
+{
+
+ INFO("Regression test for: libnet loopback.");
+ Cmsg out;
+
+ out.clear();
+ out.event="core_ChangeModule";
+ out["maxThreads"]=10;
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeSession";
+ out["maxThreads"]=10;
+ out.send();
+
+ out.clear();
+ out.event="core_LoadModule";
+ out.dst=1;
+ out["path"]="modules/net.module/libnet.so";
+ out.send();
+
+ out.clear();
+ out.event="core_ChangeLogging";
+ out["logSends"]=0;
+ out["logReceives"]=0;
+ out.send();
+
+}
+
+#define NET_SESSIONS 30
+int sessions=0;
+
+SYNAPSE_REGISTER(net_Ready)
+{
+ Cmsg out;
+
+ //start server on port 12345
+ out.clear();
+ out.event="net_Listen";
+ out["port"]=12345;
+ out.send();
+
+ //accept connections
+ for (int a=0; a<NET_SESSIONS; a++)
+ {
+ out.clear();
+ out.event="core_NewSession";
+ out["pars"]["mode"]="accept";
+ out.send();
+ };
+
+ //create connections
+ for (int a=0; a<NET_SESSIONS; a++)
+ {
+ out.clear();
+ out.event="core_NewSession";
+ out["pars"]["mode"]="connect";
+ out.send();
+ };
+
+}
+
+SYNAPSE_REGISTER(module_SessionStart)
+{
+ sessions++;
+ if (msg["pars"]["mode"].str()=="accept")
+ {
+ Cmsg out;
+ out.clear();
+ out.event="net_Accept";
+ out.src=msg.dst;
+ out["port"]=12345;
+ out.send();
+ }
+ else
+ {
+ Cmsg out;
+ out.clear();
+ out.event="net_Connect";
+ out.src=msg.dst;
+ out["port"]=12345;
+ out["host"]="localhost";
+ out.send();
+ }
+}
+
+//keep track of the data-ordering
+int lastId[10000];
+bool failed=false;
+int sessioneof=0;
+
+SYNAPSE_REGISTER(net_Connected)
+{
+ lastId[msg.dst]=0;
+
+ INFO("CONNECTED " << msg.dst << " sending data..");
+
+ Cmsg out;
+ out.src=msg.dst;
+ out.dst=msg.src;
+ out.event="net_Write";
+
+ //send lines of text with an identifier, so we can check data order and integrety
+ for (int a=1; a<=1000; a++)
+ {
+ out["data"]=a;
+ out.send();
+ }
+ out["data"]="eof";
+ out.send();
+
+ INFO("SENDING FOR " << msg.dst << " completed..");
+}
+
+
+SYNAPSE_REGISTER(net_Read)
+{
+ if (msg["data"].str() == "eof")
+ {
+ INFO("GOT TO EOF FOR " << msg.dst);
+ {
+ lock_guard<mutex> lock(threadMutex);
+ sessioneof++;
+ }
+ lastId[msg.dst]=-1;
+ Cmsg out;
+ out.event="net_Disconnect";
+ out.src=msg.dst;
+ out.dst=msg.src;
+ out.send();
+ return;
+ }
+ else
+ //check if received value of this sessions against last one
+ if (lastId[msg.dst]+1 != msg["data"])
+ {
+ ERROR("Data ordering error: Expected " << lastId[msg.dst]+1 << " but got " << msg["data"]);
+ {
+ lock_guard<mutex> lock(threadMutex);
+ failed=true;
+ }
+ }
+ lastId[msg.dst]=msg["data"];
+
+}
+
+SYNAPSE_REGISTER(net_Disconnected)
+{
+ lock_guard<mutex> lock(threadMutex);
+
+ if (lastId[msg.dst]!=-1)
+ {
+ ERROR("Unexpected disconnect: lastId is not -1 but " << lastId[msg.src]);
+ }
+ sessions--;
+ if (!sessions)
+ {
+ Cmsg out;
+ if (failed)
+ {
+ ERROR("FAILED TESTS!");
+ out["exit"]=1;
+ }
+ else
+ if (sessioneof!=NET_SESSIONS*2)
+ {
+ ERROR("NOT ALL SESSIONS GOT TO EOF? expected " << NET_SESSIONS*2 << " but got " << sessioneof);
+ out["exit"]=1;
+ }
+ else
+ {
+ INFO("LAST SESSION DISCONNECTED, ALL TESTS SUCCEEDED")
+ Cmsg close;
+ close.event="net_Close";
+ close["port"]=12345;
+ close.send();
+ }
+ out.event="core_Shutdown";
+ out.send();
+ }
+ else
+ {
+ INFO("DISCONNECTED " << msg.dst << ", connections left: " << sessions);
+ }
+}
+
+
+
diff --git a/modules/timer.module/CMakeLists.txt b/modules/timer.module/CMakeLists.txt
new file mode 100644
index 0000000..58de7a5
--- /dev/null
+++ b/modules/timer.module/CMakeLists.txt
@@ -0,0 +1,28 @@
+#this is just a basic CMakeLists.txt, for more information see the cmake manpage
+
+cmake_minimum_required(VERSION 2.6)
+
+#add definitions, compiler switches, etc.
+ADD_DEFINITIONS(-Wall -O2)
+
+#Determine name of the .so module:
+#A module should always be in a modulename.module directory!.
+string(REGEX REPLACE ".*/([^/]*).module$" "\\1" module_name "${CMAKE_CURRENT_BINARY_DIR}")
+MESSAGE(STATUS "Module name of ${CMAKE_CURRENT_BINARY_DIR} is: '${module_name}'")
+
+#automaticly add all sourcefiles to current module
+file(GLOB sources *.cpp)
+ADD_LIBRARY(${module_name} MODULE ${sources})
+
+#need to link to some other libraries ? just add them here
+#TARGET_LINK_LIBRARIES(test)
+
+INCLUDE_DIRECTORIES(../..)
+
+#add an install target here
+#INSTALL_FILES(...)
+#INSTALL_PROGRAMS(...)
+#INSTALL_TARGET(...)
+
+
+
diff --git a/modules/timer.module/module.cpp b/modules/timer.module/module.cpp
new file mode 100644
index 0000000..d2258e9
--- /dev/null
+++ b/modules/timer.module/module.cpp
@@ -0,0 +1,73 @@
+#include "synapse.h"
+#include <time.h>
+
+
+SYNAPSE_REGISTER(module_Init)
+{
+ Cmsg out;
+
+
+ /// max 10 threads / timers active
+ out.clear();
+ out.event="core_ChangeModule";
+ out["maxThreads"]=10;
+ out.send();
+
+ ///tell the rest of the world we are ready for duty
+ //(the core will send a timer_Ready)
+ out.clear();
+ out.event="core_Ready";
+ out.send();
+}
+
+
+SYNAPSE_REGISTER(timer_Set)
+{
+ //absolute endtime given:
+ if (msg["time"])
+ {
+ struct timespec now;
+ if (clock_gettime(CLOCK_REALTIME,&now))
+ {
+ msg.returnError("Cant get time");
+ return;
+ }
+
+ if ((msg["time"]-now.tv_sec)>600)
+ {
+ msg.returnError("Time too far in the future.");
+ return;
+ }
+ struct timespec abstime;
+ abstime.tv_sec=((int)msg["time"]);
+ abstime.tv_nsec=((long double)msg["time"] - (int)msg["time"] )*1000000000;
+ clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abstime ,NULL);
+ }
+ //relative time delta given:
+ else if (msg["seconds"])
+ {
+ if (msg["seconds"]>600)
+ {
+ msg.returnError("Time delay too long.");
+ return;
+ }
+ struct timespec reltime;
+ reltime.tv_sec=((int)msg["seconds"]);
+ reltime.tv_nsec=((long double)msg["seconds"] - (int)msg["seconds"] )*1000000000;
+ clock_nanosleep(CLOCK_REALTIME, 0, &reltime ,NULL);
+ }
+ else
+ {
+ msg.returnError("No time specified.");
+ return;
+ }
+
+ Cmsg out(msg);
+ out.src=0;
+ out.dst=msg["dst"];
+ out.event=(string)msg["event"];
+ out.erase(out.find("event"));
+ out.send();
+}
+
+
diff --git a/synapse.h b/synapse.h
new file mode 100644
index 0000000..69cadad
--- /dev/null
+++ b/synapse.h
@@ -0,0 +1,128 @@
+//this header file includes all the headers that are needed to compile a synapse module
+//TODO: split this up in 2 header files: one for the module init stuff and another thats a real header that can be included multiple times.
+
+
+#include "cmsg.h"
+#include "clog.h"
+#include "cmodule.h"
+#include "cmessageman.h"
+#include <boost/foreach.hpp>
+#include <stdarg.h>
+
+
+#ifdef SYNAPSE_HAS_INIT
+ void init();
+#endif
+
+//basic objects that are needed to call send messages
+weak_ptr<Cmodule> module; //weak pointer, otherwise the reference count would be of by one when unloading a module.
+CmessageMan * messageMan;
+
+// Thanks to hkaiser@#boost for helping me with the automatic handler registration:
+struct synapseAutoReg
+{
+ synapseAutoReg(char const* name)
+ {
+ handlers.push_back(name);
+ }
+ static list<string> handlers;
+};
+
+list<string> synapseAutoReg::handlers;
+
+//This stores the handler in a list by constructing a dummy object:
+#define SYNAPSE_REGISTER(name) \
+ synapseAutoReg BOOST_PP_CAT(synapseAutoRegDummy, __LINE__)(#name); \
+ SYNAPSE_HANDLER(name)
+
+
+//to determine compatability of module:
+extern "C" int synapseVersion() {
+ return (SYNAPSE_API_VERSION);
+};
+
+
+
+
+extern "C" bool synapseInit(CmessageMan * initMessageMan, CmodulePtr initModule)
+{
+ messageMan=initMessageMan;
+ module=initModule;
+
+ //when this function is called we have a core-lock, so we can register our handlers directly:
+ BOOST_FOREACH(string handler, synapseAutoReg::handlers)
+ {
+ ((CmodulePtr)module)->setHandler(handler, handler);
+ }
+ synapseAutoReg::handlers.clear();
+
+ //this module has its own init function?
+ #ifdef SYNAPSE_HAS_INIT
+ init();
+ #endif
+ return true;
+}
+
+extern "C" void synapseCleanup()
+{
+ //nothing to do yet..
+}
+
+
+
+//make a copy of the message (can expensive for complex message structures)
+//and send a smartpointer of it to the core.
+//sendPtr should be defined in each module in synapse.h
+//you CANT send messages from the core with this funtion, you'll get an 'undefined reference'. :)
+bool Cmsg::send()
+{
+ lock_guard<mutex> lock(messageMan->threadMutex);
+
+ return(messageMan->sendMessage((CmodulePtr)module,CmsgPtr(new Cmsg(*this))));
+}
+
+
+/*!
+ \fn Cmsg::returnError(string error)
+ */
+void Cmsg::returnError(string description)
+{
+ ERROR("while handling " << event << ": " << description);
+ Cmsg error;
+ error.event="module_Error";
+ error.dst=src;
+ error.src=dst;
+ error["event"]=event;
+ error["description"]=description;
+ error["parameters"]=*this;
+ error.send();
+}
+
+bool Cmsg::returnIfOtherThan(char * keys, ...)
+{
+ va_list args;
+ va_start(args,keys);
+
+ char * key=keys;
+ unsigned int found=0;
+
+ do
+ {
+
+ if (isSet(key))
+ {
+ found++;
+ }
+ }
+ while ((key=va_arg(args,char *))!=NULL);
+
+ va_end(args);
+
+ if (size()>found)
+ {
+ returnError("Extra parameters found");
+ return true;
+ }
+ return false;
+
+}
diff --git a/synapse.kdevelop b/synapse.kdevelop
new file mode 100644
index 0000000..ada4e39
--- /dev/null
+++ b/synapse.kdevelop
@@ -0,0 +1,232 @@
+<?xml version = '1.0'?>
+<kdevelop>
+ <general>
+ <author></author>
+ <email></email>
+ <version>$VERSION$</version>
+ <projectmanagement>KDevCustomProject</projectmanagement>
+ <primarylanguage>C++</primarylanguage>
+ <ignoreparts/>
+ <projectdirectory>/home/psy/svnhobbybop/framework/synapse</projectdirectory>
+ <absoluteprojectpath>true</absoluteprojectpath>
+ <secondaryLanguages>
+ <language>C</language>
+ </secondaryLanguages>
+ <projectname>synapse</projectname>
+ <description></description>
+ <defaultencoding></defaultencoding>
+ <versioncontrol></versioncontrol>
+ </general>
+ <kdevcustomproject>
+ <filelistdirectory>/home/psy/svnhobbybop/framework/synapse</filelistdirectory>
+ <run>
+ <mainprogram>/home/psy/svnhobbybop/framework/synapse/synapse</mainprogram>
+ <directoryradio>custom</directoryradio>
+ <customdirectory>/home/psy/svnhobbybop/framework/synapse</customdirectory>
+ <programargs>modules/test.module/libtest.so</programargs>
+ <terminal>true</terminal>
+ <autocompile>true</autocompile>
+ <envvars/>
+ <globaldebugarguments></globaldebugarguments>
+ <globalcwd>/home/psy/svnhobbybop/framework/synapse</globalcwd>
+ <useglobalprogram>false</useglobalprogram>
+ <autoinstall>false</autoinstall>
+ <autokdesu>false</autokdesu>
+ </run>
+ <build>
+ <buildtool>make</buildtool>
+ <builddir>/home/psy/svnhobbybop/framework/synapse</builddir>
+ </build>
+ <make>
+ <abortonerror>false</abortonerror>
+ <numberofjobs>4</numberofjobs>
+ <dontact>false</dontact>
+ <makebin>/usr/bin/gmake </makebin>
+ <selectedenvironment>default</selectedenvironment>
+ <environments>
+ <default>
+ <envvar value="1" name="VERBOSE" />
+ </default>
+ <debug>
+ <envvar value="Debug" name="CMAKE_BUILD_TYPE" />
+ </debug>
+ </environments>
+ <prio>0</prio>
+ <defaulttarget></defaulttarget>
+ <makeoptions></makeoptions>
+ </make>
+ <blacklist>
+ <path>modules/test/CMakeFiles</path>
+ <path>modules/test/CMakeFiles/CompilerIdC</path>
+ <path>modules/test/CMakeFiles/CompilerIdC/CMakeCCompilerId.c</path>
+ <path>modules/test/CMakeFiles/CompilerIdCXX</path>
+ <path>modules/test/CMakeFiles/CompilerIdCXX/CMakeCXXCompilerId.cpp</path>
+ <path>modules/test/CMakeLists.txt</path>
+ <path>modules/test/Makefile</path>
+ <path>modules/test/src</path>
+ <path>modules/test/src/CMakeLists.txt</path>
+ <path>modules/test/src/Makefile</path>
+ <path>modules/test/src/test.cpp</path>
+ <path>modules/test/src/test.h</path>
+ <path>modules/test/src/testtest.cpp</path>
+ <path>synapse.h</path>
+ </blacklist>
+ <filetypes>
+ <filetype>*.java</filetype>
+ <filetype>*.h</filetype>
+ <filetype>*.H</filetype>
+ <filetype>*.hh</filetype>
+ <filetype>*.hxx</filetype>
+ <filetype>*.hpp</filetype>
+ <filetype>*.c</filetype>
+ <filetype>*.C</filetype>
+ <filetype>*.cc</filetype>
+ <filetype>*.cpp</filetype>
+ <filetype>*.c++</filetype>
+ <filetype>*.cxx</filetype>
+ <filetype>Makefile</filetype>
+ <filetype>CMakeLists.txt</filetype>
+ </filetypes>
+ <other>
+ <prio>0</prio>
+ <otherbin></otherbin>
+ <defaulttarget></defaulttarget>
+ <otheroptions></otheroptions>
+ <selectedenvironment>default</selectedenvironment>
+ <environments>
+ <default/>
+ </environments>
+ </other>
+ </kdevcustomproject>
+ <kdevfilecreate>
+ <filetypes/>
+ <useglobaltypes>
+ <type ext="ui" />
+ <type ext="cpp" />
+ <type ext="h" />
+ </useglobaltypes>
+ </kdevfilecreate>
+ <kdevdoctreeview>
+ <projectdoc>
+ <userdocDir>html/</userdocDir>
+ <apidocDir>html/</apidocDir>
+ </projectdoc>
+ <ignoreqt_xml/>
+ <ignoredoxygen/>
+ <ignorekdocs/>
+ <ignoretocs/>
+ <ignoredevhelp/>
+ </kdevdoctreeview>
+ <cppsupportpart>
+ <filetemplates>
+ <interfacesuffix>.h</interfacesuffix>
+ <implementationsuffix>.cpp</implementationsuffix>
+ </filetemplates>
+ </cppsupportpart>
+ <kdevcppsupport>
+ <codecompletion>
+ <includeGlobalFunctions>true</includeGlobalFunctions>
+ <includeTypes>true</includeTypes>
+ <includeEnums>true</includeEnums>
+ <includeTypedefs>false</includeTypedefs>
+ <automaticCodeCompletion>true</automaticCodeCompletion>
+ <automaticArgumentsHint>true</automaticArgumentsHint>
+ <automaticHeaderCompletion>true</automaticHeaderCompletion>
+ <codeCompletionDelay>250</codeCompletionDelay>
+ <argumentsHintDelay>400</argumentsHintDelay>
+ <headerCompletionDelay>250</headerCompletionDelay>
+ <showOnlyAccessibleItems>false</showOnlyAccessibleItems>
+ <completionBoxItemOrder>0</completionBoxItemOrder>
+ <howEvaluationContextMenu>true</howEvaluationContextMenu>
+ <showCommentWithArgumentHint>true</showCommentWithArgumentHint>
+ <statusBarTypeEvaluation>true</statusBarTypeEvaluation>
+ <namespaceAliases>std=_GLIBCXX_STD;__gnu_cxx=std</namespaceAliases>
+ <processPrimaryTypes>true</processPrimaryTypes>
+ <processFunctionArguments>true</processFunctionArguments>
+ <preProcessAllHeaders>true</preProcessAllHeaders>
+ <parseMissingHeadersExperimental>false</parseMissingHeadersExperimental>
+ <resolveIncludePathsUsingMakeExperimental>false</resolveIncludePathsUsingMakeExperimental>
+ <alwaysParseInBackground>true</alwaysParseInBackground>
+ <usePermanentCaching>true</usePermanentCaching>
+ <alwaysIncludeNamespaces>true</alwaysIncludeNamespaces>
+ <includePaths>.;</includePaths>
+ </codecompletion>
+ <references/>
+ <qt>
+ <used>false</used>
+ <version>3</version>
+ <includestyle>3</includestyle>
+ <root>/usr/qt/3</root>
+ <designerintegration>EmbeddedKDevDesigner</designerintegration>
+ <qmake>/usr/qt/3/bin/qmake</qmake>
+ <designer>/usr/qt/3/bin/designer</designer>
+ <designerpluginpaths/>
+ </qt>
+ <creategettersetter>
+ <prefixGet></prefixGet>
+ <prefixSet>set</prefixSet>
+ <prefixVariable>m_,_</prefixVariable>
+ <parameterName>theValue</parameterName>
+ <inlineGet>true</inlineGet>
+ <inlineSet>true</inlineSet>
+ </creategettersetter>
+ <splitheadersource>
+ <enabled>false</enabled>
+ <synchronize>true</synchronize>
+ <orientation>Vertical</orientation>
+ </splitheadersource>
+ </kdevcppsupport>
+ <kdevfileview>
+ <groups>
+ <group pattern="CMakeLists.txt;*.cmake;" name="CMake" />
+ <group pattern="*.h;*.hxx;*.hpp" name="Header" />
+ <group pattern="*.c" name="C Sources" />
+ <group pattern="*.cpp;*.C;*.cxx;*.cc" name="C++ Sources" />
+ <group pattern="*.ui" name="Qt Designer files" />
+ <hidenonprojectfiles>true</hidenonprojectfiles>
+ <hidenonlocation>false</hidenonlocation>
+ </groups>
+ <tree>
+ <hidepatterns>*.o,*.lo,CVS,*~,cmake*</hidepatterns>
+ <hidenonprojectfiles>true</hidenonprojectfiles>
+ </tree>
+ </kdevfileview>
+ <substmap>
+ <APPNAME>synapse</APPNAME>
+ <APPNAMELC>synapse</APPNAMELC>
+ <APPNAMESC>Synapse</APPNAMESC>
+ <APPNAMEUC>SYNAPSE</APPNAMEUC>
+ <AUTHOR>Edwin Eefting</AUTHOR>
+ <EMAIL>edwin@datux.nl</EMAIL>
+ <LICENSE>GPL</LICENSE>
+ <LICENSEFILE>COPYING</LICENSEFILE>
+ <VERSION>0.1</VERSION>
+ <YEAR>2009</YEAR>
+ <dest>/home/psy/svnhobbybop/framework/synapse</dest>
+ </substmap>
+ <kdevdebugger>
+ <general>
+ <gdbpath></gdbpath>
+ <dbgshell></dbgshell>
+ <configGdbScript></configGdbScript>
+ <runShellScript></runShellScript>
+ <runGdbScript></runGdbScript>
+ <breakonloadinglibs>true</breakonloadinglibs>
+ <separatetty>true</separatetty>
+ <floatingtoolbar>false</floatingtoolbar>
+ <raiseGDBOnStart>false</raiseGDBOnStart>
+ </general>
+ <display>
+ <staticmembers>false</staticmembers>
+ <demanglenames>true</demanglenames>
+ <outputradix>10</outputradix>
+ </display>
+ </kdevdebugger>
+ <kdevdocumentation>
+ <projectdoc>
+ <docsystem></docsystem>
+ <docurl></docurl>
+ <usermanualurl></usermanualurl>
+ </projectdoc>
+ </kdevdocumentation>
+</kdevelop>
diff --git a/synapse.kdevelop.filelist b/synapse.kdevelop.filelist
new file mode 100644
index 0000000..773ca2b
--- /dev/null
+++ b/synapse.kdevelop.filelist
@@ -0,0 +1,66 @@
+# KDevelop Custom Project File List
+.
+./ccall.cpp
+./ccall.h
+./ccallman.cpp
+./ccallman.h
+./cgroup.cpp
+./cgroup.h
+./clog.cpp
+./clog.h
+./cmodule.cpp
+./cmodule.h
+./cmsg.cpp
+./cmsg.h
+./cnet.cpp
+./cnet.h
+./csession.cpp
+./csession.h
+./cuser.cpp
+./cuser.h
+./cuserman.cpp
+./cuserman.h
+./cvar.cpp
+./cvar.h
+CMakeFiles
+CMakeFiles/CompilerIdC
+CMakeFiles/CompilerIdC/CMakeCCompilerId.c
+CMakeFiles/CompilerIdCXX
+CMakeFiles/CompilerIdCXX/CMakeCXXCompilerId.cpp
+CMakeLists.txt
+Makefile
+ccall.cpp
+ccall.h
+ccallman.cpp
+ccallman.h
+cevent.cpp
+cevent.h
+cgroup.cpp
+cgroup.h
+clog.cpp
+clog.h
+cmessageman.cpp
+cmessageman.h
+cmodule.cpp
+cmodule.h
+cmsg.cpp
+cmsg.h
+cnet.cpp
+cnet.h
+cnetman.cpp
+cnetman.h
+common.h
+csession.cpp
+csession.h
+cuser.cpp
+cuser.h
+cuserman.cpp
+cuserman.h
+cvar.cpp
+cvar.h
+main.cpp
+modules
+modules/lirc.module
+modules/lirc.module/module.cpp
+modules/test.module
+modules/test.module/Makefile
diff --git a/synapse.kdevses b/synapse.kdevses
new file mode 100644
index 0000000..7e4bfea
--- /dev/null
+++ b/synapse.kdevses
@@ -0,0 +1,50 @@
+<?xml version = '1.0' encoding = 'UTF-8'?>
+<!DOCTYPE KDevPrjSession>
+<KDevPrjSession>
+ <DocsAndViews NumberOfDocuments="7" >
+ <Doc0 NumberOfViews="1" URL="file:///home/psy/svnhobbybop/framework/synapse/modules/lirc.module/module.cpp" >
+ <View0 Encoding="" line="23" Type="Source" />
+ </Doc0>
+ <Doc1 NumberOfViews="1" URL="file:///home/psy/svnhobbybop/framework/synapse/cmessageman.h" >
+ <View0 Encoding="" line="65" Type="Source" />
+ </Doc1>
+ <Doc2 NumberOfViews="1" URL="file:///home/psy/svnhobbybop/framework/synapse/main.cpp" >
+ <View0 Encoding="" line="10" Type="Source" />
+ </Doc2>
+ <Doc3 NumberOfViews="1" URL="file:///home/psy/svnhobbybop/framework/synapse/cmessageman.cpp" >
+ <View0 Encoding="" line="382" Type="Source" />
+ </Doc3>
+ <Doc4 NumberOfViews="1" URL="file:///home/psy/svnhobbybop/framework/synapse/modules/net.module/module.cpp" >
+ <View0 Encoding="" line="151" Type="Source" />
+ </Doc4>
+ <Doc5 NumberOfViews="1" URL="file:///home/psy/svnhobbybop/framework/synapse/cnet.cpp" >
+ <View0 Encoding="" line="8" Type="Source" />
+ </Doc5>
+ <Doc6 NumberOfViews="1" URL="file:///home/psy/svnhobbybop/framework/synapse/cnetman.cpp" >
+ <View0 Encoding="" line="0" Type="Source" />
+ </Doc6>
+ </DocsAndViews>
+ <pluginList>
+ <kdevdebugger>
+ <breakpointList/>
+ <showInternalCommands value="0" />
+ </kdevdebugger>
+ <kdevastyle>
+ <Extensions ext="*.cpp *.h *.hpp,*.c *.h,*.cxx *.hxx,*.c++ *.h++,*.cc *.hh,*.C *.H,*.diff ,*.inl,*.java,*.moc,*.patch,*.tlh,*.xpm" />
+ <AStyle IndentPreprocessors="0" FillCount="4" PadParenthesesOut="1" IndentNamespaces="1" IndentLabels="1" Fill="Tabs" MaxStatement="40" Brackets="Break" MinConditional="-1" IndentBrackets="0" PadParenthesesUn="1" BlockBreak="0" KeepStatements="1" KeepBlocks="1" BlockIfElse="0" IndentSwitches="1" PadOperators="0" FStyle="UserDefined" IndentCases="0" FillEmptyLines="0" BracketsCloseHeaders="0" BlockBreakAll="0" PadParenthesesIn="1" IndentClasses="1" IndentBlocks="0" FillForce="1" />
+ </kdevastyle>
+ <kdevbookmarks>
+ <bookmarks>
+ <bookmark url="/home/psy/svnhobbybop/framework/synapse/cuserman.cpp" >
+ <mark line="198" />
+ </bookmark>
+ </bookmarks>
+ </kdevbookmarks>
+ <kdevvalgrind>
+ <executable path="" params="" />
+ <valgrind path="/usr/bin/valgrind" params=" --tool=memcheck --leak-check=yes" />
+ <calltree path="/usr/bin/valgrind" params="--tool=callgrind" />
+ <kcachegrind path="kcachegrind" />
+ </kdevvalgrind>
+ </pluginList>
+</KDevPrjSession>