add upstream source (adch++ 2.12.1 from sourceforge)

This commit is contained in:
Jeffrey Paul 2020-03-22 01:45:29 -07:00
parent 3574617350
commit 2cfbcf1301
9637 changed files with 1934407 additions and 0 deletions

5
src/.hg_archival.txt Normal file
View File

@ -0,0 +1,5 @@
repo: 41072e8158463f921a1157e780a40dd82b2ddbf6
node: feedb6b4a3381644034fd3e5fbfcdc91be7e31ce
branch: default
latesttag: 2.3
latesttagdistance: 486

15
src/.hgignore Normal file
View File

@ -0,0 +1,15 @@
^doc$
^logs$
^build$
^custom\.py$
^openssl$
\.pdb$
\.gch$
\.pot$
\.pyc$
\.csettings$
\.sconsign\.dblite$
^php/include/
^php/lib/
^php/x64/include/
^php/x64/lib/

1
src/.hgtags Normal file
View File

@ -0,0 +1 @@
807c6d3c5e39c1eeb2625351dc82ac231175947e 2.3

279
src/ADCHPP.nsi Normal file
View File

@ -0,0 +1,279 @@
; Script generated by the HM NIS Edit Script Wizard.
; HM NIS Edit Wizard helper defines
!define PRODUCT_NAME "ADCH++"
!define PRODUCT_PUBLISHER "Jacek Sieka"
!define PRODUCT_WEB_SITE "http://adchpp.sourceforge.net"
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\adchppd.exe"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
Function GetAdchppdVersion
Exch $0
GetDllVersion "$INSTDIR\$0" $R0 $R1
IntOp $R2 $R0 >> 16
IntOp $R2 $R2 & 0x0000FFFF
IntOp $R3 $R0 & 0x0000FFFF
IntOp $R4 $R1 >> 16
IntOp $R4 $R4 & 0x0000FFFF
StrCpy $1 "$R2.$R3.$R4"
Exch $1
FunctionEnd
SetCompressor lzma
; MUI 1.67 compatible ------
!include "MUI.nsh"
; MUI Settings
!define MUI_ABORTWARNING
!define MUI_ICON "adchppd.ico"
!define MUI_UNICON "adchppd.ico"
; Welcome page
!insertmacro MUI_PAGE_WELCOME
; Directory page
!insertmacro MUI_PAGE_DIRECTORY
; Instfiles page
!insertmacro MUI_PAGE_INSTFILES
; Finish page
!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\readme.txt"
!define MUI_FINISHPAGE_RUN "$INSTDIR\adchppd.exe"
!insertmacro MUI_PAGE_FINISH
; Uninstaller pages
!insertmacro MUI_UNPAGE_INSTFILES
; Language files
!insertmacro MUI_LANGUAGE "English"
; Reserve files
!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
; MUI end ------
Name "${PRODUCT_NAME}"
OutFile "ADCHPP-xxx.exe"
InstallDir "$PROGRAMFILES\ADCH++"
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
ShowInstDetails show
ShowUnInstDetails show
Section "MainSection" SEC01
SetOutPath "$INSTDIR"
SetOverwrite ifnewer
File "aboost_date_time.dll"
File "aboost_system.dll"
File "adchpp.dll"
File "adchppd.exe"
File "alua.dll"
File "Bloom.dll"
File "changelog.txt"
File "lfs.dll"
File "libgcc_s_dw2-1.dll"
File "libstdc++-6.dll"
File "License.txt"
File "luadchpp.dll"
File "pyadchpp.py"
File "Script.dll"
File "luadchppbloom.dll"
File "aboost_locale.dll"
File "readme.txt"
File "FirstReg.cmd"
File "Generate_certs.cmd"
CreateShortCut "$DESKTOP\ADCH++.lnk" "$INSTDIR\adchppd.exe"
CreateDirectory "$SMPROGRAMS\ADCH++"
CreateShortCut "$SMPROGRAMS\ADCH++\ADCH++ Help.lnk" "$INSTDIR\readme.txt"
CreateShortCut "$SMPROGRAMS\ADCH++\Install ADCH++ as windows service.lnk" "$INSTDIR\adchppd.exe" "-i adchppd"
CreateShortCut "$SMPROGRAMS\ADCH++\Remove ADCH++ windows service.lnk" "$INSTDIR\adchppd.exe" "-u adchppd"
SetOutPath "$INSTDIR\lua"
File "lua\*.lua"
SetOutPath "$INSTDIR\lua\socket"
File "lua\socket\*.lua"
SetOutPath "$INSTDIR\mime"
File "mime\*"
SetOutPath "$INSTDIR\socket"
File "socket\*"
SetOutPath "$INSTDIR\Scripts"
File "Scripts\access.lua"
File "Scripts\access.bans.lua"
File "Scripts\access.bot.lua"
IfFileExists $INSTDIR\Scripts\access.limits.lua 0 +2
Rename $INSTDIR\Scripts\access.limits.lua $INSTDIR\Scripts\access.limits.lua.old
File "Scripts\access.guard.lua"
File "Scripts\access.op.lua"
File "Scripts\autil.lua"
File "Scripts\aio.lua"
File "Scripts\example.lua"
File "Scripts\history.lua"
File "Scripts\json.lua"
File "Scripts\motd.lua"
File "Scripts\checkemptyinbloom.lua"
CreateDirectory $INSTDIR\Scripts\FL_Database
SetOutPath "$INSTDIR\Docs"
File "Docs\*.conf"
File "Docs\*.html"
File "Docs\*.txt"
SetOutPath "$INSTDIR\Docs\images"
File "Docs\images\*.png"
SetOutPath "$INSTDIR\Docs\images\icons"
File "Docs\images\icons\*.png"
SetOverwrite off
SetOutPath "$INSTDIR\config"
File "config\motd.txt"
File "config\adchpp.xml"
File "config\Script.xml"
SectionEnd
Section -AdditionalIcons
SetOutPath $INSTDIR
WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
CreateShortCut "$SMPROGRAMS\ADCH++\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url"
CreateShortCut "$SMPROGRAMS\ADCH++\ADCH++.lnk" "$INSTDIR\adchppd.exe"
CreateShortCut "$SMPROGRAMS\ADCH++\Uninstall.lnk" "$INSTDIR\uninst.exe"
SectionEnd
Section -Service
MessageBox MB_ICONQUESTION|MB_YESNO "Do you wish to install ADCH++ as a service?" IDYES Service IDNO End
Service: Exec '"$INSTDIR\adchppd.exe" -i adchppd'
End:
SectionEnd
Section -Post
WriteUninstaller "$INSTDIR\uninst.exe"
; Get adchppd version we just installed and store in $1
Push "adchppd.exe"
Call "GetAdchppdVersion"
Pop $1
WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\adchppd.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name) $1"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\adchppd.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "$1"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
SectionEnd
Function un.onUninstSuccess
HideWindow
MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer."
FunctionEnd
Function un.onInit
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2
Abort
FunctionEnd
Section -un.Service
Exec 'sc delete adchppd'
SectionEnd
Section -un.remSettings
MessageBox MB_ICONQUESTION|MB_YESNO "Do you wish to remove all the ADCH++ configuration files, statistics, logs and accounts?" IDYES Remove IDNO NoRemove
Remove:
Delete "$INSTDIR\config\users.txt"
Delete "$INSTDIR\config\history.txt"
Delete "$INSTDIR\config\settings.txt"
Delete "$INSTDIR\config\motd.txt"
Delete "$INSTDIR\config\bans.txt"
Delete "$INSTDIR\config\en_settings.txt"
Delete "$INSTDIR\config\fl_settings.txt"
Delete "$INSTDIR\config\li_settings.txt"
Delete "$INSTDIR\config\users.txt.tmp"
Delete "$INSTDIR\config\history.txt.tmp"
Delete "$INSTDIR\config\settings.txt.tmp"
Delete "$INSTDIR\config\motd.txt.tmp"
Delete "$INSTDIR\config\bans.txt.tmp"
Delete "$INSTDIR\config\en_settings.txt.tmp"
Delete "$INSTDIR\config\fl_settings.txt.tmp"
Delete "$INSTDIR\config\li_settings.txt.tmp"
Delete "$INSTDIR\config\Script.xml"
Delete "$INSTDIR\config\adchpp.xml"
Delete "$INSTDIR\config\logs\*.log"
Delete "$INSTDIR\Scripts\FL_Database\commandstats.txt"
Delete "$INSTDIR\Scripts\FL_Database\entitystats.txt"
Delete "$INSTDIR\Scripts\FL_Database\kickstats.txt"
Delete "$INSTDIR\Scripts\FL_Database\limitstats.txt"
Delete "$INSTDIR\Scripts\FL_Database\tmpbanstats.txt"
Delete "$INSTDIR\Scripts\FL_Database\commandstats.txt.tmp"
Delete "$INSTDIR\Scripts\FL_Database\entitystats.txt.tmp"
Delete "$INSTDIR\Scripts\FL_Database\kickstats.txt.tmp"
Delete "$INSTDIR\Scripts\FL_Database\limitstats.txt.tmp"
Delete "$INSTDIR\Scripts\FL_Database\tmpbanstats.txt.tmp"
NoRemove:
SectionEnd
Section Uninstall
Delete "$INSTDIR\${PRODUCT_NAME}.url"
Delete "$INSTDIR\aboost_date_time.dll"
Delete "$INSTDIR\aboost_system.dll"
Delete "$INSTDIR\adchpp.dll"
Delete "$INSTDIR\adchppd.exe"
Delete "$INSTDIR\alua.dll"
Delete "$INSTDIR\Bloom.dll"
Delete "$INSTDIR\changelog.txt"
Delete "$INSTDIR\lfs.dll"
Delete "$INSTDIR\libgcc_s_dw2-1.dll"
Delete "$INSTDIR\libstdc++-6.dll"
Delete "$INSTDIR\License.txt"
Delete "$INSTDIR\luadchpp.dll"
Delete "$INSTDIR\pyadchpp.py"
Delete "$INSTDIR\Script.dll"
Delete "$INSTDIR\luadchppbloom.dll"
Delete "$INSTDIR\aboost_locale.dll"
Delete "$INSTDIR\readme.txt"
Delete "$INSTDIR\FirstReg.cmd"
Delete "$INSTDIR\Generate_certs.cmd"
Delete "$INSTDIR\lua\*.lua"
Delete "$INSTDIR\lua\socket\*.lua"
Delete "$INSTDIR\mime\core.dll"
Delete "$INSTDIR\socket\core.dll"
Delete "$INSTDIR\Scripts\access.lua"
Delete "$INSTDIR\Scripts\access.bans.lua"
Delete "$INSTDIR\Scripts\access.bot.lua"
Delete "$INSTDIR\Scripts\access.guard.lua"
Delete "$INSTDIR\Scripts\access.limits.lua"
Delete "$INSTDIR\Scripts\access.limits.lua.old"
Delete "$INSTDIR\Scripts\access.op.lua"
Delete "$INSTDIR\Scripts\aio.lua"
Delete "$INSTDIR\Scripts\autil.lua"
Delete "$INSTDIR\Scripts\example.lua"
Delete "$INSTDIR\Scripts\history.lua"
Delete "$INSTDIR\Scripts\json.lua"
Delete "$INSTDIR\Scripts\motd.lua"
Delete "$INSTDIR\Scripts\checkemptyinbloom.lua"
Delete "$INSTDIR\Docs\images\icons\*.*"
Delete "$INSTDIR\Docs\images\*.*"
Delete "$INSTDIR\Docs\*.*"
Delete "$INSTDIR\uninst.exe"
Delete "$SMPROGRAMS\ADCH++\Uninstall.lnk"
Delete "$SMPROGRAMS\ADCH++\ADCH++.lnk"
Delete "$SMPROGRAMS\ADCH++\Website.lnk"
Delete "$SMPROGRAMS\ADCH++\ADCH++ Help.lnk"
Delete "$SMPROGRAMS\ADCH++\Remove ADCH++ windows service.lnk"
Delete "$SMPROGRAMS\ADCH++\Install ADCH++ as windows service.lnk"
Delete "$DESKTOP\ADCH++.lnk"
RMDir "$SMPROGRAMS\ADCH++"
RMDir "$INSTDIR\lua\socket"
RMDir "$INSTDIR\lua"
RMDir "$INSTDIR\mime"
RMDir "$INSTDIR\socket"
RMDir "$INSTDIR\Scripts\FL_Database"
RMDir "$INSTDIR\Scripts"
RMDir "$INSTDIR\config\logs"
RMDir "$INSTDIR\config"
RMDir "$INSTDIR\Docs\images\icons"
RMDir "$INSTDIR\Docs\images"
RMDir "$INSTDIR\Docs"
RMDir "$INSTDIR"
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
SetAutoClose true
SectionEnd

1312
src/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

345
src/License.txt Normal file
View File

@ -0,0 +1,345 @@
adchpp
Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
Here follows the full text of the GPL-2:
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.

285
src/SConstruct Normal file
View File

@ -0,0 +1,285 @@
# vim: set filetype: py
EnsureSConsVersion(1, 2)
import os,sys
from build_util import Dev
gcc_flags = {
'common': ['-g', '-Wall', '-Wextra', '-Wno-unused-parameter', '-Wno-unused-value', '-Wno-missing-field-initializers', '-Wno-address', '-Wno-unknown-pragmas', '-fexceptions'],
'debug': [],
'release' : ['-O3', '-fno-ipa-cp-clone']
}
gcc_xxflags = {
'common' : ['-std=gnu++0x'],
'debug' : [],
'release' : []
}
msvc_flags = {
# 4100: unreferenced formal parameter
# 4121: alignment of member sensitive to packing
# 4127: conditional expression is constant
# 4189: var init'd, unused
# 4244: possible loss of data on conversion
# 4290: exception spec ignored
# 4355: "this" used in a constructor
# 4510: no default constructor
# 4512: assn not generated
# 4610: no default constructor
# 4706: assignment within conditional expression
# 4800: converting from BOOL to bool
# 4996: fn unsafe, use fn_s
'common' : ['/W4', '/EHsc', '/Zi', '/Zm200', '/GR', '/FC', '/wd4100', '/wd4121', '/wd4127', '/wd4189', '/wd4244', '/wd4290', '/wd4355', '/wd4510', '/wd4512', '/wd4610', '/wd4706', '/wd4800', '/wd4996'],
'debug' : ['/MDd', '/LDd'],
'release' : ['/O2', '/MD', '/LD']
}
# we set /LD(d) by default for all sub-projects, since most of them are DLLs. don't forget to
# remove it when building executables!
msvc_xxflags = {
'common' : [],
'debug' : [],
'release' : []
}
gcc_link_flags = {
'common' : ['-g', '$UNDEF', '-time'],
'debug' : [],
'release' : ['-O3']
}
msvc_link_flags = {
'common' : ['/DEBUG', '/FIXED:NO', '/INCREMENTAL:NO'],
'debug' : [],
'release' : []
}
msvc_defs = {
'common' : ['_REENTRANT'],
'debug' : ['_DEBUG', '_HAS_ITERATOR_DEBUGGING=0', '_SECURE_SCL=0'],
'release' : ['NDEBUG']
}
gcc_defs = {
# _BSD_SOURCE is for some int types in LuaSocket on Linux.
'common' : ['_REENTRANT', '_BSD_SOURCE'],
'debug' : ['_DEBUG'],
'release' : ['NDEBUG']
}
# --- cut ---
import os,sys,distutils.sysconfig
plugins = filter(lambda x: os.path.isfile(os.path.join('plugins', x, 'SConscript')), os.listdir('plugins'))
langs = ['lua', 'python', 'ruby']
defEnv = Environment(ENV = os.environ)
opts = Variables('custom.py', ARGUMENTS)
if sys.platform == 'win32':
tooldef = 'mingw'
else:
tooldef = 'default'
opts.AddVariables(
EnumVariable('tools', 'Toolset to compile with, default = platform default (msvc under windows)', tooldef, ['mingw', 'default', 'clang', 'clang-analyzer']),
EnumVariable('mode', 'Compile mode', 'debug', ['debug', 'release']),
ListVariable('plugins', 'The plugins to compile', 'all', plugins),
ListVariable('langs', 'The language bindings to compile', 'all', langs),
BoolVariable('secure', 'Add support for secure TLS connections via OpenSSL', 'yes'),
BoolVariable('gch', 'Use GCH when compiling GUI (disable if you have linking problems with mingw)', 'yes'),
BoolVariable('verbose', 'Show verbose command lines', 'no'),
BoolVariable('savetemps', 'Save intermediate compilation files (assembly output)', 'no'),
('prefix', 'Prefix to use when cross compiling', ''),
EnumVariable('arch', 'Target architecture', 'x86', ['x86', 'x64', 'ia64']),
('python', 'Python path to use when compiling python extensions', distutils.sysconfig.get_config_var('prefix')),
('ruby', 'Path to the ruby binary', 'ruby'),
('lua', 'Path to the lua binary', 'lua'),
BoolVariable('systemlua', 'Try to use the system lua libraries', 'no'),
BoolVariable('systemboost', 'Use the system boost libraries', 'no'),
BoolVariable('docs', 'Build docs (requires asciidoc)', 'no')
)
opts.Update(defEnv)
Help(opts.GenerateHelpText(defEnv))
# workaround for SCons 1.2 which hard-codes possible archs (only allows 'x86' and 'amd64'...)
# TODO remove when SCons knows about all available archs
TARGET_ARCH = defEnv['arch']
if TARGET_ARCH == 'x64':
TARGET_ARCH = 'amd64'
env = Environment(ENV = os.environ, tools = [defEnv['tools'], 'swig'], toolpath = ['tools'], options = opts, TARGET_ARCH = TARGET_ARCH, MSVS_ARCH = TARGET_ARCH)
# filter out boost from dependencies to get a speedier rebuild scan
# this means that if boost changes, scons -c needs to be run
# delete .sconsign.dblite to see the effects of this if you're upgrading
def filterBoost(x):
return [y for y in x if str(y).find('boost') == -1]
SourceFileScanner.function['.c'].recurse_nodes = filterBoost
SourceFileScanner.function['.cpp'].recurse_nodes = filterBoost
SourceFileScanner.function['.h'].recurse_nodes = filterBoost
SourceFileScanner.function['.hpp'].recurse_nodes = filterBoost
dev = Dev(env)
dev.prepare()
env.SConsignFile()
conf = Configure(env, conf_dir = dev.get_build_path('.sconf_temp'), log_file = dev.get_build_path('config.log'), clean = False, help = False, custom_tests = { 'CheckBoost' : dev.CheckBoost })
if dev.env['systemboost']:
sysBoostLibs = []
def checkBoostLib_(lib, header, call):
if conf.CheckLibWithHeader(lib, header, 'C++', call, 0):
sysBoostLibs.append(lib)
return True
return False
def checkBoostLib(lib, header, call): return (checkBoostLib_(lib, header, call) or
checkBoostLib_(lib + '-mt', header, call)) # Cygwin boost libs are named that way
if (not conf.CheckBoost('1.49.0') or
not checkBoostLib('libboost_system', 'boost/system/error_code.hpp', 'boost::system::error_code ec;') or
not checkBoostLib('libboost_date_time', 'boost/date_time/posix_time/posix_time.hpp', 'boost::posix_time::microsec_clock::local_time();') or
not checkBoostLib('libboost_locale', 'boost/locale.hpp', 'boost::locale::generator().generate("");')):
raise Exception('Cannot use system boost libraries - try with systemboost=0')
if not dev.env['systemboost']:
env.Append(CPPPATH = ['#/boost/'])
env.Append(CPPDEFINES = ['BOOST_ALL_DYN_LINK=1'])
if env['CC'] == 'cl': # MSVC
env.Append(CPPDEFINES = ['BOOST_ALL_NO_LIB=1'])
if not dev.is_win32():
env.Append(CPPDEFINES = ['_XOPEN_SOURCE=500'] )
env.Append(CCFLAGS=['-fvisibility=hidden'])
env.Append(LIBS = ['stdc++', 'm'])
if 'gcc' in env['TOOLS']:
if dev.is_win32():
env.Append(LINKFLAGS = ['-Wl,--enable-auto-import'])
if env['savetemps']:
env.Append(CCFLAGS = ['-save-temps', '-fverbose-asm'])
else:
env.Append(CCFLAGS = ['-pipe'])
# require i686 instructions for atomic<int64_t>, used by boost::lockfree (otherwise lockfree
# lists won't actually be lock-free).
if env['arch'] == 'x86':
env.Append(CCFLAGS = ['-march=i686'])
if env['CC'] == 'cl': # MSVC
flags = msvc_flags
xxflags = msvc_xxflags
link_flags = msvc_link_flags
defs = msvc_defs
if env['arch'] == 'x86':
env.Append(CPPDEFINES = ['_USE_32BIT_TIME_T=1']) # for compatibility with PHP
else:
flags = gcc_flags
xxflags = gcc_xxflags
link_flags = gcc_link_flags
defs = gcc_defs
env.Tool("gch", toolpath=".")
env.Append(CPPDEFINES = defs[env['mode']])
env.Append(CPPDEFINES = defs['common'])
env.Append(CCFLAGS = flags[env['mode']])
env.Append(CCFLAGS = flags['common'])
env.Append(CXXFLAGS = xxflags[env['mode']])
env.Append(CXXFLAGS = xxflags['common'])
env.Append(LINKFLAGS = link_flags[env['mode']])
env.Append(LINKFLAGS = link_flags['common'])
env.Append(UNDEF = '-Wl,--no-undefined')
if dev.is_win32():
env.Append(LIBS = ['ws2_32', 'mswsock'])
env.SourceCode('.', None)
import SCons.Scanner
SWIGScanner = SCons.Scanner.ClassicCPP(
"SWIGScan",
".i",
"CPPPATH",
'^[ \t]*[%,#][ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")'
)
env.Append(SCANNERS=[SWIGScanner])
if not env.GetOption('clean') and not env.GetOption("help"):
if not dev.is_win32():
if conf.CheckCHeader('poll.h'):
conf.env.Append(CPPDEFINES='HAVE_POLL_H')
if conf.CheckCHeader('sys/epoll.h'):
conf.env.Append(CPPDEFINES=['HAVE_SYS_EPOLL_H'])
if conf.CheckLib('pthread', 'pthread_create'):
conf.env.Append(CPPDEFINES=['HAVE_PTHREAD'])
if env['secure'] and conf.CheckLib('ssl', 'SSL_connect'):
conf.env.Append(CPPDEFINES=['HAVE_OPENSSL'])
if conf.CheckLib('dl', 'dlopen'):
conf.env.Append(CPPDEFINES=['HAVE_DL'])
else:
if env['secure'] and os.path.exists(Dir('#/openssl/include').abspath):
conf.env.Append(CPPDEFINES=['HAVE_OPENSSL'])
env = conf.Finish()
env.Append(LIBPATH = env.Dir(dev.get_build_root() + 'bin/').abspath)
if not dev.is_win32():
dev.env.Append(RPATH = env.Literal('\\$$ORIGIN'))
if dev.env['systemboost']:
env.Append(LIBS = sysBoostLibs)
else:
dev.boost_system = dev.build('boost/libs/system/src/')
dev.boost_date_time = dev.build('boost/libs/date_time/src/')
dev.boost_locale = dev.build('boost/libs/locale/src/')
env.Append(LIBS = ['aboost_system', 'aboost_date_time', 'aboost_locale'])
dev.adchpp = dev.build('adchpp/')
dev.build('adchppd/')
# Lua for plugins & swig
if 'Script' in env['plugins'] or 'lua' in env['langs']:
dev.build('lua/')
# Library wrappers
dev.build('swig/')
# Plugins
for plugin in env['plugins']:
dev.build('plugins/' + plugin + '/')
if env['docs']:
asciidoc_cmd = dev.get_asciidoc()
if asciidoc_cmd is None:
print 'asciidoc not found, docs won\'t be built'
else:
env['asciidoc_cmd'] = asciidoc_cmd
def asciidoc(target, source, env):
env.Execute(env['asciidoc_cmd'] + ' -o"' + str(target[0]) + '" "' + str(source[0]) + '"')
doc_path = '#/build/docs/'
env.Command(doc_path + 'readme.html', '#/readme.txt', asciidoc)
guide_path = '#/docs/user_guide/'
env.Command(doc_path + 'user_guide/basic_guide.html', guide_path + 'basic_guide.txt', asciidoc)
env.Command(doc_path + 'user_guide/expert_guide.html', guide_path + 'expert_guide.txt', asciidoc)
env.Command(doc_path + 'user_guide/images', guide_path + 'images', Copy('$TARGET', '$SOURCE'))

263
src/adchpp/AdcCommand.cpp Normal file
View File

@ -0,0 +1,263 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "AdcCommand.h"
#include "Text.h"
namespace adchpp {
#ifdef __GNUC__ /// @todo go figure why some GCCs need these...
const char AdcCommand::TYPE_BROADCAST;
const char AdcCommand::TYPE_CLIENT;
const char AdcCommand::TYPE_DIRECT;
const char AdcCommand::TYPE_ECHO;
const char AdcCommand::TYPE_FEATURE;
const char AdcCommand::TYPE_INFO;
const char AdcCommand::TYPE_HUB;
const char AdcCommand::TYPE_UDP;
#endif
using namespace std;
AdcCommand::AdcCommand() : cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(TYPE_INFO) { }
AdcCommand::AdcCommand(Severity sev, Error err, const string& desc, char aType /* = TYPE_INFO */) : cmdInt(CMD_STA), priority(PRIORITY_NORMAL), from(HUB_SID), to(INVALID_SID), type(aType) {
addParam(Util::toString(sev * 100 + err));
addParam(desc);
}
void AdcCommand::escape(const string& s, string& out) {
out.reserve(out.length() + static_cast<size_t>(s.length() * 1.1));
for(string::const_iterator i = s.begin(), iend = s.end(); i != iend; ++i) {
switch(*i) {
case ' ': out += '\\'; out += 's'; break;
case '\n': out += '\\'; out += 'n'; break;
case '\\': out += '\\'; out += '\\'; break;
default: out += *i;
}
}
}
void AdcCommand::parse(const char* buf, size_t len) throw(ParseException) {
if(len < 5) {
throw ParseException("Command too short");
}
type = buf[0];
if(type != TYPE_BROADCAST && type != TYPE_CLIENT && type != TYPE_DIRECT && type != TYPE_ECHO && type != TYPE_FEATURE && type != TYPE_INFO && type != TYPE_HUB && type != TYPE_UDP) {
throw ParseException("Invalid type");
}
if(type == TYPE_HUB) {
to = HUB_SID;
}
cmd[0] = buf[1];
cmd[1] = buf[2];
cmd[2] = buf[3];
if(buf[4] != ' ') {
throw ParseException("Missing space after command");
}
// Skip trailing LF
len--;
parameters.reserve(8);
string cur;
cur.reserve(64);
bool toSet = false;
bool featureSet = false;
bool fromSet = false;
string::size_type i = 5;
while(i < len) {
switch(buf[i]) {
case '\\':
++i;
if(i == len)
throw ParseException("Escape at eol");
if(buf[i] == 's')
cur += ' ';
else if(buf[i] == 'n')
cur += '\n';
else if(buf[i] == '\\')
cur += '\\';
else
throw ParseException("Unknown escape");
break;
case ' ':
// New parameter...
{
if((type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) && !fromSet) {
if(cur.length() != 4) {
throw ParseException("Invalid SID length");
}
from = toSID(cur);
fromSet = true;
} else if((type == TYPE_DIRECT || type == TYPE_ECHO) && !toSet) {
if(cur.length() != 4) {
throw ParseException("Invalid SID length");
}
to = toSID(cur);
toSet = true;
} else if(type == TYPE_FEATURE && !featureSet) {
if(cur.length() % 5 != 0) {
throw ParseException("Invalid feature length");
}
features = cur;
featureSet = true;
} else {
if(!Text::validateUtf8(cur)) {
throw ParseException("Invalid UTF-8 sequence");
}
parameters.push_back(cur);
}
cur.clear();
}
break;
default:
cur += buf[i];
}
++i;
}
if(!cur.empty()) {
if((type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) && !fromSet) {
if(cur.length() != 4) {
throw ParseException("Invalid SID length");
}
from = toSID(cur);
fromSet = true;
} else if((type == TYPE_DIRECT || type == TYPE_ECHO) && !toSet) {
if(cur.length() != 4) {
throw ParseException("Invalid SID length");
}
to = toSID(cur);
toSet = true;
} else if(type == TYPE_FEATURE && !featureSet) {
if(cur.length() % 5 != 0) {
throw ParseException("Invalid feature length");
}
features = cur;
featureSet = true;
} else {
if(!Text::validateUtf8(cur)) {
throw ParseException("Invalid UTF-8 sequence");
}
parameters.push_back(cur);
}
}
if((type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) && !fromSet) {
throw ParseException("Missing from_sid");
}
if(type == TYPE_FEATURE && !featureSet) {
throw ParseException("Missing feature");
}
if((type == TYPE_DIRECT || type == TYPE_ECHO) && !toSet) {
throw ParseException("Missing to_sid");
}
}
const BufferPtr& AdcCommand::getBuffer() const {
if(!buffer) {
buffer = make_shared<Buffer>(toString());
}
return buffer;
}
string AdcCommand::toString() const {
if(buffer) {
return string((char*)buffer->data(), buffer->size());
}
string tmp;
tmp.reserve(128);
tmp += type;
tmp += cmdChar;
if(type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) {
tmp += ' ';
appendSID(tmp, from);
}
if(type == TYPE_DIRECT || type == TYPE_ECHO) {
tmp += ' ';
appendSID(tmp, to);
}
if(type == TYPE_FEATURE) {
tmp += ' ';
tmp += features;
}
for(StringIterC i = getParameters().begin(); i != getParameters().end(); ++i) {
tmp += ' ';
escape(*i, tmp);
}
tmp += '\n';
return tmp;
}
bool AdcCommand::getParam(const char* name, size_t start, string& ret) const {
for(string::size_type i = start; i < getParameters().size(); ++i) {
if(toField(name) == toField(getParameters()[i].c_str())) {
ret = getParameters()[i].substr(2);
return true;
}
}
return false;
}
bool AdcCommand::delParam(const char* name, size_t start) {
for(string::size_type i = start; i < getParameters().size(); ++i) {
if(toField(name) == toField(getParameters()[i].c_str())) {
getParameters().erase(getParameters().begin() + i);
resetBuffer();
return true;
}
}
return false;
}
bool AdcCommand::hasFlag(const char* name, size_t start) const {
for(string::size_type i = start; i < getParameters().size(); ++i) {
if(toField(name) == toField(getParameters()[i].c_str()) &&
getParameters()[i].size() == 3 &&
getParameters()[i][2] == '1')
{
return true;
}
}
return false;
}
}

238
src/adchpp/AdcCommand.h Normal file
View File

@ -0,0 +1,238 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_ADC_COMMAND_H
#define ADCHPP_ADC_COMMAND_H
#include "common.h"
#include "Exception.h"
#include "Util.h"
#include "Buffer.h"
namespace adchpp {
STANDARD_EXCEPTION(ParseException);
class AdcCommand : private boost::noncopyable {
public:
template<uint32_t T>
struct Type {
enum { CMD = T };
};
enum Error {
ERROR_GENERIC = 0,
ERROR_HUB_GENERIC = 10,
ERROR_HUB_FULL = 11,
ERROR_HUB_DISABLED = 12,
ERROR_LOGIN_GENERIC = 20,
ERROR_NICK_INVALID = 21,
ERROR_NICK_TAKEN = 22,
ERROR_BAD_PASSWORD = 23,
ERROR_CID_TAKEN = 24,
ERROR_COMMAND_ACCESS = 25,
ERROR_REGGED_ONLY = 26,
ERROR_INVALID_PID = 27,
ERROR_BANNED_GENERIC = 30,
ERROR_PERM_BANNED = 31,
ERROR_TEMP_BANNED = 32,
ERROR_PROTOCOL_GENERIC = 40,
ERROR_PROTOCOL_UNSUPPORTED = 41,
ERROR_CONNECT_FAILED = 42,
ERROR_INF_MISSING = 43,
ERROR_BAD_STATE = 44,
ERROR_FEATURE_MISSING = 45,
ERROR_BAD_IP = 46,
ERROR_NO_HUB_HASH = 47,
ERROR_TRANSFER_GENERIC = 50,
ERROR_FILE_NOT_AVAILABLE = 51,
ERROR_FILE_PART_NOT_AVAILABLE = 52,
ERROR_SLOTS_FULL = 53,
ERROR_NO_CLIENT_HASH = 54
};
enum Severity {
SEV_SUCCESS = 0,
SEV_RECOVERABLE = 1,
SEV_FATAL = 2
};
enum Priority {
PRIORITY_NORMAL, ///< Default priority, command will be sent out normally
PRIORITY_LOW, ///< Low priority, command will only be sent if connection isn't saturated
PRIORITY_IGNORE ///< Ignore, command will not be put in send queue
};
static const char TYPE_BROADCAST = 'B';
static const char TYPE_CLIENT = 'C';
static const char TYPE_DIRECT = 'D';
static const char TYPE_ECHO = 'E';
static const char TYPE_FEATURE = 'F';
static const char TYPE_INFO = 'I';
static const char TYPE_HUB = 'H';
static const char TYPE_UDP = 'U';
// Known commands...
#define C(n, a, b, c) static const uint32_t CMD_##n = (((uint32_t)a) | (((uint32_t)b)<<8) | (((uint32_t)c)<<16)); typedef Type<CMD_##n> n
// Base commands
C(SUP, 'S','U','P');
C(STA, 'S','T','A');
C(INF, 'I','N','F');
C(MSG, 'M','S','G');
C(SCH, 'S','C','H');
C(RES, 'R','E','S');
C(CTM, 'C','T','M');
C(RCM, 'R','C','M');
C(GPA, 'G','P','A');
C(PAS, 'P','A','S');
C(QUI, 'Q','U','I');
C(GET, 'G','E','T');
C(GFI, 'G','F','I');
C(SND, 'S','N','D');
C(SID, 'S','I','D');
// Extensions
C(CMD, 'C','M','D');
C(NAT, 'N','A','T');
C(RNT, 'R','N','T');
#undef C
static const uint32_t HUB_SID = static_cast<uint32_t>(-1);
static const uint32_t INVALID_SID = static_cast<uint32_t>(-2);
static uint32_t toSID(const std::string& aSID) { return *reinterpret_cast<const uint32_t*>(aSID.data()); }
static std::string fromSID(const uint32_t aSID) { return std::string(reinterpret_cast<const char*>(&aSID), sizeof(aSID)); }
static void appendSID(std::string& str, uint32_t aSID) { str.append(reinterpret_cast<const char*>(&aSID), sizeof(aSID)); }
static uint32_t toCMD(uint8_t a, uint8_t b, uint8_t c) { return (((uint32_t)a) | (((uint32_t)b)<<8) | (((uint32_t)c)<<16)); }
static uint32_t toCMD(const char* str) { return toCMD(str[0], str[1], str[2]); }
static uint16_t toField(const char* x) { return *((uint16_t*)x); }
static std::string fromField(const uint16_t aField) { return std::string(reinterpret_cast<const char*>(&aField), sizeof(aField)); }
static uint32_t toFourCC(const char* x) { return *reinterpret_cast<const uint32_t*>(x); }
static std::string fromFourCC(uint32_t x) { return std::string(reinterpret_cast<const char*>(&x), sizeof(x)); }
ADCHPP_DLL AdcCommand();
ADCHPP_DLL explicit AdcCommand(Severity sev, Error err, const std::string& desc, char aType = TYPE_INFO);
explicit AdcCommand(uint32_t cmd, char aType = TYPE_INFO, uint32_t aFrom = HUB_SID) : cmdInt(cmd), priority(PRIORITY_NORMAL), from(aFrom), to(INVALID_SID), type(aType) { }
explicit AdcCommand(const std::string& aLine) throw(ParseException) : cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(0) { parse(aLine); }
explicit AdcCommand(const BufferPtr& buffer_) throw(ParseException) : buffer(buffer_), cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(0) { parse((const char*)buffer->data(), buffer->size()); }
void parse(const std::string& str) throw(ParseException) { parse(str.data(), str.size()); }
ADCHPP_DLL void parse(const char* buf, size_t len) throw(ParseException);
uint32_t getCommand() const { return cmdInt; }
char getType() const { return type; }
std::string getFourCC() const { std::string tmp(4, 0); tmp[0] = type; tmp[1] = cmd[0]; tmp[2] = cmd[1]; tmp[3] = cmd[2]; return tmp; }
StringList& getParameters() { return parameters; }
const StringList& getParameters() const { return parameters; }
ADCHPP_DLL std::string toString() const;
AdcCommand& addParam(const std::string& param) {
parameters.push_back(param);
resetBuffer();
return *this;
}
AdcCommand& addParam(const std::string& name, const std::string& value) {
return addParam(name + value);
}
const std::string& getParam(size_t n) const {
return getParameters().size() > n ? getParameters()[n] : Util::emptyString;
}
void resetBuffer() { buffer.reset(); }
const std::string& getFeatures() const { return features; }
/** Return a named parameter where the name is a two-letter code */
ADCHPP_DLL bool getParam(const char* name, size_t start, std::string& ret) const;
ADCHPP_DLL bool delParam(const char* name, size_t start);
ADCHPP_DLL bool hasFlag(const char* name, size_t start) const;
bool operator==(uint32_t aCmd) const { return cmdInt == aCmd; }
ADCHPP_DLL static void escape(const std::string& s, std::string& out);
ADCHPP_DLL const BufferPtr& getBuffer() const;
uint32_t getTo() const { return to; }
void setTo(uint32_t aTo) { to = aTo; }
uint32_t getFrom() const { return from; }
void setFrom(uint32_t aFrom) { from = aFrom; }
Priority getPriority() const { return priority; }
void setPriority(Priority priority_) { priority = priority_; }
private:
StringList parameters;
std::string features;
mutable BufferPtr buffer;
union {
char cmdChar[4];
uint8_t cmd[4];
uint32_t cmdInt;
};
Priority priority;
uint32_t from;
uint32_t to;
char type;
};
class Client;
class Entity;
template<class T>
class CommandHandler {
public:
bool dispatch(Entity& c, AdcCommand& cmd) {
#define C(n) case AdcCommand::CMD_##n: return ((T*)this)->handle(AdcCommand::n(), c, cmd); break;
switch(cmd.getCommand()) {
C(SUP);
C(STA);
C(INF);
C(MSG);
C(SCH);
C(RES);
C(CTM);
C(RCM);
C(GPA);
C(PAS);
C(QUI);
C(GET);
C(GFI);
C(SND);
C(SID);
C(CMD);
C(NAT);
C(RNT);
default:
dcdebug("Unknown ADC command: %.50s\n", cmd.toString().c_str());
return true;
#undef C
}
}
};
}
#endif // ADC_COMMAND_H

43
src/adchpp/AsyncStream.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include <boost/system/error_code.hpp>
#include "Buffer.h"
namespace adchpp {
class AsyncStream : private boost::noncopyable {
public:
typedef std::function<void (const boost::system::error_code& ec, size_t)> Handler;
virtual size_t available() = 0;
virtual void init(const std::function<void ()>& postInit) = 0;
virtual void setOptions(size_t bufferSize) = 0;
virtual std::string getIp() = 0;
virtual void prepareRead(const BufferPtr& buf, const Handler& handler) = 0;
virtual size_t read(const BufferPtr& buf) = 0;
virtual void write(const BufferList& bufs, const Handler& handler) = 0;
virtual void shutdown(const Handler& handler) = 0;
virtual void close() = 0;
virtual ~AsyncStream() { }
};
typedef shared_ptr<AsyncStream> AsyncStreamPtr;
}

63
src/adchpp/Bot.cpp Normal file
View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "Bot.h"
#include "ClientManager.h"
#include "SocketManager.h"
#include "Core.h"
namespace adchpp {
// TODO replace with lambda
struct BotRemover {
BotRemover(Bot* bot_,Util::Reason reason, const std::string &info) : bot(bot_), reason(reason), info(info) { }
void operator()() {
bot->die(reason, info);
}
Bot* bot;
Util::Reason reason;
std::string info;
};
Bot::Bot(ClientManager &cm, uint32_t sid, const Bot::SendHandler& handler_) : Entity(cm, sid), handler(handler_), disconnecting(false) {
setFlag(FLAG_BOT);
// Fake a CID, the script can change this if it wants to
setCID(CID::generate());
}
void Bot::disconnect(Util::Reason reason, const std::string &info) throw() {
if(!disconnecting) {
disconnecting = true;
handler = SendHandler();
cm.getCore().addJob(BotRemover(this, reason, info));
}
}
void Bot::die(Util::Reason reason, const std::string &info) {
cm.removeEntity(*this, reason, info);
delete this;
}
}

52
src/adchpp/Bot.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef BOT_H_
#define BOT_H_
#include "forward.h"
#include "Entity.h"
namespace adchpp {
struct BotRemover;
class ADCHPP_VISIBLE Bot : public Entity {
public:
typedef std::function<void (Bot& bot, const BufferPtr& cmd)> SendHandler;
ADCHPP_DLL Bot(ClientManager &cm, uint32_t sid, const SendHandler& handler_);
virtual void send(const BufferPtr& cmd) { if(handler) handler(*this, cmd); }
ADCHPP_DLL virtual void disconnect(Util::Reason reason, const std::string &info) throw();
using Entity::send;
private:
friend struct BotRemover;
SendHandler handler;
bool disconnecting;
void die(Util::Reason reason, const std::string &info);
};
}
#endif /* BOT_H_ */

37
src/adchpp/Buffer.cpp Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "Buffer.h"
namespace adchpp {
size_t Buffer::defaultBufferSize = 128;
SimplePool<ByteVector, Buffer::Clear> Buffer::pool;
void Buffer::Clear::operator()(ByteVector& v) {
if(v.capacity() > static_cast<size_t>(getDefaultBufferSize())) {
ByteVector().swap(v);
} else {
v.clear();
}
}
}

77
src/adchpp/Buffer.h Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef BUFFER_H_
#define BUFFER_H_
#include "Pool.h"
#include "FastAlloc.h"
namespace adchpp {
/**
* Reference-counted buffer
*/
class Buffer :
public FastAlloc<Buffer>,
private boost::noncopyable
{
public:
Buffer(const std::string& str) : bufp(pool.get()) { append((uint8_t*)str.data(), (uint8_t*)str.data() + str.size()); }
Buffer(const void* ptr, const size_t size) : bufp(pool.get()) { append((uint8_t*) ptr, ((uint8_t*)ptr)+size); }
Buffer(const size_t size) : bufp(pool.get()) { resize(size); }
operator const ByteVector&() const { return buf(); }
operator ByteVector&() { return buf(); }
void resize(size_t new_size) { buf().resize(new_size); }
size_t size() const { return buf().size(); }
const uint8_t* data() const { return &buf()[0]; }
uint8_t* data() { return &buf()[0]; }
/** Erase the first n bytes */
void erase_first(size_t n) { buf().erase(buf().begin(), buf().begin() + n); }
template<typename InputIterator>
void append(InputIterator start, InputIterator end) { buf().insert(buf().end(), start, end); }
static void setDefaultBufferSize(size_t newSize) { defaultBufferSize = newSize; }
static size_t getDefaultBufferSize() { return defaultBufferSize; }
virtual ~Buffer() { pool.put(bufp); }
private:
static size_t defaultBufferSize;
const ByteVector& buf() const { return *bufp; }
ByteVector& buf() { return *bufp; }
ByteVector* bufp;
struct Clear {
ADCHPP_DLL void operator()(ByteVector& x);
};
ADCHPP_DLL static SimplePool<ByteVector, Clear> pool;
};
typedef shared_ptr<Buffer> BufferPtr;
typedef std::vector<BufferPtr> BufferList;
}
#endif /*BUFFER_H_*/

76
src/adchpp/CID.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_CID_H
#define ADCHPP_CID_H
#include "Util.h"
#include "Encoder.h"
namespace adchpp {
class CID {
public:
enum { SIZE = 192 / 8 };
enum { BASE32_SIZE = 39 };
CID() { memset(cid, 0, sizeof(cid)); }
explicit CID(const uint8_t* data) { memcpy(cid, data, sizeof(cid)); }
explicit CID(const std::string& base32) { Encoder::fromBase32(base32.c_str(), cid, sizeof(cid)); }
CID(const CID& rhs) { memcpy(cid, rhs.cid, sizeof(cid)); }
CID& operator=(const CID& rhs) { memcpy(cid, rhs.cid, sizeof(cid)); return *this; }
bool operator==(const CID& rhs) const { return memcmp(cid, rhs.cid, sizeof(cid)) == 0; }
bool operator<(const CID& rhs) const { return memcmp(cid, rhs.cid, sizeof(cid)) < 0; }
std::string toBase32() const { return Encoder::toBase32(cid, sizeof(cid)); }
std::string& toBase32(std::string& tmp) const { return Encoder::toBase32(cid, sizeof(cid), tmp); }
size_t toHash() const { static_assert(sizeof(cid) >= sizeof(cidHash), "cid too small, cidHash invalid"); return cidHash; }
const uint8_t* data() const { return cid; }
bool isZero() const { return std::find_if(cid, cid+SIZE, std::bind2nd(std::not_equal_to<uint8_t>(), 0)) == (cid+SIZE); }
static CID generate() {
uint8_t data[CID::SIZE];
for(size_t i = 0; i < sizeof(data); ++i) {
data[i] = (uint8_t)Util::rand();
}
return CID(data);
}
private:
union {
uint8_t cid[SIZE];
size_t cidHash;
};
};
}
namespace std {
template<>
struct hash<adchpp::CID> {
size_t operator()(const adchpp::CID& cid) const {
return cid.toHash();
}
};
}
#endif

174
src/adchpp/Client.cpp Normal file
View File

@ -0,0 +1,174 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "Client.h"
#include "ClientManager.h"
#include "TimeUtil.h"
#include "SocketManager.h"
#include "Core.h"
namespace adchpp {
using namespace std;
using namespace std::placeholders;
Client* Client::create(ClientManager &cm, const ManagedSocketPtr& ms, uint32_t sid) throw() {
Client* c = new Client(cm, sid);
c->setSocket(ms);
return c;
}
Client::Client(ClientManager &cm, uint32_t sid_) throw() :
Entity(cm, sid_),
disconnecting(false),
dataBytes(0)
{
}
Client::~Client() {
}
namespace {
// Lightweight call forwarders, instead of std::bind
template<void (Client::*F)()>
struct Handler0 {
Handler0(Client* c_) : c(c_) { }
void operator()() { (c->*F)(); }
Client* c;
};
template<typename T, void (Client::*F)(const T&)>
struct Handler1 {
Handler1(Client* c_) : c(c_) { }
void operator()(const T& bv) { (c->*F)(bv); }
Client* c;
};
template<typename T, typename T2, void (Client::*F)(T, const T2&)>
struct Handler2 {
Handler2(Client* c_) : c(c_) { }
void operator()(const T& t, const T2& t2) { (c->*F)(t, t2); }
Client* c;
};
}
void Client::setSocket(const ManagedSocketPtr& aSocket) throw() {
dcassert(!socket);
socket = aSocket;
socket->setConnectedHandler(Handler0<&Client::onConnected>(this));
socket->setReadyHandler(Handler0<&Client::onReady>(this));
socket->setDataHandler(Handler1<BufferPtr, &Client::onData>(this));
socket->setFailedHandler(Handler2<Util::Reason, std::string, &Client::onFailed>(this));
}
void Client::onConnected() throw() {
cm.onConnected(*this);
}
void Client::onReady() throw() {
cm.onReady(*this);
}
void Client::onData(const BufferPtr& buf) throw() {
uint8_t* data = buf->data();
size_t done = 0;
size_t len = buf->size();
while(!disconnecting && done < len) {
if(dataBytes > 0) {
size_t n = (size_t)min(dataBytes, (int64_t)(len - done));
dataHandler(*this, data + done, n);
dataBytes -= n;
done += n;
} else {
size_t j = done;
while(j < len && data[j] != '\n')
++j;
if(j == len) {
if(!buffer) {
if(done == 0) {
buffer = buf;
} else {
buffer = make_shared<Buffer>(data + done, len - done);
}
} else {
buffer->append(data + done, data + len);
}
return;
} else if(!buffer) {
if(done == 0 && j == len-1) {
buffer = buf;
} else {
buffer = make_shared<Buffer>(data + done, j - done + 1);
}
} else {
buffer->append(data + done, data + j + 1);
}
done = j + 1;
if(cm.getMaxCommandSize() > 0 && buffer->size() > cm.getMaxCommandSize()) {
send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC, "Command too long"));
disconnect(Util::REASON_MAX_COMMAND_SIZE);
return;
}
if(buffer->size() == 1) {
buffer.reset();
continue;
}
try {
AdcCommand cmd(buffer);
if(cmd.getType() == 'H') {
cmd.setFrom(getSID());
} else if(cmd.getFrom() != getSID()) {
disconnect(Util::REASON_INVALID_SID);
return;
}
cm.onReceive(*this, cmd);
} catch(const ParseException&) {
cm.onBadLine(*this, string((char*)buffer->data(), buffer->size()));
}
buffer.reset();
}
}
}
void Client::disconnect(Util::Reason reason, const std::string &info) throw() {
dcassert(socket);
if(!disconnecting) {
dcdebug("%s disconnecting because %d\n", AdcCommand::fromSID(getSID()).c_str(), reason);
disconnecting = true;
socket->disconnect(reason, info);
}
}
void Client::onFailed(Util::Reason reason, const std::string &info) throw() {
cm.onFailed(*this, reason, info);
delete this;
}
}

79
src/adchpp/Client.h Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_CLIENT_H
#define ADCHPP_CLIENT_H
#include "common.h"
#include "ManagedSocket.h"
#include "FastAlloc.h"
#include "AdcCommand.h"
#include "CID.h"
#include "Entity.h"
namespace adchpp {
/**
* The client represents one connection to a user.
*/
class ADCHPP_VISIBLE Client : public Entity, public FastAlloc<Client> {
public:
static Client* create(ClientManager &cm, const ManagedSocketPtr& ms_, uint32_t sid_) throw();
using Entity::send;
virtual void send(const BufferPtr& command) { socket->write(command); }
/** @param reason The statistic to update */
ADCHPP_DLL virtual void disconnect(Util::Reason reason, const std::string &info = Util::emptyString) throw();
const std::string& getIp() const throw() { return socket->getIp(); }
/**
* Set data mode for aBytes bytes.
* May only be called from on(ClientListener::Command...).
*/
typedef std::function<void (Client&, const uint8_t*, size_t)> DataFunction;
void setDataMode(const DataFunction& handler, int64_t aBytes) { dataHandler = handler; dataBytes = aBytes; }
virtual size_t getQueuedBytes() const { return socket->getQueuedBytes(); }
virtual time::ptime getOverflow() const { return socket->getOverflow(); }
private:
Client(ClientManager &cm, uint32_t sid_) throw();
virtual ~Client();
bool disconnecting;
BufferPtr buffer;
ManagedSocketPtr socket;
int64_t dataBytes;
DataFunction dataHandler;
void setSocket(const ManagedSocketPtr& aSocket) throw();
void onConnected() throw();
void onReady() throw();
void onData(const BufferPtr&) throw();
void onFailed(Util::Reason reason, const std::string &info) throw();
};
}
#endif // CLIENT_H

View File

@ -0,0 +1,647 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "ClientManager.h"
#include "File.h"
#include "Client.h"
#include "LogManager.h"
#include "SocketManager.h"
#include "TigerHash.h"
#include "Encoder.h"
#include "version.h"
#include <boost/asio/ip/address.hpp>
#include <boost/asio/ip/address_v4.hpp>
#include <boost/asio/ip/address_v6.hpp>
#include <boost/locale.hpp>
namespace adchpp {
using namespace std;
const string ClientManager::className = "ClientManager";
ClientManager::ClientManager(Core &core) throw() :
core(core),
hub(*this),
maxCommandSize(16 * 1024),
logTimeout(30 * 1000)
{
hub.addSupports(AdcCommand::toFourCC("BASE"));
hub.addSupports(AdcCommand::toFourCC("TIGR"));
}
Bot* ClientManager::createBot(const Bot::SendHandler& handler) {
Bot* ret = new Bot(*this, makeSID(), handler);
return ret;
}
void ClientManager::regBot(Bot& bot) {
enterIdentify(bot, false);
enterNormal(bot, false, true);
cids.insert(make_pair(bot.getCID(), &bot));
nicks.insert(make_pair(bot.getField("NI"), &bot));
}
void ClientManager::send(const AdcCommand& cmd) throw() {
if(cmd.getPriority() == AdcCommand::PRIORITY_IGNORE) {
return;
}
bool all = false;
switch(cmd.getType()) {
case AdcCommand::TYPE_BROADCAST:
all = true; // Fallthrough
case AdcCommand::TYPE_FEATURE: {
for(EntityIter i = entities.begin(); i != entities.end(); ++i) {
if(all || !i->second->isFiltered(cmd.getFeatures())) {
maybeSend(*i->second, cmd);
}
}
}
break;
case AdcCommand::TYPE_DIRECT: // Fallthrough
case AdcCommand::TYPE_ECHO: {
Entity* e = getEntity(cmd.getTo());
if(e) {
maybeSend(*e, cmd);
if(cmd.getType() == AdcCommand::TYPE_ECHO) {
e = getEntity(cmd.getFrom());
if(e) {
maybeSend(*e, cmd);
}
}
}
}
break;
}
}
void ClientManager::maybeSend(Entity& c, const AdcCommand& cmd) {
bool ok = true;
signalSend_(c, cmd, ok);
if(ok) {
c.send(cmd);
}
}
void ClientManager::sendToAll(const BufferPtr& buf) throw() {
for(EntityIter i = entities.begin(); i != entities.end(); ++i) {
i->second->send(buf);
}
}
size_t ClientManager::getQueuedBytes() throw() {
size_t total = 0;
for(EntityIter i = entities.begin(); i != entities.end(); ++i) {
total += i->second->getQueuedBytes();
}
return total;
}
void ClientManager::sendTo(const BufferPtr& buffer, uint32_t to) {
EntityIter i = entities.find(to);
if(i != entities.end()) {
i->second->send(buffer);
}
}
void ClientManager::handleIncoming(const ManagedSocketPtr& socket) throw() {
Client::create(*this, socket, makeSID());
}
uint32_t ClientManager::makeSID() {
while(true) {
union {
uint32_t sid;
char chars[4];
} sid;
sid.chars[0] = Encoder::base32Alphabet[Util::rand(sizeof(Encoder::base32Alphabet))];
sid.chars[1] = Encoder::base32Alphabet[Util::rand(sizeof(Encoder::base32Alphabet))];
sid.chars[2] = Encoder::base32Alphabet[Util::rand(sizeof(Encoder::base32Alphabet))];
sid.chars[3] = Encoder::base32Alphabet[Util::rand(sizeof(Encoder::base32Alphabet))];
if(sid.sid != 0 && entities.find(sid.sid) == entities.end()) {
return sid.sid;
}
}
}
void ClientManager::onConnected(Client& c) throw() {
dcdebug("%s connected\n", AdcCommand::fromSID(c.getSID()).c_str());
// First let's check if any clients have passed the login timeout...
auto timeout = time::now() - time::millisec(getLogTimeout());
while(!logins.empty() && (timeout > logins.front().second)) {
Client* cc = logins.front().first;
dcdebug("ClientManager: Login timeout in state %d\n", cc->getState());
cc->disconnect(Util::REASON_LOGIN_TIMEOUT);
logins.pop_front();
}
logins.push_back(make_pair(&c, time::now()));
signalConnected_(c);
}
void ClientManager::onReady(Client& c) throw() {
dcdebug("%s ready\n", AdcCommand::fromSID(c.getSID()).c_str());
signalReady_(c);
}
void ClientManager::onReceive(Entity& c, AdcCommand& cmd) throw() {
if(c.isSet(Entity::FLAG_GHOST)) {
return;
}
if(!(cmd.getType() == AdcCommand::TYPE_BROADCAST || cmd.getType() == AdcCommand::TYPE_DIRECT || cmd.getType()
== AdcCommand::TYPE_ECHO || cmd.getType() == AdcCommand::TYPE_FEATURE || cmd.getType() == AdcCommand::TYPE_HUB))
{
disconnect(c, Util::REASON_INVALID_COMMAND_TYPE, "Invalid command type");
return;
}
bool ok = true;
signalReceive_(c, cmd, ok);
if(ok) {
if(!dispatch(c, cmd)) {
return;
}
}
send(cmd);
}
void ClientManager::onBadLine(Client& c, const string& aLine) throw() {
if(c.isSet(Entity::FLAG_GHOST)) {
return;
}
signalBadLine_(c, aLine);
}
void ClientManager::badState(Entity& c, const AdcCommand& cmd) throw() {
disconnect(c, Util::REASON_BAD_STATE, "Invalid state for command", AdcCommand::ERROR_BAD_STATE, "FC" + cmd.getFourCC());
}
bool ClientManager::handleDefault(Entity& c, AdcCommand& cmd) throw() {
if(c.getState() != Entity::STATE_NORMAL) {
badState(c, cmd);
return false;
}
return true;
}
bool ClientManager::handle(AdcCommand::SUP, Entity& c, AdcCommand& cmd) throw() {
if(!verifySUP(c, cmd)) {
return false;
}
if(c.getState() == Entity::STATE_PROTOCOL) {
enterIdentify(c, true);
} else if(c.getState() != Entity::STATE_NORMAL) {
badState(c, cmd);
return false;
}
return true;
}
bool ClientManager::verifySUP(Entity& c, AdcCommand& cmd) throw() {
c.updateSupports(cmd);
if(!c.hasSupport(AdcCommand::toFourCC("BASE"))) {
disconnect(c, Util::REASON_NO_BASE_SUPPORT, "This hub requires BASE support");
return false;
}
if(!c.hasSupport(AdcCommand::toFourCC("TIGR"))) {
disconnect(c, Util::REASON_NO_TIGR_SUPPORT, "This hub requires TIGR support");
return false;
}
return true;
}
bool ClientManager::verifyINF(Entity& c, AdcCommand& cmd) throw() {
Client* cc = dynamic_cast<Client*>(&c);
if(cc) {
if(!verifyIp(*cc, cmd))
return false;
}
if(!verifyCID(c, cmd))
return false;
if(!verifyNick(c, cmd))
return false;
if(cmd.getParam("DE", 0, strtmp)) {
if(!Util::validateCharset(strtmp, 32)) {
disconnect(c, Util::REASON_INVALID_DESCRIPTION, "Invalid character in description");
return false;
}
}
c.updateFields(cmd);
return true;
}
bool ClientManager::verifyPassword(Entity& c, const string& password, const ByteVector& salt,
const string& suppliedHash, TigerHash&& tiger) {
tiger.update(&password[0], password.size());
tiger.update(&salt[0], salt.size());
uint8_t tmp[TigerHash::BYTES];
Encoder::fromBase32(suppliedHash.c_str(), tmp, TigerHash::BYTES);
if(memcmp(tiger.finalize(), tmp, TigerHash::BYTES) == 0) {
return true;
}
return false;
}
bool ClientManager::verifyPassword(Entity& c, const string& password, const ByteVector& salt,
const string& suppliedHash) {
return verifyPassword(c, password, salt, suppliedHash, TigerHash());
}
bool ClientManager::verifyHashedPassword(Entity& c, const ByteVector& hashedPassword, int64_t hashedPasswordLen,
const ByteVector& salt, const string& suppliedHash) {
// hashedPassword must be in little-endian order; this code itself is endian-independent.
uint64_t initial_res[TigerHash::BYTES/8];
for (auto i = 0; i < 3; ++i) {
initial_res[i] = 0;
for (auto j = 0; j < 8; ++j)
initial_res[i] = initial_res[i] * 256 + hashedPassword[8*i+(7-j)];
}
return verifyPassword(c, "", salt, suppliedHash, TigerHash(hashedPasswordLen, initial_res));
}
bool ClientManager::verifyOverflow(Entity& c) {
size_t overflowing = 0;
for(EntityIter i = entities.begin(), iend = entities.end(); i != iend; ++i) {
if(!i->second->getOverflow().is_not_a_date_time()) {
overflowing++;
}
}
if(overflowing > 3 && overflowing > (entities.size() / 4)) {
disconnect(c, Util::REASON_NO_BANDWIDTH, "Not enough bandwidth available, please try again later", AdcCommand::ERROR_HUB_FULL);
return false;
}
return true;
}
bool ClientManager::handle(AdcCommand::INF, Entity& c, AdcCommand& cmd) throw() {
if(c.getState() != Entity::STATE_IDENTIFY && c.getState() != Entity::STATE_NORMAL) {
badState(c, cmd);
return false;
}
if(!verifyINF(c, cmd))
return false;
if(c.getState() == Entity::STATE_IDENTIFY) {
if(!verifyOverflow(c)) {
return false;
}
enterNormal(c, true, true);
return false;
}
return true;
}
bool ClientManager::verifyIp(Client& c, AdcCommand& cmd) throw() {
if(c.isSet(Entity::FLAG_OK_IP))
return true;
using namespace boost::asio::ip;
auto remote = address::from_string(c.getIp());
std::string ip;
if(remote.is_v4() || (remote.is_v6() && remote.to_v6().is_v4_mapped())) {
auto v4 = remote.is_v4() ? remote.to_v4() : remote.to_v6().to_v4();
if(cmd.getParam("I4", 0, ip)) {
dcdebug("%s verifying IP %s\n", AdcCommand::fromSID(c.getSID()).c_str(), ip.c_str());
if(ip.empty() || address_v4::from_string(ip) == address_v4::any()) {
cmd.delParam("I4", 0);
} else if(address_v4::from_string(ip) != v4 && !Util::isPrivateIp(c.getIp())) {
disconnect(c, Util::REASON_INVALID_IP, "Your IP is " + c.getIp() +
", reconfigure your client settings", AdcCommand::ERROR_BAD_IP, "IP" + c.getIp());
return false;
} else {
return true;
}
}
if(!c.hasField("I4")) {
c.setField("I4", v4.to_string());
}
if(c.getState() != Entity::STATE_NORMAL) {
cmd.addParam("I4", v4.to_string());
}
cmd.delParam("I6", 0); // We can't check this so we remove it instead...fix?
} else if(remote.is_v6()) {
if(cmd.getParam("I6", 0, ip)) {
dcdebug("%s verifying IPv6 %s\n", AdcCommand::fromSID(c.getSID()).c_str(), ip.c_str());
if(ip.empty() || address_v6::from_string(ip) == address_v6::any()) {
cmd.delParam("I6", 0);
} else if(address_v6::from_string(ip) != remote.to_v6() && !Util::isPrivateIp(c.getIp())) {
disconnect(c, Util::REASON_INVALID_IP, "Your IP is " + c.getIp() +
", reconfigure your client settings", AdcCommand::ERROR_BAD_IP, "IP" + c.getIp());
return false;
} else {
return true;
}
}
if(!c.hasField("I6")) {
c.setField("I6", c.getIp());
}
if(c.getState() != Entity::STATE_NORMAL) {
cmd.addParam("I6", c.getIp());
}
cmd.delParam("I4", 0); // We can't check this so we remove it instead...fix?
}
return true;
}
bool ClientManager::verifyCID(Entity& c, AdcCommand& cmd) throw() {
if(cmd.getParam("ID", 0, strtmp)) {
dcdebug("%s verifying CID %s\n", AdcCommand::fromSID(c.getSID()).c_str(), strtmp.c_str());
if(c.getState() != Entity::STATE_IDENTIFY) {
disconnect(c, Util::REASON_CID_CHANGE, "CID changes not allowed");
return false;
}
if(strtmp.size() != CID::BASE32_SIZE) {
disconnect(c, Util::REASON_PID_CID_LENGTH, "Invalid CID length");
return false;
}
CID cid(strtmp);
strtmp.clear();
if(!cmd.getParam("PD", 0, strtmp)) {
disconnect(c, Util::REASON_PID_MISSING, "PID missing", AdcCommand::ERROR_INF_MISSING, "FLPD");
return false;
}
if(strtmp.size() != CID::BASE32_SIZE) {
disconnect(c, Util::REASON_PID_CID_LENGTH, "Invalid PID length");
return false;
}
CID pid(strtmp);
TigerHash th;
th.update(pid.data(), CID::SIZE);
if(!(CID(th.finalize()) == cid)) {
disconnect(c, Util::REASON_PID_CID_MISMATCH, "PID does not correspond to CID", AdcCommand::ERROR_INVALID_PID);
return false;
}
auto other = cids.find(cid);
if(other != cids.end()) {
// disconnect the ghost
disconnect(*other->second, Util::REASON_CID_TAKEN, "CID taken", AdcCommand::ERROR_CID_TAKEN);
removeEntity(*other->second, Util::REASON_CID_TAKEN, Util::emptyString);
}
c.setCID(cid);
cids.insert(make_pair(c.getCID(), &c));
cmd.delParam("PD", 0);
}
if(cmd.getParam("PD", 0, strtmp)) {
disconnect(c, Util::REASON_PID_WITHOUT_CID, "CID required when sending PID");
return false;
}
return true;
}
namespace {
bool validateNickF(wchar_t c) { /// @todo lambda
// the following are explicitly allowed (isprint sometimes differs)
if(c >= L'\u2100' && c <= L'\u214F' /* letter-like symbols */) {
return false;
}
// the following are explicitly disallowed (isprint sometimes differs)
if(c == L'\u00AD' /* soft hyphen */) {
return true;
}
static std::locale loc = boost::locale::generator().generate("");
return !std::isprint(c, loc);
}
bool validateNick(const string& nick) {
if(!Util::validateCharset(nick, 33)) { // chars < 33 forbidden (including the space char)
return false;
}
// avoid impersonators
std::wstring nickW = boost::locale::conv::utf_to_utf<wchar_t>(nick);
if(std::find_if(nickW.begin(), nickW.end(), validateNickF) != nickW.end()) {
return false;
}
return true;
}
}
bool ClientManager::verifyNick(Entity& c, const AdcCommand& cmd) throw() {
if(cmd.getParam("NI", 0, strtmp)) {
dcdebug("%s verifying nick %s\n", AdcCommand::fromSID(c.getSID()).c_str(), strtmp.c_str());
if(!validateNick(strtmp)) {
disconnect(c, Util::REASON_NICK_INVALID, "Invalid character in nick", AdcCommand::ERROR_NICK_INVALID);
return false;
}
const string& oldNick = c.getField("NI");
if(!oldNick.empty())
nicks.erase(oldNick);
if(nicks.find(strtmp) != nicks.end()) {
disconnect(c, Util::REASON_NICK_TAKEN, "Nick taken, please pick another one", AdcCommand::ERROR_NICK_TAKEN);
return false;
}
nicks.insert(make_pair(strtmp, &c));
}
return true;
}
void ClientManager::setState(Entity& c, Entity::State newState) throw() {
Entity::State oldState = c.getState();
c.setState(newState);
signalState_(c, oldState);
}
void ClientManager::disconnect(Entity& c, Util::Reason reason, const std::string& info, AdcCommand::Error error, const std::string& staParam) {
// send a fatal STA
AdcCommand sta(AdcCommand::SEV_FATAL, error, info);
if(!staParam.empty())
sta.addParam(staParam);
c.send(sta);
// send a QUI
c.send(AdcCommand(AdcCommand::CMD_QUI).addParam(AdcCommand::fromSID(c.getSID()))
.addParam("DI", "1").addParam("MS", info).addParam("TL", "-1"));
c.disconnect(reason);
}
void ClientManager::enterIdentify(Entity& c, bool sendData) throw() {
dcassert(c.getState() == Entity::STATE_PROTOCOL);
dcdebug("%s entering IDENTIFY\n", AdcCommand::fromSID(c.getSID()).c_str());
if(sendData) {
c.send(hub.getSUP());
c.send(AdcCommand(AdcCommand::CMD_SID).addParam(AdcCommand::fromSID(c.getSID())));
c.send(hub.getINF());
}
setState(c, Entity::STATE_IDENTIFY);
}
ByteVector ClientManager::enterVerify(Entity& c, bool sendData) throw() {
dcassert(c.getState() == Entity::STATE_IDENTIFY);
dcdebug("%s entering VERIFY\n", AdcCommand::fromSID(c.getSID()).c_str());
ByteVector challenge;
challenge.reserve(32);
for(int i = 0; i < 32 / 4; ++i) {
uint32_t r = Util::rand();
challenge.insert(challenge.end(), (uint8_t*) &r, 4 + (uint8_t*) &r);
}
if(sendData) {
c.send(AdcCommand(AdcCommand::CMD_GPA).addParam(Encoder::toBase32(&challenge[0], challenge.size())));
}
setState(c, Entity::STATE_VERIFY);
return challenge;
}
bool ClientManager::enterNormal(Entity& c, bool sendData, bool sendOwnInf) throw() {
dcassert(c.getState() == Entity::STATE_IDENTIFY || c.getState() == Entity::STATE_VERIFY);
dcdebug("%s entering NORMAL\n", AdcCommand::fromSID(c.getSID()).c_str());
if(sendData) {
for(EntityIter i = entities.begin(); i != entities.end(); ++i) {
c.send(i->second->getINF());
}
}
if(sendOwnInf) {
sendToAll(c.getINF());
if(sendData) {
c.send(c.getINF());
}
}
removeLogins(c);
entities.insert(make_pair(c.getSID(), &c));
setState(c, Entity::STATE_NORMAL);
return true;
}
void ClientManager::removeLogins(Entity& e) throw() {
Client* c = dynamic_cast<Client*>(&e);
if(!c) {
return;
}
auto i = find_if(logins.begin(), logins.end(), CompareFirst<Client*, time::ptime> (c));
if(i != logins.end()) {
logins.erase(i);
}
}
void ClientManager::removeEntity(Entity& c, Util::Reason reason, const std::string &info) throw() {
if(c.isSet(Entity::FLAG_GHOST))
return;
dcdebug("Removing %s - %s\n", AdcCommand::fromSID(c.getSID()).c_str(), c.getCID().toBase32().c_str());
c.setFlag(Entity::FLAG_GHOST);
signalDisconnected_(c, reason, info);
if(c.getState() == Entity::STATE_NORMAL) {
entities.erase(c.getSID());
sendToAll(AdcCommand(AdcCommand::CMD_QUI).addParam(AdcCommand::fromSID(c.getSID())).addParam("DI", "1").getBuffer());
} else {
removeLogins(c);
}
nicks.erase(c.getField("NI"));
cids.erase(c.getCID());
}
Entity* ClientManager::getEntity(uint32_t aSid) throw() {
switch(aSid) {
case AdcCommand::INVALID_SID: return nullptr;
case AdcCommand::HUB_SID: return &hub;
default:
{
EntityIter i = entities.find(aSid);
return (i == entities.end()) ? nullptr : i->second;
}
}
}
uint32_t ClientManager::getSID(const string& aNick) const throw() {
NickMap::const_iterator i = nicks.find(aNick);
return (i == nicks.end()) ? AdcCommand::INVALID_SID : i->second->getSID();
}
uint32_t ClientManager::getSID(const CID& cid) const throw() {
CIDMap::const_iterator i = cids.find(cid);
return (i == cids.end()) ? AdcCommand::INVALID_SID : i->second->getSID();
}
void ClientManager::onFailed(Client& c, Util::Reason reason, const std::string &info) throw() {
removeEntity(c, reason, info);
}
}

243
src/adchpp/ClientManager.h Normal file
View File

@ -0,0 +1,243 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_CLIENTMANAGER_H
#define ADCHPP_CLIENTMANAGER_H
#include "CID.h"
#include "AdcCommand.h"
#include "Signal.h"
#include "Client.h"
#include "Hub.h"
#include "Bot.h"
#include "TimeUtil.h"
#include "TigerHash.h"
#include "forward.h"
namespace adchpp {
class ManagedSocket;
/**
* The ClientManager takes care of all protocol details, clients and so on. This is the very
* heart of ADCH++ together with SocketManager and ManagedSocket.
*/
class ClientManager : public CommandHandler<ClientManager>
{
public:
typedef std::unordered_map<uint32_t, Entity*> EntityMap;
typedef EntityMap::iterator EntityIter;
/** @return SID of entity or AdcCommand::INVALID_SID if not found */
ADCHPP_DLL uint32_t getSID(const std::string& nick) const throw();
/** @return SID of entity or AdcCommand::INVALID_SID if not found */
ADCHPP_DLL uint32_t getSID(const CID& cid) const throw();
/** @return The entity associated with a certain SID, NULL if not found */
ADCHPP_DLL Entity* getEntity(uint32_t aSid) throw();
/** @return A new Bot instance in STATE_IDENTIFY; set CID, nick etc and call regBot */
ADCHPP_DLL Bot* createBot(const Bot::SendHandler& handler);
ADCHPP_DLL void regBot(Bot& bot);
/**
* Get a list of all currently connected clients. (Don't change it, it's non-const
* so that you'll be able to get non-const clients out of it...)!!!)
*/
EntityMap& getEntities() throw() { return entities; }
/** Send a command to according to its type */
ADCHPP_DLL void send(const AdcCommand& cmd) throw();
/** Send a buffer to all connected entities */
ADCHPP_DLL void sendToAll(const BufferPtr& buffer) throw();
/** Send buffer to a single client regardless of type */
ADCHPP_DLL void sendTo(const BufferPtr& buffer, uint32_t to);
/**
* Enter IDENTIFY state.
* Call this if you stop the SUP command when in PROTOCOL state.
*
* @param sendData Send ISUP & IINF.
*/
ADCHPP_DLL void enterIdentify(Entity& c, bool sendData) throw();
/**
* Enter VERIFY state. Call this if you stop
* an INF in the IDENTIFY state and want to check a password.
*
* @param sendData Send GPA.
* @return The random data that was sent to the client (if sendData was true, undefined otherwise).
*/
ADCHPP_DLL ByteVector enterVerify(Entity& c, bool sendData) throw();
/**
* Enter NORMAL state. Call this if you stop an INF of a password-less
* client in IDENTIFY state or a PAS in VERIFY state.
*
* @param sendData Send all data as mandated by the protocol, including list of connected clients.
* @param sendOwnInf Set to true to broadcast the client's inf (i e when a plugin asks
* for password)
* @return false if the client was disconnected
*/
ADCHPP_DLL bool enterNormal(Entity& c, bool sendData, bool sendOwnInf) throw();
/**
* Do all SUP verifications and update client data. Call if you stop SUP but still want the default processing.
*/
ADCHPP_DLL bool verifySUP(Entity& c, AdcCommand& cmd) throw();
/**
* Do all INF verifications and update client data. Call if you stop INF but still want the default processing.
*/
ADCHPP_DLL bool verifyINF(Entity& c, AdcCommand& cmd) throw();
/**
* Verify nick on INF (check that its not a dupe etc...)
* @return false if the client was disconnected
*/
ADCHPP_DLL bool verifyNick(Entity& c, const AdcCommand& cmd) throw();
/**
* Verify password
*/
ADCHPP_DLL bool verifyPassword(Entity& c, const std::string& password, const ByteVector& salt, const std::string& suppliedHash);
bool verifyPassword(Entity& c, const std::string& password, const ByteVector& salt,
const std::string& suppliedHash, TigerHash&& tiger);
/**
* Verify hashed password; based on http://www.dcbase.org/forums/viewtopic.php?p=2861#p2861
*/
ADCHPP_DLL bool verifyHashedPassword(Entity& c, const ByteVector& hashedPassword, int64_t hashedPasswordLen,
const ByteVector& salt, const std::string& suppliedHash);
/**
* Verify that IP is correct and replace any zero addresses.
*/
ADCHPP_DLL bool verifyIp(Client& c, AdcCommand& cmd) throw();
/**
* Verify that CID is correct and corresponds to PID
*/
ADCHPP_DLL bool verifyCID(Entity& c, AdcCommand& cmd) throw();
/**
* Verify that there aren't too many sockets overflowing (indicates lack of bandwidth)
*/
ADCHPP_DLL bool verifyOverflow(Entity& c);
/** Update the state of c (this fires signalState as well) */
ADCHPP_DLL void setState(Entity& c, Entity::State newState) throw();
ADCHPP_DLL size_t getQueuedBytes() throw();
typedef SignalTraits<void (Entity&)> SignalConnected;
typedef SignalTraits<void (Entity&)> SignalReady;
typedef SignalTraits<void (Entity&, AdcCommand&, bool&)> SignalReceive;
typedef SignalTraits<void (Entity&, const std::string&)> SignalBadLine;
typedef SignalTraits<void (Entity&, const AdcCommand&, bool&)> SignalSend;
typedef SignalTraits<void (Entity&, int)> SignalState;
typedef SignalTraits<void (Entity&, Util::Reason, const std::string&)> SignalDisconnected;
/** A client has just connected. */
SignalConnected::Signal& signalConnected() { return signalConnected_; }
/** A client is now ready for read / write operations (TLS handshake completed). */
SignalConnected::Signal& signalReady() { return signalReady_; }
SignalReceive::Signal& signalReceive() { return signalReceive_; }
SignalBadLine::Signal& signalBadLine() { return signalBadLine_; }
SignalSend::Signal& signalSend() { return signalSend_; }
SignalState::Signal& signalState() { return signalState_; }
SignalDisconnected::Signal& signalDisconnected() { return signalDisconnected_; }
void setMaxCommandSize(size_t newSize) { maxCommandSize = newSize; }
size_t getMaxCommandSize() const { return maxCommandSize; }
void setLogTimeout(size_t millis) { logTimeout = millis; }
size_t getLogTimeout() const { return logTimeout; }
Core &getCore() const { return core; }
private:
friend class Core;
friend class Client;
friend class Entity;
friend class Bot;
Core &core;
std::list<std::pair<Client*, time::ptime> > logins;
EntityMap entities;
typedef std::unordered_map<std::string, Entity*> NickMap;
NickMap nicks;
typedef std::unordered_map<CID, Entity*> CIDMap;
CIDMap cids;
Hub hub;
size_t maxCommandSize;
size_t logTimeout;
// Temporary string to use whenever a temporary string is needed (to avoid (de)allocating memory all the time...)
std::string strtmp;
static const std::string className;
friend class CommandHandler<ClientManager>;
uint32_t makeSID();
void maybeSend(Entity& c, const AdcCommand& cmd);
void removeLogins(Entity& c) throw();
void removeEntity(Entity& c, Util::Reason reason, const std::string &info) throw();
bool handle(AdcCommand::SUP, Entity& c, AdcCommand& cmd) throw();
bool handle(AdcCommand::INF, Entity& c, AdcCommand& cmd) throw();
bool handleDefault(Entity& c, AdcCommand& cmd) throw();
template<typename T> bool handle(T, Entity& c, AdcCommand& cmd) throw() { return handleDefault(c, cmd); }
void handleIncoming(const ManagedSocketPtr& sock) throw();
void onConnected(Client&) throw();
void onReady(Client&) throw();
void onReceive(Entity&, AdcCommand&) throw();
void onBadLine(Client&, const std::string&) throw();
void onFailed(Client&, Util::Reason reason, const std::string &info) throw();
void badState(Entity& c, const AdcCommand& cmd) throw();
/** send a fatal STA, a QUI with TL-1, then disconnect. */
void disconnect(Entity& c, Util::Reason reason, const std::string& info,
AdcCommand::Error error = AdcCommand::ERROR_PROTOCOL_GENERIC, const std::string& staParam = Util::emptyString);
SignalConnected::Signal signalConnected_;
SignalReady::Signal signalReady_;
SignalReceive::Signal signalReceive_;
SignalBadLine::Signal signalBadLine_;
SignalSend::Signal signalSend_;
SignalState::Signal signalState_;
SignalDisconnected::Signal signalDisconnected_;
ClientManager(Core &core) throw();
};
}
#endif // CLIENTMANAGER_H

93
src/adchpp/Core.cpp Normal file
View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "Core.h"
#include "LogManager.h"
#include "SocketManager.h"
#include "ClientManager.h"
#include "PluginManager.h"
namespace adchpp {
shared_ptr<Core> Core::create(const std::string &configPath) {
auto ret = shared_ptr<Core>(new Core(configPath));
ret->init();
return ret;
}
Core::Core(const std::string &configPath) : configPath(configPath), startTime(time::now())
{
}
Core::~Core() {
lm->log("core", "Shutting down...");
// Order is significant...
pm.reset();
cm.reset();
sm.reset();
lm.reset();
}
void Core::init() {
lm.reset(new LogManager(*this));
sm.reset(new SocketManager(*this));
cm.reset(new ClientManager(*this));
pm.reset(new PluginManager(*this));
sm->setIncomingHandler(std::bind(&ClientManager::handleIncoming, cm.get(), std::placeholders::_1));
//lm->log("core", "Core initialized"); @todo logfile path setting isn't processed yet so this may litter log files to unwanted places, see L#907372
printf("\nCore initialized\n"); // Console print only for now...
}
void Core::run() {
pm->load();
sm->run();
}
void Core::shutdown() {
// make sure we run shutdown routines from the right thread.
addJob(std::bind(&Core::doShutdown, this));
}
void Core::doShutdown() {
sm->shutdown();
pm->shutdown();
}
const std::string &Core::getConfigPath() const { return configPath; }
LogManager &Core::getLogManager() { return *lm; }
SocketManager &Core::getSocketManager() { return *sm; }
PluginManager &Core::getPluginManager() { return *pm; }
ClientManager &Core::getClientManager() { return *cm; }
void Core::addJob(const Callback& callback) throw() { sm->addJob(callback); }
void Core::addJob(const long msec, const Callback& callback) { sm->addJob(msec, callback); }
void Core::addJob(const std::string& time, const Callback& callback) { sm->addJob(time, callback); }
Core::Callback Core::addTimedJob(const long msec, const Callback& callback) { return sm->addTimedJob(msec, callback); }
Core::Callback Core::addTimedJob(const std::string& time, const Callback& callback) { return sm->addTimedJob(time, callback); }
}

93
src/adchpp/Core.h Normal file
View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_ADCHPP_CORE_H_
#define ADCHPP_ADCHPP_CORE_H_
#include "common.h"
#include "TimeUtil.h"
#include "forward.h"
namespace adchpp {
/** A single instance of an entire hub with plugins, settings and listening sockets */
class Core {
public:
typedef std::function<void()> Callback;
ADCHPP_DLL ~Core();
ADCHPP_DLL static shared_ptr<Core> create(const std::string &configPath);
ADCHPP_DLL void run();
ADCHPP_DLL void shutdown();
ADCHPP_DLL LogManager &getLogManager();
ADCHPP_DLL SocketManager &getSocketManager();
ADCHPP_DLL PluginManager &getPluginManager();
ADCHPP_DLL ClientManager &getClientManager();
ADCHPP_DLL const std::string &getConfigPath() const;
/** execute a function asynchronously */
ADCHPP_DLL void addJob(const Callback& callback) throw();
/** execute a function after the specified amount of time
* @param msec milliseconds
*/
ADCHPP_DLL void addJob(const long msec, const Callback& callback);
/** execute a function after the specified amount of time
* @param time a string that obeys to the "[-]h[h][:mm][:ss][.fff]" format
*/
ADCHPP_DLL void addJob(const std::string& time, const Callback& callback);
/** execute a function at regular intervals
* @param msec milliseconds
* @return function one must call to cancel the timer (its callback will still be executed)
*/
ADCHPP_DLL Callback addTimedJob(const long msec, const Callback& callback);
/** execute a function at regular intervals
* @param time a string that obeys to the "[-]h[h][:mm][:ss][.fff]" format
* @return function one must call to cancel the timer (its callback will still be executed)
*/
ADCHPP_DLL Callback addTimedJob(const std::string& time, const Callback& callback);
time::ptime getStartTime() const { return startTime; }
private:
Core(const std::string &configPath);
void init();
void doShutdown(); /// @todo remove when we have lambdas
std::unique_ptr<LogManager> lm;
std::unique_ptr<SocketManager> sm;
std::unique_ptr<PluginManager> pm;
std::unique_ptr<ClientManager> cm;
std::string configPath;
time::ptime startTime;
};
}
#endif /* CORE_H_ */

115
src/adchpp/Encoder.cpp Normal file
View File

@ -0,0 +1,115 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "Encoder.h"
#include "common.h"
namespace adchpp {
using namespace std;
const int8_t Encoder::base32Table[256] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
};
const char Encoder::base32Alphabet[32] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '2', '3', '4', '5', '6', '7'
};
string& Encoder::toBase32(const uint8_t* src, size_t len, string& dst) {
// Code snagged from the bitzi bitcollider
size_t i, index;
uint8_t word;
dst.reserve(((len * 8) / 5) + 1);
for(i = 0, index = 0; i < len;) {
/* Is the current word going to span a byte boundary? */
if (index > 3) {
word = (uint8_t)(src[i] & (0xFF >> index));
index = (index + 5) % 8;
word <<= index;
if ((i + 1) < len)
word |= src[i + 1] >> (8 - index);
i++;
} else {
word = (uint8_t)(src[i] >> (8 - (index + 5))) & 0x1F;
index = (index + 5) % 8;
if (index == 0)
i++;
}
dcassert(word < 32);
dst += base32Alphabet[word];
}
return dst;
}
void Encoder::fromBase32(const char* src, uint8_t* dst, size_t len) {
size_t i, index, offset;
memset(dst, 0, len);
for(i = 0, index = 0, offset = 0; src[i]; i++) {
// Skip what we don't recognise
int8_t tmp = base32Table[(unsigned char)src[i]];
if(tmp == -1)
continue;
if (index <= 3) {
index = (index + 5) % 8;
if (index == 0) {
dst[offset] |= tmp;
offset++;
if(offset == len)
break;
} else {
dst[offset] |= tmp << (8 - index);
}
} else {
index = (index + 5) % 8;
dst[offset] |= (tmp >> index);
offset++;
if(offset == len)
break;
dst[offset] |= tmp << (8 - index);
}
}
}
}

41
src/adchpp/Encoder.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_ENCODER_H
#define ADCHPP_ENCODER_H
namespace adchpp {
class Encoder
{
public:
ADCHPP_DLL static std::string& toBase32(const uint8_t* src, size_t len, std::string& tgt);
static std::string toBase32(const uint8_t* src, size_t len) {
std::string tmp;
return toBase32(src, len, tmp);
}
ADCHPP_DLL static void fromBase32(const char* src, uint8_t* dst, size_t len);
ADCHPP_DLL static const int8_t base32Table[256];
ADCHPP_DLL static const char base32Alphabet[32];
private:
};
}
#endif // _ENCODER

218
src/adchpp/Entity.cpp Normal file
View File

@ -0,0 +1,218 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "Entity.h"
#include "ClientManager.h"
namespace adchpp {
Entity::~Entity() {
for(PluginDataMap::iterator i = pluginData.begin(), iend = pluginData.end(); i != iend; ++i) {
(*i->first)(i->second);
}
}
void Entity::inject(AdcCommand& cmd) {
cm.onReceive(*this, cmd);
}
const std::string& Entity::getField(const char* name) const {
auto i = fields.find(AdcCommand::toField(name));
return i == fields.end() ? Util::emptyString : i->second;
}
bool Entity::hasField(const char* name) const {
return fields.find(AdcCommand::toField(name)) != fields.end();
}
void Entity::setField(const char* name, const std::string& value) {
uint16_t code = AdcCommand::toField(name);
if(code == AdcCommand::toField("SU")) {
filters.clear();
if((value.size() + 1) % 5 == 0) {
filters.reserve((value.size() + 1) / 5);
for(size_t i = 0; i < value.size(); i += 5) {
filters.push_back(AdcCommand::toFourCC(value.data() + i));
}
}
}
if(value.empty()) {
fields.erase(code);
} else {
fields[code] = value;
}
INF = BufferPtr();
}
bool Entity::getAllFields(AdcCommand& cmd) const throw() {
for(auto i = fields.begin(); i != fields.end(); ++i)
cmd.addParam(AdcCommand::fromField(i->first), i->second);
return !fields.empty();
}
void Entity::updateFields(const AdcCommand& cmd) {
dcassert(cmd.getCommand() == AdcCommand::CMD_INF);
for(StringIterC j = cmd.getParameters().begin(); j != cmd.getParameters().end(); ++j) {
if(j->size() < 2)
continue;
setField(j->c_str(), j->substr(2));
}
}
const BufferPtr& Entity::getINF() const {
if(!INF) {
AdcCommand cmd(AdcCommand::CMD_INF, getSID() == AdcCommand::HUB_SID ? AdcCommand::TYPE_INFO : AdcCommand::TYPE_BROADCAST, getSID());
getAllFields(cmd);
INF = cmd.getBuffer();
}
return INF;
}
bool Entity::addSupports(uint32_t feature) {
if(std::find(supports.begin(), supports.end(), feature) != supports.end()) {
return false;
}
supports.push_back(feature);
SUP = BufferPtr();
return true;
}
StringList Entity::getSupportList() const {
StringList ret(supports.size());
for(size_t i = 0; i < supports.size(); ++i) {
ret[i] = AdcCommand::fromFourCC(supports[i]);
}
return ret;
}
bool Entity::removeSupports(uint32_t feature) {
std::vector<uint32_t>::iterator i = std::find(supports.begin(), supports.end(), feature);
if(i == supports.end()) {
return false;
}
supports.erase(i);
SUP = BufferPtr();
return true;
}
const BufferPtr& Entity::getSUP() const {
if(!SUP) {
AdcCommand cmd(AdcCommand::CMD_SUP, getSID() == AdcCommand::HUB_SID ? AdcCommand::TYPE_INFO : AdcCommand::TYPE_BROADCAST, getSID());
for(std::vector<uint32_t>::const_iterator i = supports.begin(), iend = supports.end(); i != iend; ++i) {
cmd.addParam("AD", AdcCommand::fromFourCC(*i));
}
SUP = cmd.getBuffer();
}
return SUP;
}
bool Entity::hasSupport(uint32_t feature) const {
return find(supports.begin(), supports.end(), feature) != supports.end();
}
void Entity::updateSupports(const AdcCommand& cmd) throw() {
for(StringIterC i = cmd.getParameters().begin(); i != cmd.getParameters().end(); ++i) {
const std::string& str = *i;
if(str.size() != 6) {
continue;
}
if(str[0] == 'A' && str[1] == 'D') {
addSupports(AdcCommand::toFourCC(str.c_str() + 2));
} else if(str[0] == 'R' && str[1] == 'M') {
removeSupports(AdcCommand::toFourCC(str.c_str() + 2));
}
}
}
bool Entity::isFiltered(const std::string& features) const {
if(filters.empty()) {
return true;
}
for(size_t i = 0; i < features.size(); i += 5) {
if(features[i] == '-') {
if(std::find(filters.begin(), filters.end(), AdcCommand::toFourCC(features.data() + i + 1)) != filters.end()) {
return true;
}
} else if(features[i] == '+') {
if(std::find(filters.begin(), filters.end(), AdcCommand::toFourCC(features.data() + i + 1)) == filters.end()) {
return true;
}
}
}
return false;
}
void Entity::setPluginData(const PluginDataHandle& handle, void* data) throw() {
clearPluginData(handle);
pluginData.insert(std::make_pair(handle, data));
}
void* Entity::getPluginData(const PluginDataHandle& handle) const throw() {
PluginDataMap::const_iterator i = pluginData.find(handle);
return i == pluginData.end() ? 0 : i->second;
}
void Entity::clearPluginData(const PluginDataHandle& handle) throw() {
PluginDataMap::iterator i = pluginData.find(handle);
if(i == pluginData.end()) {
return;
}
(*i->first)(i->second);
pluginData.erase(i);
}
void Entity::setFlag(size_t flag) {
flags.setFlag(flag);
if(flag & MASK_CLIENT_TYPE) {
setField("CT", Util::toString(flags.getFlags() & MASK_CLIENT_TYPE));
}
}
void Entity::unsetFlag(size_t flag) {
flags.unsetFlag(flag);
if(flag & MASK_CLIENT_TYPE) {
setField("CT", Util::toString(flags.getFlags() & MASK_CLIENT_TYPE));
}
}
size_t Entity::getQueuedBytes() const {
return 0;
}
time::ptime Entity::getOverflow() const {
return time::not_a_date_time;
}
}

173
src/adchpp/Entity.h Normal file
View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_ENTITY_H
#define ADCHPP_ENTITY_H
#include "forward.h"
#include "Buffer.h"
#include "AdcCommand.h"
#include "Plugin.h"
#include "CID.h"
#include "TimeUtil.h"
namespace adchpp {
class ADCHPP_VISIBLE Entity : private boost::noncopyable {
public:
enum State {
/** Initial protocol negotiation (wait for SUP) */
STATE_PROTOCOL,
/** Identify the connecting client (wait for INF) */
STATE_IDENTIFY,
/** Verify the client (wait for PAS) */
STATE_VERIFY,
/** Normal operation */
STATE_NORMAL,
/** Binary data transfer */
STATE_DATA
};
enum Flag {
FLAG_BOT = 0x01,
FLAG_REGISTERED = 0x02,
FLAG_OP = 0x04,
FLAG_SU = 0x08,
FLAG_OWNER = 0x10,
FLAG_HUB = 0x20,
FLAG_HIDDEN = 0x40,
MASK_CLIENT_TYPE = FLAG_BOT | FLAG_REGISTERED | FLAG_OP | FLAG_SU | FLAG_OWNER | FLAG_HUB | FLAG_HIDDEN,
FLAG_PASSWORD = 0x100,
/** Extended away, no need to send msg */
FLAG_EXT_AWAY = 0x200,
/** Plugins can use these flags to disable various checks */
/** Bypass ip check */
FLAG_OK_IP = 0x400,
/** This entity is now a ghost being disconnected, totally ignored by ADCH++ */
FLAG_GHOST = 0x800
};
Entity(ClientManager &cm, uint32_t sid_) : sid(sid_), state(STATE_PROTOCOL), cm(cm) { }
void send(const AdcCommand& cmd) { send(cmd.getBuffer()); }
virtual void send(const BufferPtr& cmd) = 0;
ADCHPP_DLL virtual void inject(AdcCommand& cmd);
ADCHPP_DLL const std::string& getField(const char* name) const;
ADCHPP_DLL bool hasField(const char* name) const;
ADCHPP_DLL void setField(const char* name, const std::string& value);
/** Add any flags that have been updated to the AdcCommand (type etc is not set) */
ADCHPP_DLL bool getAllFields(AdcCommand& cmd) const throw();
ADCHPP_DLL const BufferPtr& getINF() const;
ADCHPP_DLL bool addSupports(uint32_t feature);
ADCHPP_DLL StringList getSupportList() const;
ADCHPP_DLL bool hasSupport(uint32_t feature) const;
ADCHPP_DLL bool removeSupports(uint32_t feature);
ADCHPP_DLL const BufferPtr& getSUP() const;
uint32_t getSID() const { return sid; }
ADCHPP_DLL bool isFiltered(const std::string& features) const;
ADCHPP_DLL void updateFields(const AdcCommand& cmd);
ADCHPP_DLL void updateSupports(const AdcCommand& cmd) throw();
/**
* Set PSD (plugin specific data). This allows a plugin to store arbitrary
* per-client data, and retrieve it later on. The life cycle of the data follows
* that of the client unless explicitly removed. Any data referenced by the plugin
* will have its delete function called when the Entity is deleted.
* @param id Id as retrieved from PluginManager::getPluginId()
* @param data Data to store, this can be pretty much anything
*/
ADCHPP_DLL void setPluginData(const PluginDataHandle& handle, void* data) throw();
/**
* @param handle Plugin data handle, as returned by PluginManager::registerPluginData
* @return Value stored, NULL if none found
*/
ADCHPP_DLL void* getPluginData(const PluginDataHandle& handle) const throw();
/**
* Clear any data referenced by the handle, calling the registered delete function.
*/
ADCHPP_DLL void clearPluginData(const PluginDataHandle& handle) throw();
const CID& getCID() const { return cid; }
void setCID(const CID& cid_) { cid = cid_; }
State getState() const { return state; }
void setState(State state_) { state = state_; }
bool isSet(size_t aFlag) const { return flags.isSet(aFlag); }
bool isAnySet(size_t aFlag) const { return flags.isAnySet(aFlag); }
ADCHPP_DLL void setFlag(size_t aFlag);
ADCHPP_DLL void unsetFlag(size_t aFlag);
ADCHPP_DLL virtual void disconnect(Util::Reason reason, const std::string &info = Util::emptyString) = 0;
/** The number of bytes in the write buffer */
ADCHPP_DLL virtual size_t getQueuedBytes() const;
/** The time that this entity's write buffer size exceeded the maximum buffer size, 0 if no overflow */
ADCHPP_DLL virtual time::ptime getOverflow() const;
protected:
virtual ~Entity();
typedef std::map<PluginDataHandle, void*> PluginDataMap;
CID cid;
uint32_t sid;
Flags flags;
State state;
/** SUP items */
std::vector<uint32_t> supports;
/** INF SU */
std::vector<uint32_t> filters;
/** INF fields */
std::map<uint16_t, std::string> fields;
/** Plugin data, see PluginManager::registerPluginData */
PluginDataMap pluginData;
/** Latest INF cached */
mutable BufferPtr INF;
/** Latest SUP cached */
mutable BufferPtr SUP;
/** ClientManager that owns this entity */
ClientManager &cm;
};
}
#endif /* ADCHPP_ENTITY_H */

60
src/adchpp/Exception.h Normal file
View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_EXCEPTION_H
#define ADCHPP_EXCEPTION_H
#include "common.h"
namespace adchpp {
class ADCHPP_VISIBLE Exception : public std::exception
{
public:
Exception() { }
Exception(const std::string& aError) throw() : error(aError) { dcdebug("Thrown: %s\n", error.c_str()); }
virtual ~Exception() throw() { }
const std::string& getError() const throw() { return error; }
virtual const char* what() const throw() { return error.c_str(); }
protected:
std::string error;
};
#ifndef NDEBUG
#define STANDARD_EXCEPTION(name) class ADCHPP_VISIBLE name : public Exception { \
public:\
name() throw() : Exception(#name) { } \
name(const std::string& aError) throw() : Exception(#name ": " + aError) { } \
virtual ~name() throw() { } \
}
#else // NDEBUG
#define STANDARD_EXCEPTION(name) class ADCHPP_VISIBLE name : public Exception { \
public:\
name() throw() : Exception() { } \
name(const std::string& aError) throw() : Exception(aError) { } \
virtual ~name() throw() { } \
}
#endif
}
#endif // EXCEPTION_H

100
src/adchpp/FastAlloc.h Normal file
View File

@ -0,0 +1,100 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_FASTALLOC_H
#define ADCHPP_FASTALLOC_H
#include "Mutex.h"
namespace adchpp {
#ifdef NDEBUG
struct FastAllocBase {
ADCHPP_DLL static FastMutex mtx;
};
/**
* Fast new/delete replacements for constant sized objects, that also give nice
* reference locality...
*/
template<class T>
struct FastAlloc : public FastAllocBase {
// Custom new & delete that (hopefully) use the node allocator
static void* operator new(size_t s) {
if(s != sizeof(T))
return ::operator new(s);
return allocate();
}
// Avoid hiding placement new that's needed by the stl containers...
static void* operator new(size_t, void* m) {
return m;
}
// ...and the warning about missing placement delete...
static void operator delete(void*, void*) {
// ? We didn't allocate so...
}
static void operator delete(void* m, size_t s) {
if (s != sizeof(T)) {
::operator delete(m);
} else if(m != NULL) {
deallocate((uint8_t*)m);
}
}
private:
static void* allocate() {
FastMutex::Lock l(mtx);
if(freeList == NULL) {
grow();
}
void* tmp = freeList;
freeList = *((void**)freeList);
return tmp;
}
static void deallocate(void* p) {
FastMutex::Lock l(mtx);
*(void**)p = freeList;
freeList = p;
}
static void* freeList;
static void grow() {
dcassert(sizeof(T) >= sizeof(void*));
// We want to grow by approximately 128kb at a time...
size_t items = ((128*1024 + sizeof(T) - 1)/sizeof(T));
freeList = new uint8_t[sizeof(T)*items];
uint8_t* tmp = (uint8_t*)freeList;
for(size_t i = 0; i < items - 1; i++) {
*(void**)tmp = tmp + sizeof(T);
tmp += sizeof(T);
}
*(void**)tmp = NULL;
}
};
template<class T> void* FastAlloc<T>::freeList = 0;
#else
template<class T> struct FastAlloc { };
#endif
}
#endif // FASTALLOC_H

188
src/adchpp/File.cpp Normal file
View File

@ -0,0 +1,188 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "File.h"
namespace adchpp {
using namespace std;
string File::read(uint32_t len) throw(FileException) {
string tmp;
tmp.resize(len);
uint32_t x = read(&tmp[0], len);
tmp.resize(x);
return tmp;
}
#ifdef _WIN32
File::File(const string& aFileName, int access, int mode) throw(FileException) {
dcassert(access == WRITE || access == READ || access == (READ | WRITE));
int m = 0;
if(mode & OPEN) {
if(mode & CREATE) {
m = (mode & TRUNCATE) ? CREATE_ALWAYS : OPEN_ALWAYS;
} else {
m = (mode & TRUNCATE) ? TRUNCATE_EXISTING : OPEN_EXISTING;
}
} else {
if(mode & CREATE) {
m = (mode & TRUNCATE) ? CREATE_ALWAYS : CREATE_NEW;
} else {
dcassert(0);
}
}
int a = 0;
if(access & READ)
a |= GENERIC_READ;
if(access & WRITE)
a |= GENERIC_WRITE;
h = ::CreateFile(aFileName.c_str(), a, FILE_SHARE_READ, NULL, m, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if(h == INVALID_HANDLE_VALUE) {
throw FileException(Util::translateError(GetLastError()));
}
}
int64_t File::getSize() {
DWORD x;
DWORD l = ::GetFileSize(h, &x);
if( (l == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
return -1;
return (int64_t)l | ((int64_t)x)<<32;
}
int64_t File::getSize(const string& aFileName) {
WIN32_FIND_DATA fd;
HANDLE hFind;
hFind = FindFirstFile(aFileName.c_str(), &fd);
if (hFind == INVALID_HANDLE_VALUE) {
return -1;
} else {
FindClose(hFind);
return ((int64_t)fd.nFileSizeHigh << 32 | (int64_t)fd.nFileSizeLow);
}
}
string File::getFilePath(const string& path) throw() {
string::size_type i = path.find_last_of("\\/");
return (i != string::npos) ? path.substr(0, i) : path;
}
string File::getFileName(const string& path) throw() {
string::size_type i = path.find_last_of("\\/");
return (i != string::npos) ? path.substr(i + 1) : path;
}
bool File::isAbsolutePath(const string& path) throw() {
return (path.length() >= 3 && path[1] == ':' && (path[2] == '\\' || path[2] == '/')) ||
(path.length() >= 1 && (path[0] == '\\' || path[0] == '/'));
}
void File::ensureDirectory(const string& aFile) throw() {
string::size_type start = 0;
while( (start = aFile.find_first_of("\\/", start)) != string::npos) {
::CreateDirectory(aFile.substr(0, start+1).c_str(), NULL);
start++;
}
}
#else // _WIN32
File::File(const string& aFileName, int access, int mode) throw(FileException) {
dcassert(access == WRITE || access == READ || access == (READ | WRITE));
int m = 0;
if(access == READ)
m |= O_RDONLY;
else if(access == WRITE)
m |= O_WRONLY;
else
m |= O_RDWR;
if(mode & CREATE) {
m |= O_CREAT;
}
if(mode & TRUNCATE) {
m |= O_TRUNC;
}
h = open(aFileName.c_str(), m, S_IRUSR | S_IWUSR);
if(h == -1)
throw FileException("Could not open file");
}
int64_t File::getSize() {
struct stat s;
if(fstat(h, &s) == -1)
return -1;
return (int64_t)s.st_size;
}
int64_t File::getSize(const string& aFileName) {
struct stat s;
if(stat(aFileName.c_str(), &s) == -1)
return -1;
return s.st_size;
}
string File::getFilePath(const string& path) throw() {
string::size_type i = path.rfind('/');
return (i != string::npos) ? path.substr(0, i) : path;
}
string File::getFileName(const string& path) throw() {
string::size_type i = path.rfind('/');
return (i != string::npos) ? path.substr(i + 1) : path;
}
bool File::isAbsolutePath(const string& path) throw() {
return path.length() >= 1 && path[0] == '/';
}
void File::ensureDirectory(const string& aFile) throw() {
string::size_type start = 0;
while( (start = aFile.find('/', start)) != string::npos) {
::mkdir(aFile.substr(0, start+1).c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
start++;
}
}
#endif
std::string File::makeAbsolutePath(const std::string& filename) {
return makeAbsolutePath(Util::getAppPath() + PATH_SEPARATOR, filename);
}
std::string File::makeAbsolutePath(const std::string& path, const std::string& filename) {
return isAbsolutePath(filename) ? filename : path + filename;
}
}

193
src/adchpp/File.h Normal file
View File

@ -0,0 +1,193 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_FILE_H
#define ADCHPP_FILE_H
#include "Exception.h"
#include "Util.h"
#ifndef _WIN32
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif
namespace adchpp {
STANDARD_EXCEPTION(FileException);
class File
{
public:
enum {
READ = 0x01,
WRITE = 0x02
};
enum {
OPEN = 0x01,
CREATE = 0x02,
TRUNCATE = 0x04
};
ADCHPP_DLL File(const std::string& aFileName, int access, int mode = OPEN) throw(FileException);
ADCHPP_DLL int64_t getSize();
ADCHPP_DLL static int64_t getSize(const std::string& aFileName);
ADCHPP_DLL std::string read(uint32_t len) throw(FileException);
/** Returns the directory part of the full path */
ADCHPP_DLL static std::string getFilePath(const std::string& name) throw();
/** Returns the filename part of the full path */
ADCHPP_DLL static std::string getFileName(const std::string& name) throw();
ADCHPP_DLL static bool isAbsolutePath(const std::string& name) throw();
ADCHPP_DLL static std::string makeAbsolutePath(const std::string& filename);
ADCHPP_DLL static std::string makeAbsolutePath(const std::string& path, const std::string& filename);
ADCHPP_DLL static void ensureDirectory(const std::string& aFile) throw();
#ifdef _WIN32
void close() {
if(h != INVALID_HANDLE_VALUE) {
CloseHandle(h);
h = INVALID_HANDLE_VALUE;
}
}
int64_t getPos() {
LONG x = 0;
DWORD l = ::SetFilePointer(h, 0, &x, FILE_CURRENT);
return (int64_t)l | ((int64_t)x)<<32;
}
void setPos(int64_t pos) {
LONG x = (LONG) (pos>>32);
::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_BEGIN);
}
void setEndPos(int64_t pos) {
LONG x = (LONG) (pos>>32);
::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_END);
}
void movePos(int64_t pos) {
LONG x = (LONG) (pos>>32);
::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_CURRENT);
}
uint32_t read(void* buf, uint32_t len) throw(FileException) {
DWORD x;
if(!::ReadFile(h, buf, len, &x, NULL)) {
throw(FileException(Util::translateError(GetLastError())));
}
return x;
}
void write(const void* buf, size_t len) throw(FileException) {
DWORD x;
if(!::WriteFile(h, buf, (DWORD)len, &x, NULL)) {
throw FileException(Util::translateError(GetLastError()));
}
if(x < len) {
throw FileException("Unable to write, disk full?");
}
}
void setEOF() throw(FileException) {
dcassert(h != NULL);
if(!SetEndOfFile(h)) {
throw FileException(Util::translateError(GetLastError()));
}
}
static void deleteFile(const std::string& aFileName) { ::DeleteFile(aFileName.c_str()); };
static void renameFile(const std::string& source, const std::string& target) { ::MoveFile(source.c_str(), target.c_str()); };
#else // WIN32
void close() {
if(h != -1) {
::close(h);
h = -1;
}
}
int64_t getPos() { return (int64_t) lseek(h, 0, SEEK_CUR); }
void setPos(int64_t pos) { lseek(h, (off_t)pos, SEEK_SET); };
void setEndPos(int64_t pos) { lseek(h, (off_t)pos, SEEK_END); };
void movePos(int64_t pos) { lseek(h, (off_t)pos, SEEK_CUR); };
uint32_t read(void* buf, uint32_t len) throw(FileException) {
ssize_t x = ::read(h, buf, (size_t)len);
if(x == -1)
throw FileException(Util::translateError(errno));
return (uint32_t)x;
}
void write(const void* buf, uint32_t len) throw(FileException) {
ssize_t x;
x = ::write(h, buf, len);
if(x == -1)
throw FileException(Util::translateError(errno));
if(x < (ssize_t)len)
throw FileException("Unable to write, disk full?");
}
/**
* @todo fix for unix...
*/
void setEOF() throw(FileException) {
}
static void deleteFile(const std::string& aFileName) { ::unlink(aFileName.c_str()); };
static void renameFile(const std::string& source, const std::string& target) { ::rename(source.c_str(), target.c_str()); };
#endif // WIN32
~File() {
close();
}
std::string read() throw(FileException) {
setPos(0);
return read((uint32_t)getSize());
}
void write(const std::string& aString) throw(FileException) {
write((void*)aString.data(), aString.size());
}
private:
File(const File&);
File& operator=(const File&);
#ifdef _WIN32
HANDLE h;
#else
int h;
#endif
};
}
#endif // FILE_H

36
src/adchpp/Hub.cpp Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "Hub.h"
#include "AdcCommand.h"
#include "version.h"
namespace adchpp {
Hub::Hub(ClientManager &cm) : Entity(cm, AdcCommand::HUB_SID) {
setField("NI", "adchpp");
setField("HI", "1");
setField("DE", appName + ' ' + versionString);
setField("AP", appName);
setField("VE", versionString);
setFlag(FLAG_HUB);
}
}

39
src/adchpp/Hub.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef HUB_H_
#define HUB_H_
#include "forward.h"
#include "Entity.h"
namespace adchpp {
class ADCHPP_VISIBLE Hub : public Entity {
public:
ADCHPP_DLL Hub(ClientManager &cm);
virtual void send(const BufferPtr& cmd) { }
virtual void disconnect(Util::Reason reason, const std::string &) throw() { }
private:
};
}
#endif /* HUB_H_ */

69
src/adchpp/LogManager.cpp Normal file
View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "LogManager.h"
#include "File.h"
#include "Core.h"
namespace adchpp {
using namespace std;
LogManager::LogManager(Core &core) : logFile("logs/adchpp%Y%m.log"), enabled(true), core(core) { }
void LogManager::log(const string& area, const string& msg) throw() {
char buf[64];
time_t now = std::time(NULL);
size_t s = strftime(buf, 64, "%Y-%m-%d %H:%M:%S: ", localtime(&now));
string tmp(buf, s);
tmp += area;
tmp += ": ";
tmp += msg;
dolog(tmp);
}
void LogManager::dolog(const string& msg) throw() {
dcdebug("Logging: %s\n", msg.c_str());
signalLog_(msg);
if(getEnabled()) {
string logFile = Util::formatTime(File::makeAbsolutePath(core.getConfigPath(), getLogFile()));
FastMutex::Lock l(mtx);
try {
File f(logFile, File::WRITE, File::OPEN | File::CREATE);
f.setEndPos(0);
f.write(msg + "\r\n");
return;
} catch(const FileException& e) {
dcdebug("LogManager::log: %s\n", e.getError().c_str());
}
try {
File::ensureDirectory(logFile);
File f(logFile, File::WRITE, File::OPEN | File::CREATE);
f.setEndPos(0);
f.write(msg + "\r\n");
} catch(const FileException& ee) {
dcdebug("LogManager::log2: %s\n", ee.getError().c_str());
}
}
}
}

70
src/adchpp/LogManager.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_LOGMANAGER_H
#define ADCHPP_LOGMANAGER_H
#include "forward.h"
#include "Mutex.h"
#include "Signal.h"
namespace adchpp {
/**
* Log writing utilities.
*/
class LogManager
{
public:
/**
* Add a line to the log.
* @param area Name of the module that generated the error.
* @param msg Message to log.
*/
ADCHPP_DLL void log(const std::string& area, const std::string& msg) throw();
void setLogFile(const std::string& fileName) { logFile = fileName; }
const std::string& getLogFile() const { return logFile; }
void setEnabled(bool enabled_) { enabled = enabled_; }
bool getEnabled() const { return enabled; }
typedef SignalTraits<void (const std::string&)> SignalLog;
SignalLog::Signal& signalLog() { return signalLog_; }
private:
friend class Core;
FastMutex mtx;
std::string logFile;
bool enabled;
LogManager(Core &core);
SignalLog::Signal signalLog_;
Core &core;
ADCHPP_DLL void dolog(const std::string& msg) throw();
};
#define LOGC(core, area, msg) (core).getLogManager().log(area, msg)
#define LOG(area, msg) LOGC(core, area, msg)
}
#endif // LOGMANAGER_H

View File

@ -0,0 +1,278 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "ManagedSocket.h"
#include "SocketManager.h"
namespace adchpp {
using namespace std;
using namespace boost::asio;
ManagedSocket::ManagedSocket(SocketManager &sm, const AsyncStreamPtr &sock_) :
sock(sock_),
overflow(time::not_a_date_time),
disc(time::not_a_date_time),
lastWrite(time::not_a_date_time),
sm(sm)
{ }
ManagedSocket::~ManagedSocket() throw() {
dcdebug("ManagedSocket deleted\n");
}
static size_t sum(const BufferList& l) {
size_t bytes = 0;
for(BufferList::const_iterator i = l.begin(); i != l.end(); ++i) {
bytes += (*i)->size();
}
return bytes;
}
size_t ManagedSocket::getQueuedBytes() const {
return sum(outBuf);
}
void ManagedSocket::write(const BufferPtr& buf, bool lowPrio /* = false */) throw() {
if(buf->size() == 0 || disconnecting())
return;
size_t queued = getQueuedBytes();
if(sm.getMaxBufferSize() > 0 && queued + buf->size() > sm.getMaxBufferSize()) {
if(lowPrio) {
return;
} else if(!overflow.is_not_a_date_time() && overflow + time::millisec(sm.getOverflowTimeout()) < time::now()) {
disconnect(Util::REASON_WRITE_OVERFLOW);
return;
} else {
overflow = time::now();
}
}
sm.getStats().queueBytes += buf->size();
sm.getStats().queueCalls++;
outBuf.push_back(buf);
prepareWrite();
}
// Simplified handlers to avoid bind complexity
namespace {
/** Keeper keeps a reference to the managed socket */
struct Keeper {
Keeper(const ManagedSocketPtr& ms_) : ms(ms_) { }
ManagedSocketPtr ms;
void operator()(const boost::system::error_code& ec, size_t bytes) { }
};
template<void (ManagedSocket::*F)(const boost::system::error_code&, size_t)>
struct Handler : Keeper {
Handler(const ManagedSocketPtr& ms) : Keeper(ms) { }
void operator()(const boost::system::error_code& ec, size_t bytes) {
(ms.get()->*F)(ec, bytes);
}
};
struct Disconnector {
Disconnector(const AsyncStreamPtr& stream_) : stream(stream_) { }
void operator()() { stream->close(); }
AsyncStreamPtr stream;
};
}
void ManagedSocket::prepareWrite() throw() {
if(!writing()) { // Not writing
if(!outBuf.empty()) {
lastWrite = time::now();
sock->write(outBuf, Handler<&ManagedSocket::completeWrite>(shared_from_this()));
}
} else if(time::now() > lastWrite + time::seconds(60)) {
disconnect(Util::REASON_WRITE_TIMEOUT);
}
}
void ManagedSocket::completeWrite(const boost::system::error_code& ec, size_t bytes) throw() {
lastWrite = time::not_a_date_time;
if(!ec) {
sm.getStats().sendBytes += bytes;
sm.getStats().sendCalls++;
while(bytes > 0) {
BufferPtr& p = *outBuf.begin();
if(p->size() <= bytes) {
bytes -= p->size();
outBuf.erase(outBuf.begin());
} else {
p = make_shared<Buffer>(p->data() + bytes, p->size() - bytes);
bytes = 0;
}
}
if(!overflow.is_not_a_date_time()) {
size_t left = getQueuedBytes();
if(left < sm.getMaxBufferSize()) {
overflow = time::not_a_date_time;
}
}
if(disconnecting() && outBuf.empty()) {
sock->shutdown(Keeper(shared_from_this()));
} else {
prepareWrite();
}
} else {
fail(Util::REASON_SOCKET_ERROR, ec.message());
}
}
void ManagedSocket::prepareRead() throw() {
// We first send in an empty buffer to get notification when there's data available
sock->prepareRead(BufferPtr(), Handler<&ManagedSocket::prepareRead2>(shared_from_this()));
}
void ManagedSocket::prepareRead2(const boost::system::error_code& ec, size_t) throw() {
if(!ec) {
// ADC commands are typically small - using a small buffer
// helps with fairness
// Calling available() on an ASIO socket seems to be terribly slow
// Also, we might end up here if the socket has been closed, in which
// case available would return 0 bytes...
// We can't make a synchronous receive here because when using SSL
// there might be data on the socket that won't translate into user data
// and thus read_some will block
// If there's no user data, this will effectively post a read operation
// with a buffer and waste memory...to be continued.
inBuf = make_shared<Buffer>(64);
sock->prepareRead(inBuf, Handler<&ManagedSocket::completeRead>(shared_from_this()));
} else {
fail(Util::REASON_SOCKET_ERROR, ec.message());
}
}
void ManagedSocket::completeRead(const boost::system::error_code& ec, size_t bytes) throw() {
if(!ec) {
try {
sm.getStats().recvBytes += bytes;
sm.getStats().recvCalls++;
inBuf->resize(bytes);
if(dataHandler) {
dataHandler(inBuf);
}
inBuf.reset();
prepareRead();
} catch(const boost::system::system_error& e) {
fail(Util::REASON_SOCKET_ERROR, e.code().message());
}
} else {
inBuf.reset();
fail(Util::REASON_SOCKET_ERROR, ec.message());
}
}
void ManagedSocket::completeAccept(const boost::system::error_code& ec) throw() {
if(!ec) {
if(connectedHandler)
connectedHandler();
sock->init(std::bind(&ManagedSocket::ready, shared_from_this()));
} else {
fail(Util::REASON_SOCKET_ERROR, ec.message());
}
}
void ManagedSocket::ready() throw() {
if(readyHandler)
readyHandler();
prepareRead();
}
void ManagedSocket::fail(Util::Reason reason, const std::string &info) throw() {
if(failedHandler) {
failedHandler(reason, info);
// using nullptr fails on older GCCs for which we're using nullptr.h; using 0 fails on VS...
#ifndef FAKE_NULLPTR
connectedHandler = nullptr;
readyHandler = nullptr;
dataHandler = nullptr;
failedHandler = nullptr;
#else
connectedHandler = 0;
readyHandler = 0;
dataHandler = 0;
failedHandler = 0;
#endif
}
}
struct Reporter {
Reporter(ManagedSocketPtr ms, void (ManagedSocket::*f)(Util::Reason reason, const std::string &info), Util::Reason reason, const std::string &info) :
ms(ms), f(f), reason(reason), info(info) { }
void operator()() { (ms.get()->*f)(reason, info); }
ManagedSocketPtr ms;
void (ManagedSocket::*f)(Util::Reason reason, const std::string &info);
Util::Reason reason;
std::string info;
};
void ManagedSocket::disconnect(Util::Reason reason, const std::string &info) throw() {
if(disconnecting()) {
return;
}
const auto timeout = sm.getDisconnectTimeout();
disc = time::now() + time::millisec(timeout);
sm.addJob(Reporter(shared_from_this(), &ManagedSocket::fail, reason, info));
if(!writing()) {
sock->shutdown(Keeper(shared_from_this()));
}
sm.addJob(timeout, Disconnector(sock));
}
bool ManagedSocket::disconnecting() const {
return !disc.is_not_a_date_time();
}
bool ManagedSocket::writing() const {
return !lastWrite.is_not_a_date_time();
}
}

117
src/adchpp/ManagedSocket.h Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_MANAGEDSOCKET_H
#define ADCHPP_MANAGEDSOCKET_H
#include "common.h"
#include "forward.h"
#include "Signal.h"
#include "Util.h"
#include "Buffer.h"
#include "AsyncStream.h"
#include "TimeUtil.h"
namespace adchpp {
/**
* An asynchronous socket managed by SocketManager.
*/
class ManagedSocket : private boost::noncopyable, public enable_shared_from_this<ManagedSocket> {
public:
ManagedSocket(SocketManager &sm, const AsyncStreamPtr& sock_);
/** Asynchronous write */
ADCHPP_DLL void write(const BufferPtr& buf, bool lowPrio = false) throw();
/** Returns the number of bytes in the output buffer; buffers must be locked */
ADCHPP_DLL size_t getQueuedBytes() const;
/** Asynchronous disconnect. Pending data will be written within the limits of the
* DisconnectTimeout setting, but no more data will be read. */
ADCHPP_DLL void disconnect(Util::Reason reason, const std::string &info = Util::emptyString) throw();
const std::string& getIp() const { return ip; }
void setIp(const std::string& ip_) { ip = ip_; }
typedef std::function<void()> ConnectedHandler;
void setConnectedHandler(const ConnectedHandler& handler) { connectedHandler = handler; }
typedef std::function<void()> ReadyHandler;
void setReadyHandler(const ReadyHandler& handler) { readyHandler = handler; }
typedef std::function<void(const BufferPtr&)> DataHandler;
void setDataHandler(const DataHandler& handler) { dataHandler = handler; }
typedef std::function<void(Util::Reason, const std::string &)> FailedHandler;
void setFailedHandler(const FailedHandler& handler) { failedHandler = handler; }
time::ptime getOverflow() { return overflow; }
time::ptime getLastWrite() { return lastWrite; }
~ManagedSocket() throw();
private:
friend class SocketManager;
friend class SocketFactory;
void completeAccept(const boost::system::error_code&) throw();
void ready() throw();
void prepareWrite() throw();
void completeWrite(const boost::system::error_code& ec, size_t bytes) throw();
void prepareRead() throw();
void prepareRead2(const boost::system::error_code& ec, size_t bytes) throw();
void completeRead(const boost::system::error_code& ec, size_t bytes) throw();
void fail(Util::Reason reason, const std::string &info) throw();
bool disconnecting() const;
bool writing() const;
AsyncStreamPtr sock;
/** Output buffer, for storing data that's waiting to be transmitted */
BufferList outBuf;
/** Input buffer used when receiving data */
BufferPtr inBuf;
/** Overflow timer, the time when the socket started to overflow */
time::ptime overflow;
/** Time when this socket will be disconnected regardless of buffers */
time::ptime disc;
/** Last time that a write started, 0 if no active write */
time::ptime lastWrite;
std::string ip;
ConnectedHandler connectedHandler;
ReadyHandler readyHandler;
DataHandler dataHandler;
FailedHandler failedHandler;
SocketManager &sm;
};
}
#endif // MANAGEDSOCKET_H

108
src/adchpp/Mutex.h Normal file
View File

@ -0,0 +1,108 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_MUTEX_H_
#define ADCHPP_MUTEX_H_
#include "Thread.h"
namespace adchpp {
template<typename Mutex>
class ScopedLock {
public:
ScopedLock(Mutex& m_) : m(m_) { m.lock(); }
~ScopedLock() { m.unlock(); }
private:
Mutex& m;
};
#if defined(_WIN32)
class RecursiveMutex : private boost::noncopyable {
public:
RecursiveMutex() { InitializeCriticalSection(&cs); }
~RecursiveMutex() { DeleteCriticalSection(&cs); }
void lock() { EnterCriticalSection(&cs); }
void unlock() { LeaveCriticalSection(&cs); }
typedef ScopedLock<RecursiveMutex> Lock;
private:
CRITICAL_SECTION cs;
};
class FastMutex : private boost::noncopyable {
public:
FastMutex() : val(0) { }
~FastMutex() { }
void lock() { while(InterlockedExchange(&val, 1) == 1) Thread::yield(); }
void unlock() { InterlockedExchange(&val, 0); }
typedef ScopedLock<FastMutex> Lock;
private:
long val;
};
#elif defined(HAVE_PTHREAD)
class RecursiveMutex : private boost::noncopyable {
public:
RecursiveMutex() throw() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mtx, &attr);
pthread_mutexattr_destroy(&attr);
}
~RecursiveMutex() throw() { pthread_mutex_destroy(&mtx); }
void lock() throw() { pthread_mutex_lock(&mtx); }
void unlock() throw() { pthread_mutex_unlock(&mtx); }
typedef ScopedLock<RecursiveMutex> Lock;
private:
pthread_mutex_t mtx;
};
class FastMutex : private boost::noncopyable {
public:
FastMutex() throw() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
pthread_mutex_init(&mtx, &attr);
pthread_mutexattr_destroy(&attr);
}
~FastMutex() throw() { pthread_mutex_destroy(&mtx); }
void lock() throw() { pthread_mutex_lock(&mtx); }
void unlock() throw() { pthread_mutex_unlock(&mtx); }
typedef ScopedLock<FastMutex> Lock;
private:
pthread_mutex_t mtx;
};
#else
#error No mutex found
#endif
}
#endif /*MUTEX_H_*/

62
src/adchpp/Plugin.h Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_PLUGIN_H_
#define ADCHPP_PLUGIN_H_
#include "forward.h"
namespace adchpp {
/**
* Public plugin interface, for plugin intercom.
* Plugins that register a public interface must inherit from this class.
* Plugins requesting another plugins interface will get a pointer to this
* class and must upcast it (using dynamic_cast<> and check NULL to be safe).
*/
class Plugin {
public:
virtual ~Plugin() { }
/** @return API version for a plugin (incremented every time API changes) */
virtual int getVersion() = 0;
protected:
Plugin() { }
};
typedef std::function<void (void*)> PluginDataDeleter;
class PluginData {
public:
template<typename T>
static void simpleDataDeleter(void* p) { delete reinterpret_cast<T*>(p); }
private:
friend class PluginManager;
friend class Entity;
PluginData(const PluginDataDeleter& deleter_) : deleter(deleter_) { }
void operator()(void* p) { if(deleter) deleter(p); }
PluginDataDeleter deleter;
};
typedef shared_ptr<PluginData> PluginDataHandle;
}
#endif /* PLUGIN_H_ */

View File

@ -0,0 +1,214 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "PluginManager.h"
#include "SimpleXML.h"
#include "LogManager.h"
#include "SocketManager.h"
#include "version.h"
#include "File.h"
#include "Text.h"
#include "Core.h"
#ifdef _WIN32
#define PLUGIN_EXT _T(".dll")
#define PM_LOAD_LIBRARY(filename) ::LoadLibrary(filename)
#define PM_UNLOAD_LIBRARY(lib) ::FreeLibrary(lib)
#define PM_GET_ADDRESS(lib, name) ::GetProcAddress(lib, name)
#define PM_GET_ERROR_STRING() Util::translateError(GetLastError())
#else
#include "dlfcn.h"
#define PLUGIN_EXT ".so"
#define PM_LOAD_LIBRARY(filename) ::dlopen(filename, RTLD_LAZY | RTLD_GLOBAL)
#define PM_UNLOAD_LIBRARY(lib) ::dlclose(lib)
#define PM_GET_ADDRESS(lib, name) ::dlsym(lib, name)
#define PM_GET_ERROR_STRING() ::dlerror()
#endif
namespace adchpp {
using namespace std;
using std::placeholders::_1;
const string PluginManager::className = "PluginManager";
PluginManager::PluginManager(Core &core) throw() : core(core) {
}
void PluginManager::attention(const function<void()>& f) {
core.addJob(f);
}
void PluginManager::load() {
for(StringIter i = plugins.begin(); i != plugins.end(); ++i) {
loadPlugin(*i + PLUGIN_EXT);
}
}
bool PluginManager::loadPlugin(const string& file) {
if(file.length() < 3) {
return false;
}
plugin_t h;
#ifndef _WIN32
if(!File::isAbsolutePath(file)) {
h = PM_LOAD_LIBRARY((pluginPath + file).c_str());
} else {
h = PM_LOAD_LIBRARY(file.c_str());
}
#else
if(!File::isAbsolutePath(file)) {
h = LoadLibraryEx((pluginPath + file).c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES);
} else {
h = LoadLibraryEx(file.c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES);
}
#endif
if(h == NULL) {
LOG(className, "Failed to load " + Text::utf8ToAcp(file) + ": " + PM_GET_ERROR_STRING());
return false;
}
PLUGIN_GET_VERSION v = (PLUGIN_GET_VERSION)PM_GET_ADDRESS(h, "pluginGetVersion");
if(v != NULL) {
double ver = v();
if(ver == PLUGINVERSION) {
#ifdef _WIN32
// Reload plugin with references resolved...
FreeLibrary(h);
if(!File::isAbsolutePath(file)) {
h = PM_LOAD_LIBRARY((pluginPath + file).c_str());
} else {
h = PM_LOAD_LIBRARY(file.c_str());
}
if(h == NULL) {
LOG(className, "Failed to load " + Text::utf8ToAcp(file) + ": " + PM_GET_ERROR_STRING());
return false;
}
#endif
PLUGIN_LOAD l = (PLUGIN_LOAD)PM_GET_ADDRESS(h, "pluginLoad");
PLUGIN_UNLOAD u = (PLUGIN_UNLOAD)PM_GET_ADDRESS(h, "pluginUnload");
if(l != NULL && u != NULL) {
int i = l(this);
if(i != 0) {
LOG(className, "Failed to load plugin " + Text::utf8ToAcp(file) + " (Error " + Util::toString(i) + ")");
} else {
// Wonderful, we have a plugin...
active.push_back(PluginInfo(h, v, l, u));
LOG(className, Text::utf8ToAcp(file) + " loaded");
return true;
}
} else {
LOG(className, Text::utf8ToAcp(file) + " is not a valid ADCH++ plugin");
}
} else {
LOG(className, Text::utf8ToAcp(file) + " is for another version of ADCH++ (" + Util::toString(ver) + "), please get the correct one from the author");
}
} else {
LOG(className, Text::utf8ToAcp(file) + " is not a valid ADCH++ plugin");
}
PM_UNLOAD_LIBRARY(h);
return false;
}
void PluginManager::shutdown() {
registry.clear();
for(PluginList::reverse_iterator i = active.rbegin(); i != active.rend(); ++i)
i->pluginUnload();
#ifndef HAVE_BROKEN_MTALLOC
for(PluginList::reverse_iterator i = active.rbegin(); i != active.rend(); ++i)
PM_UNLOAD_LIBRARY(i->handle);
#endif
active.clear();
}
PluginManager::CommandDispatch::CommandDispatch(PluginManager& pm, const std::string& name_, const PluginManager::CommandSlot& f_) :
name('+' + name_),
f(f_),
pm(&pm)
{
}
void PluginManager::CommandDispatch::operator()(Entity& e, AdcCommand& cmd, bool& ok) {
if(e.getState() != Entity::STATE_NORMAL) {
return;
}
if(cmd.getCommand() != AdcCommand::CMD_MSG) {
return;
}
if(cmd.getParameters().size() < 1) {
return;
}
StringList l;
Util::tokenize(l, cmd.getParameters()[0], ' ');
if(l[0] != name) {
return;
}
l[0] = name.substr(1);
if(!pm->handleCommand(e, l)) {
return;
}
cmd.setPriority(AdcCommand::PRIORITY_IGNORE);
f(e, l, ok);
}
ClientManager::SignalReceive::Connection PluginManager::onCommand(const std::string& commandName, const CommandSlot& f) {
return core.getClientManager().signalReceive().connect(CommandDispatch(*this, commandName, f));
}
PluginManager::CommandSignal& PluginManager::getCommandSignal(const std::string& commandName) {
CommandHandlers::iterator i = commandHandlers.find(commandName);
if(i == commandHandlers.end())
return commandHandlers.insert(make_pair(commandName, CommandSignal())).first->second;
return i->second;
}
bool PluginManager::handleCommand(Entity& e, const StringList& l) {
CommandHandlers::iterator i = commandHandlers.find(l[0]);
if(i == commandHandlers.end())
return true;
bool ok = true;
i->second(e, l, ok);
return ok;
}
Core &PluginManager::getCore() { return core; }
}

257
src/adchpp/PluginManager.h Normal file
View File

@ -0,0 +1,257 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
/**
* @page PluginAPI Plugin API Information
* @section General General
*
* ADCH++ contains a rather powerful plugin API that can be used to create advanced
* plugins that change or add to ADCH++'s behaviour. Most plugins will need
* PluginManager.h, ClientManager.h and Client.h included to work, even though the
* other header files are available as well (they're more likely to change in future
* versions though). You can use any method that is declared as DLL or is inline, the
* others are meant to be internal to ADCH++, very likely to change/disappear and will
* generate link errors (when compiling under windows anyway). When starting a plugin
* project I strongly recommend that you take one of the existing plugins and modify
* it to your needs (to get all compiler settings and base code right).
*
* @section Versions Versions
*
* Due to C++ name mangling, plugins are generally valid only for a certain version
* of the ADCH++ plugin API. This version usually follows the main ADCH++ version,
* unless a small update is made that I judge shouldn't affect plugins in any way.
* Most of the time, recompiling the plugin should be enough, unless any major changes
* have been made, and your plugin doesn't rely on the nasty internals.
*
* @section Threads Threads
*
* ADCH++ has two main threads running when operating. One handles all network
* communication while the other does all other work (handle protocol data and
* so on). All plugins are run in the worker thread, which is the only thread
* visible to the API. You are only allowed to interact with ADCH++ from this
* thread, as none of the API is thread safe, unless otherwise noted. This has a
* few important consequences. First off, you can assume that your plugin will
* only be called by this thread, which means that you don't have to worry about
* multithreading issues unless you start threads by yourself. Second, any work you
* do in a plugin halts <b>all</b> of ADCH++'s processing (apart from receiving/sending
* buffered data), in other words, don't do any lengthy processing in the on methods,
* as the whole of ADCH++ will suffer. Third, if you indeed start another thread, make
* sure you don't use any API functions from it apart from those explicitly marked
* as thread safe. To indicate from a plugin that you have work to do in the main
* worker thread, call PluginManager::attention().
*/
#ifndef ADCHPP_PLUGINMANAGER_H
#define ADCHPP_PLUGINMANAGER_H
#include "version.h"
#include "Signal.h"
#include "ClientManager.h"
#include "Plugin.h"
namespace adchpp {
class SimpleXML;
#ifdef _WIN32
#ifdef BUILDING_ADCHPP
#define PLUGIN_API
#else
#define PLUGIN_API __declspec(dllexport)
#endif
typedef HMODULE plugin_t;
#else // WIN32
#ifdef BUILDING_ADCHPP
#define PLUGIN_API
#else
#define PLUGIN_API __attribute__ ((visibility("default")))
#endif
typedef void* plugin_t;
#endif // WIN32
/**
* PLUGIN_API double pluginGetVersion()
* This function should just return the constant PLUGINVERSIONFLOAT
* so that the pluginmanager can determine if this plugin should
* be loaded or not
*/
typedef int (*PLUGIN_GET_VERSION)();
/**
* PLUGIN_API void pluginLoad()
* This function is called when the hub is starting up and loading the plugin.
* Here you should load any data your plugin might need and connect to any
* Managers you might be interested in. Note; you also have to connect to
* PluginManager itself to receive its events.
* @return 0 if the plugin was loaded ok, != 0 otherwise (the number will be logged,
* use as error code). Plugin dll will get unloaded without calling pluginUnload if the return
* value is not 0 here.
* @see pluginUnload
*/
typedef int (*PLUGIN_LOAD)(PluginManager *);
/**
* PLUGIN_API void pluginUnload()
* Called when the hub is shutting down
* @see pluginLoad
*/
typedef void (*PLUGIN_UNLOAD)();
class PluginManager
{
public:
typedef std::unordered_map<std::string, shared_ptr<Plugin>> Registry;
/**
* This is a thread-safe method to call when you need to perform some work
* in the main ADCH++ worker thread. Your job will be executed once, when
* time permits.
*/
ADCHPP_DLL void attention(const std::function<void()>& f);
/**
* Get a list of currently loaded plugins
*/
const StringList& getPluginList() const {
return plugins;
}
void setPluginList(const StringList& pluginList) { plugins = pluginList; }
/**
* Get the plugin path as set in adchpp.xml
*/
const std::string& getPluginPath() const {
return pluginPath;
}
void setPluginPath(const std::string& path) { pluginPath = path; }
/**
* Register a plugin data type to be used with Client::setPSD and friends.
* When data is removed, the deleter function will automatically be called
* with the data as parameter, allowing automatic life cycle managment for
* plugin-specific data.
*/
PluginDataHandle registerPluginData(const PluginDataDeleter& deleter_) { return PluginDataHandle(new PluginData(deleter_)); }
/**
* Register a plugin interface under a name.
* @return false if name was already registered and call fails
*/
bool registerPlugin(const std::string& name, shared_ptr<Plugin> ptr) {
return registry.insert(std::make_pair(name, ptr)).second;
}
/** @return True if the plugin existed and was thus unregistered */
bool unregisterPlugin(const std::string& name) {
return registry.erase(name) > 0;
}
/**
* @return Plugin interface, or an empty pointer if not found
*/
shared_ptr<Plugin> getPlugin(const std::string& name) {
auto i = registry.find(name);
return i == registry.end() ? shared_ptr<Plugin>() : i->second;
}
/**
* The full map of registered plugins.
*/
const Registry& getPlugins() const {
return registry;
}
typedef SignalTraits<void (Entity&, const StringList&, bool&)>::Signal CommandSignal;
typedef CommandSignal::Slot CommandSlot;
/**
* Utility function to handle +-commands from clients
* The parameters are the same as ClientManager::signalReceive, only that the parameters will
* have been parsed already, and the function will only be called if the command name matches
*/
ADCHPP_DLL ClientManager::SignalReceive::Connection onCommand(const std::string& commandName, const CommandSlot& f);
/// Handle +-commands set by another script, and possibly prevent them from being dispatched
ADCHPP_DLL CommandSignal& getCommandSignal(const std::string& commandName);
/** @internal */
void load();
/** @internal */
void shutdown();
ADCHPP_DLL Core &getCore();
private:
friend class Core;
PluginManager(Core &core) throw();
class PluginInfo {
public:
PluginInfo(plugin_t h, PLUGIN_GET_VERSION v, PLUGIN_LOAD l, PLUGIN_UNLOAD u) :
handle(h), pluginGetVersion(v), pluginLoad(l), pluginUnload(u) { }
plugin_t handle;
PLUGIN_GET_VERSION pluginGetVersion;
PLUGIN_LOAD pluginLoad;
PLUGIN_UNLOAD pluginUnload;
};
struct CommandDispatch {
CommandDispatch(PluginManager &pm, const std::string& name_, const PluginManager::CommandSlot& f_);
void operator()(Entity& e, AdcCommand& cmd, bool& ok);
private:
std::string name;
PluginManager::CommandSlot f;
PluginManager *pm;
};
friend struct CommandDispatch;
typedef std::vector<PluginInfo> PluginList;
typedef PluginList::iterator PluginIter;
PluginList active;
Registry registry;
StringList plugins;
std::string pluginPath;
Core &core;
static const std::string className;
bool loadPlugin(const std::string& file);
typedef std::unordered_map<std::string, CommandSignal> CommandHandlers;
CommandHandlers commandHandlers;
bool handleCommand(Entity& e, const StringList& l);
};
}
#endif // PLUGINMANAGER_H

94
src/adchpp/Pool.h Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_POOL_H
#define ADCHPP_POOL_H
#include "Mutex.h"
namespace adchpp {
template<class T>
struct PoolDummy {
void operator()(T&) { }
};
template<typename T, class Clear = PoolDummy<T> >
class SimplePool {
public:
SimplePool() : busy(0) { }
~SimplePool() { dcdebug("Busy pool objects: %d\n", (int)busy); }
T* get() {
busy++;
if(!free.empty()) {
T* tmp = free.back();
free.pop_back();
return tmp;
} else {
return new T;
}
}
void put(T* item) {
dcassert(busy > 0);
busy--;
Clear()(*item);
// Remove some objects every now and then...
if(free.size() > (2*busy) && free.size() > 32) {
dcdebug("Clearing pool\n");
while(free.size() > busy / 2) {
delete free.back();
free.pop_back();
}
}
free.push_back(item);
}
private:
size_t busy;
std::vector<T*> free;
};
/** A thread safe object pool */
template<class T, class Clear = PoolDummy<T> >
class Pool {
public:
Pool() { }
~Pool() { }
T* get() {
FastMutex::Lock l(mtx);
return pool.get();
}
void put(T* obj) {
FastMutex::Lock l(mtx);
pool.put(obj);
}
private:
Pool(const Pool&);
Pool& operator=(const Pool&);
FastMutex mtx;
SimplePool<T, Clear> pool;
};
}
#endif //POOL_H_

68
src/adchpp/SConscript Normal file
View File

@ -0,0 +1,68 @@
# vim: set filetype=py
def getRevision(env):
"""Attempt to get information about the repository, via the "hg log"
command. Its output is formatted via the "-T" parameter (see "hg templates"
for details).
:return: Version information string, or "[unknown]" on failure.
:rtype: str.
"""
try:
import subprocess
ret = subprocess.check_output(
'hg log -r tip -T "{node | short} - {date | isodate}"',
shell=True
)
if ret:
return ret
except:
pass
return '[unknown]'
Import('dev source_path')
env, target, sources = dev.prepare_build(source_path, 'adchpp', shared_precompiled_header = 'adchpp')
env.Append(CPPPATH = ['.'])
env.Append(CPPDEFINES=["BUILDING_ADCHPP=1"])
if env['CC'] == 'cl': # MSVC
env.Append(LIBS = ['advapi32', 'user32'])
if 'HAVE_DL' in env['CPPDEFINES']:
env.Append(LIBS = ['dl'])
if 'HAVE_PTHREAD' in env['CPPDEFINES']:
env.Append(LIBS = ['pthread'])
if 'HAVE_OPENSSL' in env['CPPDEFINES']:
if dev.is_win32():
if env['CC'] == 'cl': # MSVC
if env['mode'] == 'debug':
env.Prepend(LIBS = ['ssleay32d', 'libeay32d'])
else:
env.Prepend(LIBS = ['ssleay32', 'libeay32'])
else:
env.Prepend(LIBS = ['ssl', 'crypto'])
env.Append(LIBS = ['gdi32']) # something in OpenSSL uses CreateDC etc...
env.Append(CPPPATH=['#/openssl/include'])
openssl_lib = '#/openssl/lib/'
if env['arch'] != 'x86':
openssl_lib += env['arch'] + '/'
env.Append(LIBPATH=[openssl_lib])
else:
env.Prepend(LIBS = ['ssl', 'crypto'])
for i, source in enumerate(sources):
if source.find("version.cpp") != -1:
rev = ['ADCHPP_REVISION=' + getRevision(env)]
sources[i] = env.SharedObject(source, CPPDEFINES=env['CPPDEFINES'] + rev)
headers=dev.get_sources(source_path, "*.h")
ret = env.SharedLibrary(target, sources)
Return('ret')

45
src/adchpp/ServerInfo.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_SERVER_INFO_H
#define ADCHPP_SERVER_INFO_H
namespace adchpp {
struct ServerInfo {
std::string ip;
std::string port;
struct TLSInfo {
std::string cert;
std::string pkey;
std::string trustedPath;
std::string dh;
private:
friend struct ServerInfo;
bool secure() const {
return !cert.empty() && !pkey.empty() && !trustedPath.empty() && !dh.empty();
}
} TLSParams;
bool secure() const { return TLSParams.secure(); }
};
}
#endif

124
src/adchpp/Signal.h Normal file
View File

@ -0,0 +1,124 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_SIGNAL_H
#define ADCHPP_SIGNAL_H
namespace adchpp {
struct Connection : private boost::noncopyable {
public:
Connection() { }
virtual ~Connection() { }
virtual void disconnect() = 0;
};
typedef std::unique_ptr<Connection> ConnectionPtr;
template<typename F>
class Signal {
public:
typedef std::function<F> Slot;
typedef std::list<Slot> SlotList;
typedef F FunctionType;
template<typename T0>
void operator()(T0&& t0) {
for(auto i = slots.begin(), iend = slots.end(); i != iend;) {
(*i++)(std::forward<T0>(t0));
}
}
template<typename T0, typename T1>
void operator()(T0&& t0, T1&& t1) {
for(auto i = slots.begin(), iend = slots.end(); i != iend;) {
(*i++)(std::forward<T0>(t0), std::forward<T1>(t1));
}
}
template<typename T0, typename T1, typename T2>
void operator()(T0&& t0, T1&& t1, T2&& t2) {
for(auto i = slots.begin(), iend = slots.end(); i != iend;) {
(*i++)(std::forward<T0>(t0), std::forward<T1>(t1), std::forward<T2>(t2));
}
}
template<typename T>
ConnectionPtr connect(const T& f) { return ConnectionPtr(new SlotConnection(this, slots.insert(slots.end(), f))); }
~Signal() { }
private:
SlotList slots;
void disconnect(const typename SlotList::iterator& i) {
slots.erase(i);
}
struct SlotConnection : public Connection {
SlotConnection(Signal<F>* sig_, const typename SlotList::iterator& i_) : sig(sig_), i(i_) { }
virtual void disconnect() { if(sig) sig->disconnect(i), sig = 0; }
Signal<F>* sig;
typename Signal<F>::SlotList::iterator i;
};
};
struct ManagedConnection : private boost::noncopyable {
ManagedConnection(ConnectionPtr&& conn_) : conn(move(conn_)) {
}
void disconnect() {
if(conn.get()) {
conn->disconnect();
conn.reset();
}
}
void release() {
conn.reset();
}
~ManagedConnection() {
disconnect();
}
private:
ConnectionPtr conn;
};
typedef shared_ptr<ManagedConnection> ManagedConnectionPtr;
template<typename F1, typename F2>
inline ManagedConnectionPtr manage(Signal<F1>* signal, const F2& f) {
return make_shared<ManagedConnection>(signal->connect(f));
}
inline ManagedConnectionPtr manage(ConnectionPtr && conn) {
return make_shared<ManagedConnection>(move(conn));
}
template<typename F>
struct SignalTraits {
typedef adchpp::Signal<F> Signal;
typedef adchpp::ConnectionPtr Connection;
typedef adchpp::ManagedConnectionPtr ManagedConnection;
};
}
#endif // SIGNAL_H

349
src/adchpp/SimpleXML.cpp Normal file
View File

@ -0,0 +1,349 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "SimpleXML.h"
namespace adchpp {
using namespace std;
SimpleXML::SimpleXML(int numAttribs) : attribs(numAttribs), found(false) {
root = current = new Tag("BOGUSROOT", Util::emptyString, NULL);
}
SimpleXML::~SimpleXML() {
delete root;
}
void SimpleXML::escape(string& aString, bool aAttrib, bool aLoading /* = false */) {
string::size_type i = 0;
const char* chars = aAttrib ? "<&>'\"" : "<&>";
if(aLoading) {
while((i = aString.find('&', i)) != string::npos) {
if(aString.compare(i+1, 3, "lt;") == 0) {
aString.replace(i, 4, 1, '<');
} else if(aString.compare(i+1, 4, "amp;") == 0) {
aString.replace(i, 5, 1, '&');
} else if(aString.compare(i+1, 3, "gt;") == 0) {
aString.replace(i, 4, 1, '>');
} else if(aAttrib) {
if(aString.compare(i+1, 5, "apos;") == 0) {
aString.replace(i, 6, 1, '\'');
} else if(aString.compare(i+1, 5, "quot;") == 0) {
aString.replace(i, 6, 1, '"');
}
}
i++;
}
i = 0;
if( (i = aString.find('\n')) != string::npos) {
if(i > 0 && aString[i-1] != '\r') {
// This is a unix \n thing...convert it...
i = 0;
while( (i = aString.find('\n', i) ) != string::npos) {
if(aString[i-1] != '\r')
aString.insert(i, 1, '\r');
i+=2;
}
}
}
} else {
while( (i = aString.find_first_of(chars, i)) != string::npos) {
switch(aString[i]) {
case '<': aString.replace(i, 1, "&lt;"); i+=4; break;
case '&': aString.replace(i, 1, "&amp;"); i+=5; break;
case '>': aString.replace(i, 1, "&gt;"); i+=4; break;
case '\'': aString.replace(i, 1, "&apos;"); i+=6; break;
case '"': aString.replace(i, 1, "&quot;"); i+=6; break;
default: dcasserta(0);
}
}
}
}
void SimpleXML::Tag::appendAttribString(string& tmp) {
for(AttribIter i = attribs.begin(); i!= attribs.end(); ++i) {
tmp.append(i->first);
tmp.append("=\"", 2);
if(needsEscape(i->second, true)) {
string tmp2(i->second);
escape(tmp2, true);
tmp.append(tmp2);
} else {
tmp.append(i->second);
}
tmp.append("\" ", 2);
}
tmp.erase(tmp.size()-1);
}
string SimpleXML::Tag::toXML(int indent) {
if(children.empty() && data.empty()) {
string tmp;
tmp.reserve(indent + name.length() + 30);
tmp.append(indent, '\t');
tmp.append(1, '<');
tmp.append(name);
tmp.append(1, ' ');
appendAttribString(tmp);
tmp.append("/>\r\n", 4);
return tmp;
} else {
string tmp;
tmp.append(indent, '\t');
tmp.append(1, '<');
tmp.append(name);
tmp.append(1, ' ');
appendAttribString(tmp);
if(children.empty()) {
tmp.append(1, '>');
if(needsEscape(data, false)) {
string tmp2(data);
escape(tmp2, false);
tmp.append(tmp2);
} else {
tmp.append(data);
}
} else {
tmp.append(">\r\n", 3);
for(Iter i = children.begin(); i!=children.end(); ++i) {
tmp.append((*i)->toXML(indent + 1));
}
tmp.append(indent, '\t');
}
tmp.append("</", 2);
tmp.append(name);
tmp.append(">\r\n", 3);
return tmp;
}
}
bool SimpleXML::findChild(const string& aName) const throw() {
dcassert(current != NULL);
if(found && currentChild != current->children.end())
currentChild++;
while(currentChild!=current->children.end()) {
if(aName.empty() || (*currentChild)->name == aName) {
found = true;
return true;
} else
currentChild++;
}
return false;
}
void SimpleXML::stepIn() const throw(SimpleXMLException) {
checkChildSelected();
current = *currentChild;
currentChild = current->children.begin();
found = false;
}
void SimpleXML::stepOut() const throw(SimpleXMLException) {
if(current == root)
throw SimpleXMLException("Already at lowest level");
dcassert(current->parent != NULL);
currentChild = find(current->parent->children.begin(), current->parent->children.end(), current);
current = current->parent;
found = true;
}
string::size_type SimpleXML::Tag::loadAttribs(const string& tmp, string::size_type start) throw(SimpleXMLException) {
string::size_type i = start;
string::size_type j;
for(;;) {
j = tmp.find('=', i);
if(j == string::npos) {
throw SimpleXMLException("Missing '=' in " + name);
}
if(tmp[j+1] != '"' && tmp[j+1] != '\'') {
throw SimpleXMLException("Invalid character after '=' in " + name);
}
string::size_type x = j + 2;
string::size_type y = tmp.find(tmp[j+1], x);
if(y == string::npos) {
throw SimpleXMLException("Missing '" + string(1, tmp[j+1]) + "' in " + name);
}
// Ok, we have an attribute...
attribs.push_back(make_pair(tmp.substr(i, j-i), tmp.substr(x, y-x)));
escape(attribs.back().second, true, true);
i = tmp.find_first_not_of("\r\n\t ", y + 1);
if(tmp[i] == '/' || tmp[i] == '>')
return i;
}
}
string::size_type SimpleXML::Tag::fromXML(const string& tmp, string::size_type start, int aa, bool isRoot /* = false */) throw(SimpleXMLException) {
string::size_type i = start;
string::size_type j;
bool hasChildren = false;
dcassert(tmp.size() > 0);
for(;;) {
j = tmp.find('<', i);
if(j == string::npos) {
if(isRoot) {
throw SimpleXMLException("Invalid XML file, missing root tag");
} else {
throw SimpleXMLException("Missing end tag in " + name);
}
}
// Check that we have at least 3 more characters as the shortest valid xml tag is <a/>...
if((j + 3) > tmp.size()) {
throw SimpleXMLException("Missing end tag in " + name);
}
Ptr child = NULL;
i = j + 1;
if(tmp[i] == '?') {
// <? processing instruction ?>, ignore...
i = tmp.find("?>", i);
if(i == string::npos) {
throw SimpleXMLException("Missing '?>' in " + name);
}
i+= 2;
continue;
}
if(tmp[i] == '!' && tmp[i+1] == '-' && tmp[i+2] == '-') {
// <!-- comment -->, ignore...
i = tmp.find("-->", i);
if(i == string::npos) {
throw SimpleXMLException("Missing '-->' in " + name);
}
continue;
}
// Check if we reached the end tag
if(tmp[i] == '/') {
i++;
if( (tmp.compare(i, name.length(), name) == 0) &&
(tmp[i + name.length()] == '>') )
{
if(!hasChildren) {
data = tmp.substr(start, i - start - 2);
escape(data, false, true);
}
return i + name.length() + 1;
} else {
throw SimpleXMLException("Missing end tag in " + name);
}
}
// Alright, we have a real tag for sure...now get the name of it.
j = tmp.find_first_of("\r\n\t />", i);
if(j == string::npos) {
throw SimpleXMLException("Missing '>' in " + name);
}
child = new Tag(tmp.substr(i, j-i), Util::emptyString, this, aa);
// Put it here immideately to avoid mem leaks
children.push_back(child);
if(tmp[j] == ' ')
j = tmp.find_first_not_of("\r\n\t ", j+1);
if(j == string::npos) {
throw SimpleXMLException("Missing '>' in " + name);
}
if(tmp[j] != '/' && tmp[j] != '>') {
// We have attribs...
j = child->loadAttribs(tmp, j);
}
if(tmp[j] == '>') {
// This is a real tag with data etc...
hasChildren = true;
j = child->fromXML(tmp, j+1, aa);
} else {
// A simple tag (<xxx/>
j++;
}
i = j;
if(isRoot) {
if(tmp.find('<', i) != string::npos) {
throw SimpleXMLException("Invalid XML file, multiple root tags");
}
return tmp.length();
}
}
}
void SimpleXML::addTag(const string& aName, const string& aData /* = "" */) throw(SimpleXMLException) {
if(aName.empty()) {
throw SimpleXMLException("Empty tag names not allowed");
}
if(current == root) {
if(current->children.empty()) {
current->children.push_back(new Tag(aName, aData, root, attribs));
currentChild = current->children.begin();
} else {
throw SimpleXMLException("Only one root tag allowed");
}
} else {
current->children.push_back(new Tag(aName, aData, current, attribs));
currentChild = current->children.end() - 1;
}
}
void SimpleXML::addAttrib(const string& aName, const string& aData) throw(SimpleXMLException) {
if(current==root)
throw SimpleXMLException("No tag is currently selected");
current->attribs.push_back(make_pair(aName, aData));
}
void SimpleXML::addChildAttrib(const string& aName, const string& aData) throw(SimpleXMLException) {
checkChildSelected();
(*currentChild)->attribs.push_back(make_pair(aName, aData));
}
void SimpleXML::fromXML(const string& aXML) throw(SimpleXMLException) {
if(root) {
delete root;
}
root = new Tag("BOGUSROOT", Util::emptyString, NULL, 0);
root->fromXML(aXML, 0, attribs, true);
if(root->children.size() != 1) {
throw SimpleXMLException("Invalid XML file, missing or multiple root tags");
}
current = root;
resetCurrentChild();
}
}

191
src/adchpp/SimpleXML.h Normal file
View File

@ -0,0 +1,191 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_SIMPLEXML_H
#define ADCHPP_SIMPLEXML_H
#include "Exception.h"
#include "Util.h"
namespace adchpp {
STANDARD_EXCEPTION(SimpleXMLException);
/**
* A simple XML class that loads an XML-ish structure into an internal tree
* and allows easy access to each element through a "current location".
*/
class SimpleXML : private boost::noncopyable
{
public:
ADCHPP_DLL SimpleXML(int numAttribs = 0);
ADCHPP_DLL ~SimpleXML();
ADCHPP_DLL void addTag(const std::string& aName, const std::string& aData = Util::emptyString) throw(SimpleXMLException);
void addTag(const std::string& aName, int aData) throw(SimpleXMLException) {
addTag(aName, Util::toString(aData));
}
void addTag(const std::string& aName, int64_t aData) throw(SimpleXMLException) {
addTag(aName, Util::toString(aData));
}
template<typename T>
void addAttrib(const std::string& aName, const T& aData) throw(SimpleXMLException) {
addAttrib(aName, Util::toString(aData));
}
ADCHPP_DLL void addAttrib(const std::string& aName, const std::string& aData) throw(SimpleXMLException);
template <typename T>
void addChildAttrib(const std::string& aName, const T& aData) throw(SimpleXMLException) {
addChildAttrib(aName, Util::toString(aData));
}
ADCHPP_DLL void addChildAttrib(const std::string& aName, const std::string& aData) throw(SimpleXMLException);
const std::string& getData() const {
dcassert(current != NULL);
return current->data;
}
ADCHPP_DLL void stepIn() const throw(SimpleXMLException);
ADCHPP_DLL void stepOut() const throw(SimpleXMLException);
void resetCurrentChild() const throw() {
found = false;
dcassert(current != NULL);
currentChild = current->children.begin();
}
ADCHPP_DLL bool findChild(const std::string& aName) const throw();
const std::string& getChildName() const {
checkChildSelected();
return (*currentChild)->name;
}
const std::string& getChildData() const {
checkChildSelected();
return (*currentChild)->data;
}
const std::string& getChildAttrib(const std::string& aName, const std::string& aDefault = Util::emptyString) const {
checkChildSelected();
return (*currentChild)->getAttrib(aName, aDefault);
}
int getIntChildAttrib(const std::string& aName) const {
checkChildSelected();
return Util::toInt(getChildAttrib(aName));
}
int64_t getLongLongChildAttrib(const std::string& aName) const {
checkChildSelected();
return Util::toInt64(getChildAttrib(aName));
}
bool getBoolChildAttrib(const std::string& aName) const {
checkChildSelected();
const std::string& tmp = getChildAttrib(aName);
return (tmp.size() > 0) && tmp[0] == '1';
}
ADCHPP_DLL void fromXML(const std::string& aXML) throw(SimpleXMLException);
std::string toXML() { return (!root->children.empty()) ? root->children[0]->toXML(0) : Util::emptyString; }
ADCHPP_DLL static void escape(std::string& aString, bool aAttrib, bool aLoading = false);
/**
* This is a heurestic for whether escape needs to be called or not. The results are
* only guaranteed for false, i e sometimes true might be returned even though escape
* was not needed...
*/
static bool needsEscape(const std::string& aString, bool aAttrib, bool aLoading = false) {
return ((aLoading) ? aString.find('&') : aString.find_first_of(aAttrib ? "<&>'\"" : "<&>")) != std::string::npos;
}
private:
class Tag {
public:
typedef Tag* Ptr;
typedef std::vector<Ptr> List;
typedef List::iterator Iter;
typedef std::pair<std::string, std::string> StringPair;
typedef std::vector<StringPair> AttribMap;
typedef AttribMap::iterator AttribIter;
/**
* A simple list of children. To find a tag, one must search the entire list.
*/
List children;
/**
* Attributes of this tag. According to the XML standard the names
* must be unique (case-sensitive). (Assuming that we have few attributes here,
* we use a vector instead of a (hash)map to save a few bytes of memory and unnecessary
* calls to the memory allocator...)
*/
AttribMap attribs;
/** Tag name */
std::string name;
/** Tag data, may be empty. */
std::string data;
/** Parent tag, for easy traversal */
Ptr parent;
Tag(const std::string& aName, const std::string& aData, Ptr aParent, int numAttribs = 0) : name(aName), data(aData), parent(aParent) {
if(numAttribs > 0)
attribs.reserve(numAttribs);
}
const std::string& getAttrib(const std::string& aName, const std::string& aDefault = Util::emptyString) {
AttribIter i = find_if(attribs.begin(), attribs.end(), CompareFirst<std::string, std::string>(aName));
return (i == attribs.end()) ? aDefault : i->second;
}
ADCHPP_DLL std::string toXML(int indent);
std::string::size_type fromXML(const std::string& tmp, std::string::size_type start, int aa, bool isRoot = false) throw(SimpleXMLException);
std::string::size_type loadAttribs(const std::string& tmp, std::string::size_type start) throw(SimpleXMLException);
void appendAttribString(std::string& tmp);
/** Delete all children! */
~Tag() {
for(Iter i = children.begin(); i != children.end(); ++i) {
delete *i;
}
}
};
/** Bogus root tag, should be only one child! */
Tag::Ptr root;
/** Current position */
mutable Tag::Ptr current;
mutable Tag::Iter currentChild;
void checkChildSelected() const throw() {
dcassert(current != NULL);
dcassert(currentChild != current->children.end());
}
int attribs;
mutable bool found;
};
}
#endif // SIMPLEXML_H

View File

@ -0,0 +1,385 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "SocketManager.h"
#include "LogManager.h"
#include "ManagedSocket.h"
#include "ServerInfo.h"
#include "SimpleXML.h"
#include "Core.h"
#ifdef HAVE_OPENSSL
#include <boost/asio/ssl.hpp>
#endif
#include <boost/date_time/posix_time/time_parsers.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ip/v6_only.hpp>
namespace adchpp {
using namespace std;
using namespace std::placeholders;
using namespace boost::asio;
using boost::system::error_code;
using boost::system::system_error;
SocketManager::SocketManager(Core &core) :
core(core),
bufferSize(1024),
maxBufferSize(16 * 1024),
overflowTimeout(60 * 1000),
disconnectTimeout(10 * 1000)
{
}
const string SocketManager::className = "SocketManager";
template<typename T>
class SocketStream : public AsyncStream {
public:
template<typename X>
SocketStream(X& x) : sock(x) { }
template<typename X, typename Y>
SocketStream(X& x, Y& y) : sock(x, y) { }
~SocketStream() { dcdebug("SocketStream deleted\n"); }
virtual size_t available() {
return sock.lowest_layer().available();
}
virtual void setOptions(size_t bufferSize) {
sock.lowest_layer().set_option(socket_base::receive_buffer_size(bufferSize));
sock.lowest_layer().set_option(socket_base::send_buffer_size(bufferSize));
}
virtual std::string getIp() {
try { return sock.lowest_layer().remote_endpoint().address().to_string(); }
catch(const system_error&) { return Util::emptyString; }
}
virtual void prepareRead(const BufferPtr& buf, const Handler& handler) {
if(buf) {
sock.async_read_some(buffer(buf->data(), buf->size()), handler);
} else {
sock.async_read_some(null_buffers(), handler);
}
}
virtual size_t read(const BufferPtr& buf) {
return sock.read_some(buffer(buf->data(), buf->size()));
}
virtual void write(const BufferList& bufs, const Handler& handler) {
if(bufs.size() == 1) {
sock.async_write_some(buffer(bufs[0]->data(), bufs[0]->size()), handler);
} else {
size_t n = std::min(bufs.size(), static_cast<size_t>(64));
std::vector<const_buffer> buffers;
buffers.reserve(n);
const size_t maxBytes = 1024;
for(size_t i = 0, total = 0; i < n && total < maxBytes; ++i) {
size_t left = maxBytes - total;
size_t bytes = min(bufs[i]->size(), left);
buffers.push_back(const_buffer(bufs[i]->data(), bytes));
total += bytes;
}
sock.async_write_some(buffers, handler);
}
}
T sock;
};
class SimpleSocketStream : public SocketStream<ip::tcp::socket> {
typedef SocketStream<ip::tcp::socket> Stream;
struct ShutdownHandler {
ShutdownHandler(const Handler& h) : h(h) { }
void operator()() { error_code ec; h(ec, 0); }
Handler h;
};
public:
SimpleSocketStream(boost::asio::io_service& x) : Stream(x) { }
virtual void init(const std::function<void ()>& postInit) {
postInit();
}
virtual void shutdown(const Handler& handler) {
sock.shutdown(ip::tcp::socket::shutdown_send);
sock.get_io_service().post(ShutdownHandler(handler));
}
virtual void close() {
// Abortive close, just go away...
if(sock.is_open()) {
error_code ec;
sock.close(ec); // Ignore errors
}
}
};
#ifdef HAVE_OPENSSL
class TLSSocketStream : public SocketStream<ssl::stream<ip::tcp::socket> > {
typedef SocketStream<ssl::stream<ip::tcp::socket> > Stream;
struct ShutdownHandler {
ShutdownHandler(const Handler& h) : h(h) { }
void operator()(const error_code &ec) { h(ec, 0); }
Handler h;
};
public:
TLSSocketStream(io_service& x, ssl::context& y) : Stream(x, y) { }
virtual void init(const std::function<void ()>& postInit) {
sock.async_handshake(ssl::stream_base::server, std::bind(&TLSSocketStream::handleHandshake,
this, std::placeholders::_1, postInit));
}
virtual void shutdown(const Handler& handler) {
sock.async_shutdown(ShutdownHandler(handler));
}
virtual void close() {
// Abortive close, just go away...
if(sock.lowest_layer().is_open()) {
error_code ec;
sock.lowest_layer().close(ec); // Ignore errors
}
}
private:
void handleHandshake(const error_code& ec, const std::function<void ()>& postInit) {
if(!ec) {
postInit();
}
}
};
#endif
static string formatEndpoint(const ip::tcp::endpoint& ep) {
return (ep.address().is_v4() ? ep.address().to_string() + ':' : '[' + ep.address().to_string() + "]:")
+ Util::toString(ep.port());
}
class SocketFactory : public enable_shared_from_this<SocketFactory>, boost::noncopyable {
public:
SocketFactory(SocketManager& sm, const SocketManager::IncomingHandler& handler_, const ServerInfo& info, const ip::tcp::endpoint& endpoint) :
sm(sm),
acceptor(sm.io),
handler(handler_)
{
acceptor.open(endpoint.protocol());
acceptor.set_option(socket_base::reuse_address(true));
if(endpoint.protocol() == ip::tcp::v6()) {
acceptor.set_option(ip::v6_only(true));
}
acceptor.bind(endpoint);
acceptor.listen(socket_base::max_connections);
LOGC(sm.getCore(), SocketManager::className,
"Listening on " + formatEndpoint(endpoint) +
" (Encrypted: " + (info.secure() ? "Yes)" : "No)"));
#ifdef HAVE_OPENSSL
if(info.secure()) {
context.reset(new ssl::context(sm.io, ssl::context::sslv23_server));
context->set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3 | ssl::context::single_dh_use);
//context->set_password_callback(boost::bind(&server::get_password, this));
context->use_certificate_chain_file(info.TLSParams.cert);
context->use_private_key_file(info.TLSParams.pkey, ssl::context::pem);
context->use_tmp_dh_file(info.TLSParams.dh);
}
#endif
}
void prepareAccept() {
if(!sm.work.get()) {
return;
}
#ifdef HAVE_OPENSSL
if(context) {
auto s = make_shared<TLSSocketStream>(sm.io, *context);
auto socket = make_shared<ManagedSocket>(sm, s);
acceptor.async_accept(s->sock.lowest_layer(), std::bind(&SocketFactory::handleAccept, shared_from_this(), std::placeholders::_1, socket));
} else {
#endif
auto s = make_shared<SimpleSocketStream>(sm.io);
auto socket = make_shared<ManagedSocket>(sm, s);
acceptor.async_accept(s->sock.lowest_layer(), std::bind(&SocketFactory::handleAccept, shared_from_this(), std::placeholders::_1, socket));
#ifdef HAVE_OPENSSL
}
#endif
}
void handleAccept(const error_code& ec, const ManagedSocketPtr& socket) {
if(!ec) {
socket->sock->setOptions(sm.getBufferSize());
socket->setIp(socket->sock->getIp());
}
completeAccept(ec, socket);
prepareAccept();
}
void completeAccept(const error_code& ec, const ManagedSocketPtr& socket) {
handler(socket);
socket->completeAccept(ec);
}
void close() { acceptor.close(); }
SocketManager &sm;
ip::tcp::acceptor acceptor;
SocketManager::IncomingHandler handler;
#ifdef HAVE_OPENSSL
unique_ptr<ssl::context> context;
#endif
};
int SocketManager::run() {
LOG(SocketManager::className, "Starting");
work.reset(new io_service::work(io));
for(auto i = servers.begin(), iend = servers.end(); i != iend; ++i) {
auto& si = *i;
try {
using ip::tcp;
tcp::resolver r(io);
auto local = r.resolve(tcp::resolver::query(si->ip, si->port,
tcp::resolver::query::address_configured | tcp::resolver::query::passive));
for(auto i = local; i != tcp::resolver::iterator(); ++i) {
SocketFactoryPtr factory = make_shared<SocketFactory>(*this, incomingHandler, *si, *i);
factory->prepareAccept();
factories.push_back(factory);
}
} catch(const std::exception& e) {
LOG(SocketManager::className, "Error while loading server on port " + si->port +": " + e.what());
}
}
io.run();
io.reset();
return 0;
}
void SocketManager::closeFactories() {
for(auto i = factories.begin(), iend = factories.end(); i != iend; ++i) {
(*i)->close();
}
factories.clear();
}
void SocketManager::addJob(const Callback& callback) throw() {
io.post(callback);
}
void SocketManager::addJob(const long msec, const Callback& callback) {
addJob(boost::posix_time::milliseconds(msec), callback);
}
void SocketManager::addJob(const std::string& time, const Callback& callback) {
addJob(boost::posix_time::duration_from_string(time), callback);
}
SocketManager::Callback SocketManager::addTimedJob(const long msec, const Callback& callback) {
return addTimedJob(boost::posix_time::milliseconds(msec), callback);
}
SocketManager::Callback SocketManager::addTimedJob(const std::string& time, const Callback& callback) {
return addTimedJob(boost::posix_time::duration_from_string(time), callback);
}
void SocketManager::addJob(const deadline_timer::duration_type& duration, const Callback& callback) {
setTimer(make_shared<timer_ptr::element_type>(io, duration), deadline_timer::duration_type(), new Callback(callback));
}
SocketManager::Callback SocketManager::addTimedJob(const deadline_timer::duration_type& duration, const Callback& callback) {
timer_ptr timer = make_shared<timer_ptr::element_type>(io, duration);
Callback* pCallback = new Callback(callback); // create a separate callback on the heap to avoid shutdown crashes
setTimer(timer, duration, pCallback);
return std::bind(&SocketManager::cancelTimer, this, timer, pCallback);
}
void SocketManager::setTimer(timer_ptr timer, const deadline_timer::duration_type& duration, Callback* callback) {
timer->async_wait(std::bind(&SocketManager::handleWait, this, timer, duration, std::placeholders::_1, callback));
}
void SocketManager::handleWait(timer_ptr timer, const deadline_timer::duration_type& duration, const error_code& error, Callback* callback) {
bool run_on = duration.ticks();
if(!error) {
if(run_on) {
// re-schedule the timer
timer->expires_at(timer->expires_at() + duration);
setTimer(timer, duration, callback);
}
addJob(*callback);
}
if(!run_on) {
// this timer was only running once, so it has no cancel function
delete callback;
}
}
void SocketManager::cancelTimer(timer_ptr timer, Callback* callback) {
if(timer.get()) {
error_code ec;
timer->cancel(ec);
}
delete callback;
}
void SocketManager::shutdown() {
closeFactories();
work.reset();
io.stop();
}
void SocketManager::onLoad(const SimpleXML& xml) throw() {
servers.clear();
}
}

133
src/adchpp/SocketManager.h Normal file
View File

@ -0,0 +1,133 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_SOCKETMANAGER_H
#define ADCHPP_SOCKETMANAGER_H
#include "common.h"
#include "forward.h"
#include "ServerInfo.h"
#include <boost/asio/io_service.hpp>
#include <boost/asio/deadline_timer.hpp>
namespace adchpp {
struct SocketStats {
SocketStats() : queueCalls(0), queueBytes(0), sendCalls(0), sendBytes(0), recvCalls(0), recvBytes(0) { }
size_t queueCalls;
int64_t queueBytes;
size_t sendCalls;
int64_t sendBytes;
int64_t recvCalls;
int64_t recvBytes;
};
class SocketManager {
public:
typedef std::function<void()> Callback;
/** execute a function asynchronously */
ADCHPP_DLL void addJob(const Callback& callback) throw();
/** execute a function after the specified amount of time
* @param msec milliseconds
*/
ADCHPP_DLL void addJob(const long msec, const Callback& callback);
/** execute a function after the specified amount of time
* @param time a string that obeys to the "[-]h[h][:mm][:ss][.fff]" format
*/
ADCHPP_DLL void addJob(const std::string& time, const Callback& callback);
/** execute a function at regular intervals
* @param msec milliseconds
* @return function one must call to cancel the timer (its callback will still be executed)
*/
ADCHPP_DLL Callback addTimedJob(const long msec, const Callback& callback);
/** execute a function at regular intervals
* @param time a string that obeys to the "[-]h[h][:mm][:ss][.fff]" format
* @return function one must call to cancel the timer (its callback will still be executed)
*/
ADCHPP_DLL Callback addTimedJob(const std::string& time, const Callback& callback);
void shutdown();
void setServers(const ServerInfoList& servers_) { servers = servers_; }
typedef std::function<void (const ManagedSocketPtr&)> IncomingHandler;
void setIncomingHandler(const IncomingHandler& handler) { incomingHandler = handler; }
int run();
void setBufferSize(size_t newSize) { bufferSize = newSize; }
size_t getBufferSize() const { return bufferSize; }
void setMaxBufferSize(size_t newSize) { maxBufferSize = newSize; }
size_t getMaxBufferSize() const { return maxBufferSize; }
void setOverflowTimeout(size_t timeout) { overflowTimeout = timeout; }
size_t getOverflowTimeout() const { return overflowTimeout; }
void setDisconnectTimeout(size_t timeout) { disconnectTimeout = timeout; }
size_t getDisconnectTimeout() const { return disconnectTimeout; }
SocketStats &getStats() { return stats; }
Core &getCore() { return core; }
private:
friend class Core;
friend class ManagedSocket;
friend class SocketFactory;
void closeFactories();
Core &core;
boost::asio::io_service io;
std::unique_ptr<boost::asio::io_service::work> work;
SocketStats stats;
ServerInfoList servers;
std::vector<SocketFactoryPtr> factories;
IncomingHandler incomingHandler;
size_t bufferSize; /// Default buffer size used for SO_RCVBUF/SO_SNDBUF
size_t maxBufferSize; /// Max allowed write buffer size for each socket
size_t overflowTimeout;
size_t disconnectTimeout;
static const std::string className;
typedef shared_ptr<boost::asio::deadline_timer> timer_ptr;
void addJob(const boost::asio::deadline_timer::duration_type& duration, const Callback& callback);
Callback addTimedJob(const boost::asio::deadline_timer::duration_type& duration, const Callback& callback);
void setTimer(timer_ptr timer, const boost::asio::deadline_timer::duration_type& duration, Callback* callback);
void handleWait(timer_ptr timer, const boost::asio::deadline_timer::duration_type& duration, const boost::system::error_code& error,
Callback* callback);
void cancelTimer(timer_ptr timer, Callback* callback);
void onLoad(const SimpleXML& xml) throw();
SocketManager(Core &core);
};
}
#endif // SOCKETMANAGER_H

246
src/adchpp/Text.cpp Normal file
View File

@ -0,0 +1,246 @@
/*
* Copyright (C) 2001-2014 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "Text.h"
#include "Util.h"
using namespace std;
namespace adchpp {
int Text::utf8ToWc(const char* str, wchar_t& c) {
const auto c0 = static_cast<uint8_t>(str[0]);
const auto bytes = 2 + !!(c0 & 0x20) + ((c0 & 0x30) == 0x30);
if((c0 & 0xc0) == 0xc0) { // 11xx xxxx
// # bytes of leading 1's; check for 0 next
const auto check_bit = 1 << (7 - bytes);
if (c0 & check_bit)
return -1;
c = (check_bit - 1) & c0;
// 2-4 total, or 1-3 additional, bytes
// Can't run off end of str so long as has sub-0x80-terminator
for (auto i = 1; i < bytes; ++i) {
const auto ci = static_cast<uint8_t>(str[i]);
if ((ci & 0xc0) != 0x80)
return -i;
c = (c << 6) | (ci & 0x3f);
}
// Invalid UTF-8 code points
if (c > 0x10ffff || (c >= 0xd800 && c <= 0xdfff)) {
// "REPLACEMENT CHARACTER": used to replace an incoming character
// whose value is unknown or unrepresentable in Unicode
c = 0xfffd;
return -bytes;
}
return bytes;
} else if ((c0 & 0x80) == 0) { // 0xxx xxxx
c = static_cast<unsigned char>(str[0]);
return 1;
} else { // 10xx xxxx
return -1;
}
dcassert(0);
}
void Text::wcToUtf8(wchar_t c, string& str) {
// https://tools.ietf.org/html/rfc3629#section-3
if(c > 0x10ffff || (c >= 0xd800 && c <= 0xdfff)) {
// Invalid UTF-8 code point
// REPLACEMENT CHARACTER: http://www.fileformat.info/info/unicode/char/0fffd/index.htm
wcToUtf8(0xfffd, str);
} else if(c >= 0x10000) {
str += (char)(0x80 | 0x40 | 0x20 | 0x10 | (c >> 18));
str += (char)(0x80 | ((c >> 12) & 0x3f));
str += (char)(0x80 | ((c >> 6) & 0x3f));
str += (char)(0x80 | (c & 0x3f));
} else if(c >= 0x0800) {
str += (char)(0x80 | 0x40 | 0x20 | (c >> 12));
str += (char)(0x80 | ((c >> 6) & 0x3f));
str += (char)(0x80 | (c & 0x3f));
} else if(c >= 0x0080) {
str += (char)(0x80 | 0x40 | (c >> 6));
str += (char)(0x80 | (c & 0x3f));
} else {
str += (char)c;
}
}
const string& Text::acpToUtf8(const string& str, string& tmp) throw() {
wstring wtmp;
return wideToUtf8(acpToWide(str, wtmp), tmp);
}
const wstring& Text::acpToWide(const string& str, wstring& tmp) throw() {
if(str.empty())
return Util::emptyStringW;
#ifdef _WIN32
int n = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.c_str(), (int)str.length(), NULL, 0);
if(n == 0) {
return Util::emptyStringW;
}
tmp.resize(n);
n = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.c_str(), (int)str.length(), &tmp[0], n);
if(n == 0) {
return Util::emptyStringW;
}
return tmp;
#else
size_t rv;
wchar_t wc;
const char *src = str.c_str();
size_t n = str.length() + 1;
tmp.clear();
tmp.reserve(n);
while(n > 0) {
rv = mbrtowc(&wc, src, n, NULL);
if(rv == 0 || rv == (size_t)-2) {
break;
} else if(rv == (size_t)-1) {
tmp.push_back(L'_');
++src;
--n;
} else {
tmp.push_back(wc);
src += rv;
n -= rv;
}
}
return tmp;
#endif
}
const string& Text::wideToUtf8(const wstring& str, string& tgt) throw() {
if(str.empty()) {
return Util::emptyString;
}
string::size_type n = str.length();
tgt.clear();
for(string::size_type i = 0; i < n; ++i) {
wcToUtf8(str[i], tgt);
}
return tgt;
}
const string& Text::wideToAcp(const wstring& str, string& tmp) throw() {
if(str.empty())
return Util::emptyString;
#ifdef _WIN32
int n = WideCharToMultiByte(CP_ACP, 0, str.c_str(), (int)str.length(), NULL, 0, NULL, NULL);
if(n == 0) {
return Util::emptyString;
}
tmp.resize(n);
n = WideCharToMultiByte(CP_ACP, 0, str.c_str(), (int)str.length(), &tmp[0], n, NULL, NULL);
if(n == 0) {
return Util::emptyString;
}
return tmp;
#else
const wchar_t* src = str.c_str();
int n = wcsrtombs(NULL, &src, 0, NULL);
if(n < 1) {
return Util::emptyString;
}
src = str.c_str();
tmp.resize(n);
n = wcsrtombs(&tmp[0], &src, n, NULL);
if(n < 1) {
return Util::emptyString;
}
return tmp;
#endif
}
bool Text::validateUtf8(const string& str) throw() {
string::size_type i = 0;
while(i < str.length()) {
wchar_t dummy = 0;
int j = utf8ToWc(&str[i], dummy);
if(j < 0)
return false;
i += j;
}
return true;
}
const string& Text::utf8ToAcp(const string& str, string& tmp) throw() {
wstring wtmp;
return wideToAcp(utf8ToWide(str, wtmp), tmp);
}
const wstring& Text::utf8ToWide(const string& str, wstring& tgt) throw() {
tgt.reserve(str.length());
string::size_type n = str.length();
for(string::size_type i = 0; i < n; ) {
wchar_t c = 0;
int x = utf8ToWc(str.c_str() + i, c);
if(x < 0) {
tgt += '_';
i += abs(x);
} else {
i += x;
tgt += c;
}
}
return tgt;
}
string Text::acpToUtf8(const string& str) throw() {
string tmp;
return acpToUtf8(str, tmp);
}
wstring Text::acpToWide(const string& str) throw() {
wstring tmp;
return acpToWide(str, tmp);
}
string Text::utf8ToAcp(const string& str) throw() {
string tmp;
return utf8ToAcp(str, tmp);
}
wstring Text::utf8ToWide(const string& str) throw() {
wstring tmp;
return utf8ToWide(str, tmp);
}
string Text::wideToAcp(const wstring& str) throw() {
string tmp;
return wideToAcp(str, tmp);
}
string Text::wideToUtf8(const wstring& str) throw() {
string tmp;
return wideToUtf8(str, tmp);
}
} // namespace adchpp

68
src/adchpp/Text.h Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2001-2015 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_TEXT_H
#define ADCHPP_TEXT_H
namespace adchpp {
/**
* Text handling routines for ADCH++. ADCH++ internally uses UTF-8 for
* (almost) all string:s, hence all foreign text must be converted
* appropriately...
* acp - ANSI code page used by the system
* wide - wide unicode string
* utf8 - UTF-8 representation of the string
* string - UTF-8 string (most of the time)
* wstring - Wide string
*
* Taken from DC++.
*/
class Text {
typedef std::string string;
typedef std::wstring wstring;
public:
static const string& acpToUtf8(const string& str, string& tmp) throw();
ADCHPP_DLL static string acpToUtf8(const string& str) throw();
static const wstring& acpToWide(const string& str, wstring& tmp) throw();
ADCHPP_DLL static wstring acpToWide(const string& str) throw();
static const string& utf8ToAcp(const string& str, string& tmp) throw();
ADCHPP_DLL static string utf8ToAcp(const string& str) throw();
static const wstring& utf8ToWide(const string& str, wstring& tmp) throw();
ADCHPP_DLL static wstring utf8ToWide(const string& str) throw();
static const string& wideToAcp(const wstring& str, string& tmp) throw();
ADCHPP_DLL static string wideToAcp(const wstring& str) throw();
static const string& wideToUtf8(const wstring& str, string& tmp) throw();
ADCHPP_DLL static string wideToUtf8(const wstring& str) throw();
ADCHPP_DLL static bool validateUtf8(const string& str) throw();
private:
static int utf8ToWc(const char* str, wchar_t& c);
static void wcToUtf8(wchar_t c, string& str);
};
} // namespace dcpp
#endif

79
src/adchpp/Thread.cpp Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "Thread.h"
#include "Util.h"
namespace adchpp {
#ifdef _WIN32
void Thread::start() throw(ThreadException) {
if(isRunning()) {
throw ThreadException(_T("Already running"));
}
DWORD threadId = 0;
if( (threadHandle = ::CreateThread(NULL, 0, &starter, this, 0, &threadId)) == NULL) {
throw ThreadException(Util::translateError(::GetLastError()));
}
}
void Thread::join() throw() {
if(!isRunning()) {
return;
}
::WaitForSingleObject(threadHandle, INFINITE);
::CloseHandle(threadHandle);
threadHandle = INVALID_HANDLE_VALUE;
}
#else // _WIN32
void Thread::start() throw(ThreadException) {
if(isRunning()) {
throw ThreadException(_T("Already running"));
}
// Not all implementations may create threads as joinable by default.
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int result = pthread_create(&t, &attr, &starter, this);
if(result != 0) {
throw ThreadException(Util::translateError(result));
}
pthread_attr_destroy(&attr);
}
void Thread::join() throw() {
if(t == 0)
return;
void* x;
pthread_join(t, &x);
t = 0;
}
#endif
}

107
src/adchpp/Thread.h Normal file
View File

@ -0,0 +1,107 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_THREAD_H
#define ADCHPP_THREAD_H
#ifndef _WIN32
# include <pthread.h>
# include <sched.h>
# include <sys/resource.h>
#include <unistd.h>
#endif
#include "Exception.h"
#include "nullptr.h"
namespace adchpp {
STANDARD_EXCEPTION(ThreadException);
class Thread : private boost::noncopyable
{
public:
ADCHPP_DLL void start() throw(ThreadException);
ADCHPP_DLL void join() throw();
#ifdef _WIN32
enum Priority {
LOW = THREAD_PRIORITY_BELOW_NORMAL,
NORMAL = THREAD_PRIORITY_NORMAL,
HIGH = THREAD_PRIORITY_ABOVE_NORMAL
};
Thread() throw() : threadHandle(INVALID_HANDLE_VALUE) { }
virtual ~Thread() {
if(threadHandle != INVALID_HANDLE_VALUE)
CloseHandle(threadHandle);
}
void setThreadPriority(Priority p) throw() { ::SetThreadPriority(threadHandle, p); }
bool isRunning() throw() { return (threadHandle != INVALID_HANDLE_VALUE); }
static void sleep(uint32_t millis) { ::Sleep(millis); }
static void yield() { ::Sleep(1); }
#elif defined(HAVE_PTHREAD)
enum Priority {
LOW = 1,
NORMAL = 0,
HIGH = -1
};
Thread() throw() : t(0) { }
virtual ~Thread() {
if(t != 0) {
pthread_detach(t);
}
}
void setThreadPriority(Priority p) { setpriority(PRIO_PROCESS, 0, p); }
bool isRunning() { return (t != 0); }
static void sleep(uint32_t millis) { ::usleep(millis*1000); }
static void yield() { ::sched_yield(); }
#else
#error No threading support found
#endif
protected:
virtual int run() = 0;
#ifdef _WIN32
HANDLE threadHandle;
static DWORD WINAPI starter(void* p) {
return static_cast<DWORD>(reinterpret_cast<Thread*>(p)->run());
}
#else
pthread_t t;
static void* starter(void* p) {
// ignore the return value.
reinterpret_cast<Thread*>(p)->run();
return nullptr;
}
#endif
};
}
#endif // THREAD_H

687
src/adchpp/TigerHash.cpp Normal file
View File

@ -0,0 +1,687 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "TigerHash.h"
#include "common.h"
namespace adchpp {
using namespace std;
#define PASSES 3
#define t1 (table)
#define t2 (table+256)
#define t3 (table+256*2)
#define t4 (table+256*3)
#define save_abc \
aa = a; \
bb = b; \
cc = c;
#define round(a,b,c,x,mul) \
c ^= x; \
a -= t1[(uint8_t)(c)] ^ \
t2[(uint8_t)(((uint32_t)(c))>>(2*8))] ^ \
t3[(uint8_t)((c)>>(4*8))] ^ \
t4[(uint8_t)(((uint32_t)((c)>>(4*8)))>>(2*8))] ; \
b += t4[(uint8_t)(((uint32_t)(c))>>(1*8))] ^ \
t3[(uint8_t)(((uint32_t)(c))>>(3*8))] ^ \
t2[(uint8_t)(((uint32_t)((c)>>(4*8)))>>(1*8))] ^ \
t1[(uint8_t)(((uint32_t)((c)>>(4*8)))>>(3*8))]; \
b *= mul;
#define pass(a,b,c,mul) \
round(a,b,c,x0,mul) \
round(b,c,a,x1,mul) \
round(c,a,b,x2,mul) \
round(a,b,c,x3,mul) \
round(b,c,a,x4,mul) \
round(c,a,b,x5,mul) \
round(a,b,c,x6,mul) \
round(b,c,a,x7,mul)
#define key_schedule \
x0 -= x7 ^ _ULL(0xA5A5A5A5A5A5A5A5); \
x1 ^= x0; \
x2 += x1; \
x3 -= x2 ^ ((~x1)<<19); \
x4 ^= x3; \
x5 += x4; \
x6 -= x5 ^ ((~x4)>>23); \
x7 ^= x6; \
x0 += x7; \
x1 -= x0 ^ ((~x7)<<19); \
x2 ^= x1; \
x3 += x2; \
x4 -= x3 ^ ((~x2)>>23); \
x5 ^= x4; \
x6 += x5; \
x7 -= x6 ^ _ULL(0x0123456789ABCDEF);
#define feedforward \
a ^= aa; \
b -= bb; \
c += cc;
#define compress \
save_abc \
for(pass_no=0; pass_no<PASSES; pass_no++) { \
if(pass_no != 0) {key_schedule} \
pass(a,b,c,(pass_no==0?5:pass_no==1?7:9)); \
tmpa=a; a=c; c=b; b=tmpa;} \
feedforward
#define tiger_compress_macro(str, state) \
{ \
register uint64_t a, b, c, tmpa; \
uint64_t aa, bb, cc; \
register uint64_t x0, x1, x2, x3, x4, x5, x6, x7; \
int pass_no; \
\
a = state[0]; \
b = state[1]; \
c = state[2]; \
\
x0=str[0]; x1=str[1]; x2=str[2]; x3=str[3]; \
x4=str[4]; x5=str[5]; x6=str[6]; x7=str[7]; \
\
compress; \
\
state[0] = a; \
state[1] = b; \
state[2] = c; \
}
/* The compress function is a function. Requires smaller cache? */
void TigerHash::tigerCompress(const uint64_t *str, uint64_t state[3]) {
tiger_compress_macro(((const uint64_t*)str), ((uint64_t*)state));
}
void TigerHash::update(const void* data, size_t length) {
size_t tmppos = (uint32_t)(pos & (BLOCK_SIZE-1));
const uint8_t* str = (const uint8_t*)data;
// First empty tmp buffer if possible
if(tmppos > 0) {
size_t n = min(length, BLOCK_SIZE-tmppos);
memcpy(tmp + tmppos, str, n);
str += n;
pos += n;
length -= n;
if((tmppos + n) == BLOCK_SIZE) {
tigerCompress((uint64_t*)tmp, res);
tmppos = 0;
}
}
// So, now either tmp is empty or all data has been consumed...
dcassert(length == 0 || tmppos == 0);
// Process the bulk of data
while(length>=BLOCK_SIZE) {
tigerCompress((uint64_t*)str, res);
str += BLOCK_SIZE;
pos += BLOCK_SIZE;
length -= BLOCK_SIZE;
}
// Copy the rest to the tmp buffer
memcpy(tmp, str, length);
pos += length;
}
uint8_t* TigerHash::finalize() {
size_t tmppos = (size_t)(pos & (BLOCK_SIZE-1));
// Tmp buffer always has at least one pos, otherwise it would have
// been processed in update()
tmp[tmppos++] = 0x01;
if(tmppos > (BLOCK_SIZE - sizeof(uint64_t))) {
memset(tmp + tmppos, 0, BLOCK_SIZE - tmppos);
tigerCompress(((uint64_t*)tmp), res);
memset(tmp, 0, BLOCK_SIZE);
} else {
memset(tmp + tmppos, 0, BLOCK_SIZE - tmppos - sizeof(uint64_t));
}
((uint64_t*)(&(tmp[56])))[0] = pos<<3;
tigerCompress((uint64_t*)tmp, res);
return getResult();
}
uint64_t TigerHash::table[4*256] = {
_ULL(0x02AAB17CF7E90C5E) /* 0 */, _ULL(0xAC424B03E243A8EC) /* 1 */,
_ULL(0x72CD5BE30DD5FCD3) /* 2 */, _ULL(0x6D019B93F6F97F3A) /* 3 */,
_ULL(0xCD9978FFD21F9193) /* 4 */, _ULL(0x7573A1C9708029E2) /* 5 */,
_ULL(0xB164326B922A83C3) /* 6 */, _ULL(0x46883EEE04915870) /* 7 */,
_ULL(0xEAACE3057103ECE6) /* 8 */, _ULL(0xC54169B808A3535C) /* 9 */,
_ULL(0x4CE754918DDEC47C) /* 10 */, _ULL(0x0AA2F4DFDC0DF40C) /* 11 */,
_ULL(0x10B76F18A74DBEFA) /* 12 */, _ULL(0xC6CCB6235AD1AB6A) /* 13 */,
_ULL(0x13726121572FE2FF) /* 14 */, _ULL(0x1A488C6F199D921E) /* 15 */,
_ULL(0x4BC9F9F4DA0007CA) /* 16 */, _ULL(0x26F5E6F6E85241C7) /* 17 */,
_ULL(0x859079DBEA5947B6) /* 18 */, _ULL(0x4F1885C5C99E8C92) /* 19 */,
_ULL(0xD78E761EA96F864B) /* 20 */, _ULL(0x8E36428C52B5C17D) /* 21 */,
_ULL(0x69CF6827373063C1) /* 22 */, _ULL(0xB607C93D9BB4C56E) /* 23 */,
_ULL(0x7D820E760E76B5EA) /* 24 */, _ULL(0x645C9CC6F07FDC42) /* 25 */,
_ULL(0xBF38A078243342E0) /* 26 */, _ULL(0x5F6B343C9D2E7D04) /* 27 */,
_ULL(0xF2C28AEB600B0EC6) /* 28 */, _ULL(0x6C0ED85F7254BCAC) /* 29 */,
_ULL(0x71592281A4DB4FE5) /* 30 */, _ULL(0x1967FA69CE0FED9F) /* 31 */,
_ULL(0xFD5293F8B96545DB) /* 32 */, _ULL(0xC879E9D7F2A7600B) /* 33 */,
_ULL(0x860248920193194E) /* 34 */, _ULL(0xA4F9533B2D9CC0B3) /* 35 */,
_ULL(0x9053836C15957613) /* 36 */, _ULL(0xDB6DCF8AFC357BF1) /* 37 */,
_ULL(0x18BEEA7A7A370F57) /* 38 */, _ULL(0x037117CA50B99066) /* 39 */,
_ULL(0x6AB30A9774424A35) /* 40 */, _ULL(0xF4E92F02E325249B) /* 41 */,
_ULL(0x7739DB07061CCAE1) /* 42 */, _ULL(0xD8F3B49CECA42A05) /* 43 */,
_ULL(0xBD56BE3F51382F73) /* 44 */, _ULL(0x45FAED5843B0BB28) /* 45 */,
_ULL(0x1C813D5C11BF1F83) /* 46 */, _ULL(0x8AF0E4B6D75FA169) /* 47 */,
_ULL(0x33EE18A487AD9999) /* 48 */, _ULL(0x3C26E8EAB1C94410) /* 49 */,
_ULL(0xB510102BC0A822F9) /* 50 */, _ULL(0x141EEF310CE6123B) /* 51 */,
_ULL(0xFC65B90059DDB154) /* 52 */, _ULL(0xE0158640C5E0E607) /* 53 */,
_ULL(0x884E079826C3A3CF) /* 54 */, _ULL(0x930D0D9523C535FD) /* 55 */,
_ULL(0x35638D754E9A2B00) /* 56 */, _ULL(0x4085FCCF40469DD5) /* 57 */,
_ULL(0xC4B17AD28BE23A4C) /* 58 */, _ULL(0xCAB2F0FC6A3E6A2E) /* 59 */,
_ULL(0x2860971A6B943FCD) /* 60 */, _ULL(0x3DDE6EE212E30446) /* 61 */,
_ULL(0x6222F32AE01765AE) /* 62 */, _ULL(0x5D550BB5478308FE) /* 63 */,
_ULL(0xA9EFA98DA0EDA22A) /* 64 */, _ULL(0xC351A71686C40DA7) /* 65 */,
_ULL(0x1105586D9C867C84) /* 66 */, _ULL(0xDCFFEE85FDA22853) /* 67 */,
_ULL(0xCCFBD0262C5EEF76) /* 68 */, _ULL(0xBAF294CB8990D201) /* 69 */,
_ULL(0xE69464F52AFAD975) /* 70 */, _ULL(0x94B013AFDF133E14) /* 71 */,
_ULL(0x06A7D1A32823C958) /* 72 */, _ULL(0x6F95FE5130F61119) /* 73 */,
_ULL(0xD92AB34E462C06C0) /* 74 */, _ULL(0xED7BDE33887C71D2) /* 75 */,
_ULL(0x79746D6E6518393E) /* 76 */, _ULL(0x5BA419385D713329) /* 77 */,
_ULL(0x7C1BA6B948A97564) /* 78 */, _ULL(0x31987C197BFDAC67) /* 79 */,
_ULL(0xDE6C23C44B053D02) /* 80 */, _ULL(0x581C49FED002D64D) /* 81 */,
_ULL(0xDD474D6338261571) /* 82 */, _ULL(0xAA4546C3E473D062) /* 83 */,
_ULL(0x928FCE349455F860) /* 84 */, _ULL(0x48161BBACAAB94D9) /* 85 */,
_ULL(0x63912430770E6F68) /* 86 */, _ULL(0x6EC8A5E602C6641C) /* 87 */,
_ULL(0x87282515337DDD2B) /* 88 */, _ULL(0x2CDA6B42034B701B) /* 89 */,
_ULL(0xB03D37C181CB096D) /* 90 */, _ULL(0xE108438266C71C6F) /* 91 */,
_ULL(0x2B3180C7EB51B255) /* 92 */, _ULL(0xDF92B82F96C08BBC) /* 93 */,
_ULL(0x5C68C8C0A632F3BA) /* 94 */, _ULL(0x5504CC861C3D0556) /* 95 */,
_ULL(0xABBFA4E55FB26B8F) /* 96 */, _ULL(0x41848B0AB3BACEB4) /* 97 */,
_ULL(0xB334A273AA445D32) /* 98 */, _ULL(0xBCA696F0A85AD881) /* 99 */,
_ULL(0x24F6EC65B528D56C) /* 100 */, _ULL(0x0CE1512E90F4524A) /* 101 */,
_ULL(0x4E9DD79D5506D35A) /* 102 */, _ULL(0x258905FAC6CE9779) /* 103 */,
_ULL(0x2019295B3E109B33) /* 104 */, _ULL(0xF8A9478B73A054CC) /* 105 */,
_ULL(0x2924F2F934417EB0) /* 106 */, _ULL(0x3993357D536D1BC4) /* 107 */,
_ULL(0x38A81AC21DB6FF8B) /* 108 */, _ULL(0x47C4FBF17D6016BF) /* 109 */,
_ULL(0x1E0FAADD7667E3F5) /* 110 */, _ULL(0x7ABCFF62938BEB96) /* 111 */,
_ULL(0xA78DAD948FC179C9) /* 112 */, _ULL(0x8F1F98B72911E50D) /* 113 */,
_ULL(0x61E48EAE27121A91) /* 114 */, _ULL(0x4D62F7AD31859808) /* 115 */,
_ULL(0xECEBA345EF5CEAEB) /* 116 */, _ULL(0xF5CEB25EBC9684CE) /* 117 */,
_ULL(0xF633E20CB7F76221) /* 118 */, _ULL(0xA32CDF06AB8293E4) /* 119 */,
_ULL(0x985A202CA5EE2CA4) /* 120 */, _ULL(0xCF0B8447CC8A8FB1) /* 121 */,
_ULL(0x9F765244979859A3) /* 122 */, _ULL(0xA8D516B1A1240017) /* 123 */,
_ULL(0x0BD7BA3EBB5DC726) /* 124 */, _ULL(0xE54BCA55B86ADB39) /* 125 */,
_ULL(0x1D7A3AFD6C478063) /* 126 */, _ULL(0x519EC608E7669EDD) /* 127 */,
_ULL(0x0E5715A2D149AA23) /* 128 */, _ULL(0x177D4571848FF194) /* 129 */,
_ULL(0xEEB55F3241014C22) /* 130 */, _ULL(0x0F5E5CA13A6E2EC2) /* 131 */,
_ULL(0x8029927B75F5C361) /* 132 */, _ULL(0xAD139FABC3D6E436) /* 133 */,
_ULL(0x0D5DF1A94CCF402F) /* 134 */, _ULL(0x3E8BD948BEA5DFC8) /* 135 */,
_ULL(0xA5A0D357BD3FF77E) /* 136 */, _ULL(0xA2D12E251F74F645) /* 137 */,
_ULL(0x66FD9E525E81A082) /* 138 */, _ULL(0x2E0C90CE7F687A49) /* 139 */,
_ULL(0xC2E8BCBEBA973BC5) /* 140 */, _ULL(0x000001BCE509745F) /* 141 */,
_ULL(0x423777BBE6DAB3D6) /* 142 */, _ULL(0xD1661C7EAEF06EB5) /* 143 */,
_ULL(0xA1781F354DAACFD8) /* 144 */, _ULL(0x2D11284A2B16AFFC) /* 145 */,
_ULL(0xF1FC4F67FA891D1F) /* 146 */, _ULL(0x73ECC25DCB920ADA) /* 147 */,
_ULL(0xAE610C22C2A12651) /* 148 */, _ULL(0x96E0A810D356B78A) /* 149 */,
_ULL(0x5A9A381F2FE7870F) /* 150 */, _ULL(0xD5AD62EDE94E5530) /* 151 */,
_ULL(0xD225E5E8368D1427) /* 152 */, _ULL(0x65977B70C7AF4631) /* 153 */,
_ULL(0x99F889B2DE39D74F) /* 154 */, _ULL(0x233F30BF54E1D143) /* 155 */,
_ULL(0x9A9675D3D9A63C97) /* 156 */, _ULL(0x5470554FF334F9A8) /* 157 */,
_ULL(0x166ACB744A4F5688) /* 158 */, _ULL(0x70C74CAAB2E4AEAD) /* 159 */,
_ULL(0xF0D091646F294D12) /* 160 */, _ULL(0x57B82A89684031D1) /* 161 */,
_ULL(0xEFD95A5A61BE0B6B) /* 162 */, _ULL(0x2FBD12E969F2F29A) /* 163 */,
_ULL(0x9BD37013FEFF9FE8) /* 164 */, _ULL(0x3F9B0404D6085A06) /* 165 */,
_ULL(0x4940C1F3166CFE15) /* 166 */, _ULL(0x09542C4DCDF3DEFB) /* 167 */,
_ULL(0xB4C5218385CD5CE3) /* 168 */, _ULL(0xC935B7DC4462A641) /* 169 */,
_ULL(0x3417F8A68ED3B63F) /* 170 */, _ULL(0xB80959295B215B40) /* 171 */,
_ULL(0xF99CDAEF3B8C8572) /* 172 */, _ULL(0x018C0614F8FCB95D) /* 173 */,
_ULL(0x1B14ACCD1A3ACDF3) /* 174 */, _ULL(0x84D471F200BB732D) /* 175 */,
_ULL(0xC1A3110E95E8DA16) /* 176 */, _ULL(0x430A7220BF1A82B8) /* 177 */,
_ULL(0xB77E090D39DF210E) /* 178 */, _ULL(0x5EF4BD9F3CD05E9D) /* 179 */,
_ULL(0x9D4FF6DA7E57A444) /* 180 */, _ULL(0xDA1D60E183D4A5F8) /* 181 */,
_ULL(0xB287C38417998E47) /* 182 */, _ULL(0xFE3EDC121BB31886) /* 183 */,
_ULL(0xC7FE3CCC980CCBEF) /* 184 */, _ULL(0xE46FB590189BFD03) /* 185 */,
_ULL(0x3732FD469A4C57DC) /* 186 */, _ULL(0x7EF700A07CF1AD65) /* 187 */,
_ULL(0x59C64468A31D8859) /* 188 */, _ULL(0x762FB0B4D45B61F6) /* 189 */,
_ULL(0x155BAED099047718) /* 190 */, _ULL(0x68755E4C3D50BAA6) /* 191 */,
_ULL(0xE9214E7F22D8B4DF) /* 192 */, _ULL(0x2ADDBF532EAC95F4) /* 193 */,
_ULL(0x32AE3909B4BD0109) /* 194 */, _ULL(0x834DF537B08E3450) /* 195 */,
_ULL(0xFA209DA84220728D) /* 196 */, _ULL(0x9E691D9B9EFE23F7) /* 197 */,
_ULL(0x0446D288C4AE8D7F) /* 198 */, _ULL(0x7B4CC524E169785B) /* 199 */,
_ULL(0x21D87F0135CA1385) /* 200 */, _ULL(0xCEBB400F137B8AA5) /* 201 */,
_ULL(0x272E2B66580796BE) /* 202 */, _ULL(0x3612264125C2B0DE) /* 203 */,
_ULL(0x057702BDAD1EFBB2) /* 204 */, _ULL(0xD4BABB8EACF84BE9) /* 205 */,
_ULL(0x91583139641BC67B) /* 206 */, _ULL(0x8BDC2DE08036E024) /* 207 */,
_ULL(0x603C8156F49F68ED) /* 208 */, _ULL(0xF7D236F7DBEF5111) /* 209 */,
_ULL(0x9727C4598AD21E80) /* 210 */, _ULL(0xA08A0896670A5FD7) /* 211 */,
_ULL(0xCB4A8F4309EBA9CB) /* 212 */, _ULL(0x81AF564B0F7036A1) /* 213 */,
_ULL(0xC0B99AA778199ABD) /* 214 */, _ULL(0x959F1EC83FC8E952) /* 215 */,
_ULL(0x8C505077794A81B9) /* 216 */, _ULL(0x3ACAAF8F056338F0) /* 217 */,
_ULL(0x07B43F50627A6778) /* 218 */, _ULL(0x4A44AB49F5ECCC77) /* 219 */,
_ULL(0x3BC3D6E4B679EE98) /* 220 */, _ULL(0x9CC0D4D1CF14108C) /* 221 */,
_ULL(0x4406C00B206BC8A0) /* 222 */, _ULL(0x82A18854C8D72D89) /* 223 */,
_ULL(0x67E366B35C3C432C) /* 224 */, _ULL(0xB923DD61102B37F2) /* 225 */,
_ULL(0x56AB2779D884271D) /* 226 */, _ULL(0xBE83E1B0FF1525AF) /* 227 */,
_ULL(0xFB7C65D4217E49A9) /* 228 */, _ULL(0x6BDBE0E76D48E7D4) /* 229 */,
_ULL(0x08DF828745D9179E) /* 230 */, _ULL(0x22EA6A9ADD53BD34) /* 231 */,
_ULL(0xE36E141C5622200A) /* 232 */, _ULL(0x7F805D1B8CB750EE) /* 233 */,
_ULL(0xAFE5C7A59F58E837) /* 234 */, _ULL(0xE27F996A4FB1C23C) /* 235 */,
_ULL(0xD3867DFB0775F0D0) /* 236 */, _ULL(0xD0E673DE6E88891A) /* 237 */,
_ULL(0x123AEB9EAFB86C25) /* 238 */, _ULL(0x30F1D5D5C145B895) /* 239 */,
_ULL(0xBB434A2DEE7269E7) /* 240 */, _ULL(0x78CB67ECF931FA38) /* 241 */,
_ULL(0xF33B0372323BBF9C) /* 242 */, _ULL(0x52D66336FB279C74) /* 243 */,
_ULL(0x505F33AC0AFB4EAA) /* 244 */, _ULL(0xE8A5CD99A2CCE187) /* 245 */,
_ULL(0x534974801E2D30BB) /* 246 */, _ULL(0x8D2D5711D5876D90) /* 247 */,
_ULL(0x1F1A412891BC038E) /* 248 */, _ULL(0xD6E2E71D82E56648) /* 249 */,
_ULL(0x74036C3A497732B7) /* 250 */, _ULL(0x89B67ED96361F5AB) /* 251 */,
_ULL(0xFFED95D8F1EA02A2) /* 252 */, _ULL(0xE72B3BD61464D43D) /* 253 */,
_ULL(0xA6300F170BDC4820) /* 254 */, _ULL(0xEBC18760ED78A77A) /* 255 */,
_ULL(0xE6A6BE5A05A12138) /* 256 */, _ULL(0xB5A122A5B4F87C98) /* 257 */,
_ULL(0x563C6089140B6990) /* 258 */, _ULL(0x4C46CB2E391F5DD5) /* 259 */,
_ULL(0xD932ADDBC9B79434) /* 260 */, _ULL(0x08EA70E42015AFF5) /* 261 */,
_ULL(0xD765A6673E478CF1) /* 262 */, _ULL(0xC4FB757EAB278D99) /* 263 */,
_ULL(0xDF11C6862D6E0692) /* 264 */, _ULL(0xDDEB84F10D7F3B16) /* 265 */,
_ULL(0x6F2EF604A665EA04) /* 266 */, _ULL(0x4A8E0F0FF0E0DFB3) /* 267 */,
_ULL(0xA5EDEEF83DBCBA51) /* 268 */, _ULL(0xFC4F0A2A0EA4371E) /* 269 */,
_ULL(0xE83E1DA85CB38429) /* 270 */, _ULL(0xDC8FF882BA1B1CE2) /* 271 */,
_ULL(0xCD45505E8353E80D) /* 272 */, _ULL(0x18D19A00D4DB0717) /* 273 */,
_ULL(0x34A0CFEDA5F38101) /* 274 */, _ULL(0x0BE77E518887CAF2) /* 275 */,
_ULL(0x1E341438B3C45136) /* 276 */, _ULL(0xE05797F49089CCF9) /* 277 */,
_ULL(0xFFD23F9DF2591D14) /* 278 */, _ULL(0x543DDA228595C5CD) /* 279 */,
_ULL(0x661F81FD99052A33) /* 280 */, _ULL(0x8736E641DB0F7B76) /* 281 */,
_ULL(0x15227725418E5307) /* 282 */, _ULL(0xE25F7F46162EB2FA) /* 283 */,
_ULL(0x48A8B2126C13D9FE) /* 284 */, _ULL(0xAFDC541792E76EEA) /* 285 */,
_ULL(0x03D912BFC6D1898F) /* 286 */, _ULL(0x31B1AAFA1B83F51B) /* 287 */,
_ULL(0xF1AC2796E42AB7D9) /* 288 */, _ULL(0x40A3A7D7FCD2EBAC) /* 289 */,
_ULL(0x1056136D0AFBBCC5) /* 290 */, _ULL(0x7889E1DD9A6D0C85) /* 291 */,
_ULL(0xD33525782A7974AA) /* 292 */, _ULL(0xA7E25D09078AC09B) /* 293 */,
_ULL(0xBD4138B3EAC6EDD0) /* 294 */, _ULL(0x920ABFBE71EB9E70) /* 295 */,
_ULL(0xA2A5D0F54FC2625C) /* 296 */, _ULL(0xC054E36B0B1290A3) /* 297 */,
_ULL(0xF6DD59FF62FE932B) /* 298 */, _ULL(0x3537354511A8AC7D) /* 299 */,
_ULL(0xCA845E9172FADCD4) /* 300 */, _ULL(0x84F82B60329D20DC) /* 301 */,
_ULL(0x79C62CE1CD672F18) /* 302 */, _ULL(0x8B09A2ADD124642C) /* 303 */,
_ULL(0xD0C1E96A19D9E726) /* 304 */, _ULL(0x5A786A9B4BA9500C) /* 305 */,
_ULL(0x0E020336634C43F3) /* 306 */, _ULL(0xC17B474AEB66D822) /* 307 */,
_ULL(0x6A731AE3EC9BAAC2) /* 308 */, _ULL(0x8226667AE0840258) /* 309 */,
_ULL(0x67D4567691CAECA5) /* 310 */, _ULL(0x1D94155C4875ADB5) /* 311 */,
_ULL(0x6D00FD985B813FDF) /* 312 */, _ULL(0x51286EFCB774CD06) /* 313 */,
_ULL(0x5E8834471FA744AF) /* 314 */, _ULL(0xF72CA0AEE761AE2E) /* 315 */,
_ULL(0xBE40E4CDAEE8E09A) /* 316 */, _ULL(0xE9970BBB5118F665) /* 317 */,
_ULL(0x726E4BEB33DF1964) /* 318 */, _ULL(0x703B000729199762) /* 319 */,
_ULL(0x4631D816F5EF30A7) /* 320 */, _ULL(0xB880B5B51504A6BE) /* 321 */,
_ULL(0x641793C37ED84B6C) /* 322 */, _ULL(0x7B21ED77F6E97D96) /* 323 */,
_ULL(0x776306312EF96B73) /* 324 */, _ULL(0xAE528948E86FF3F4) /* 325 */,
_ULL(0x53DBD7F286A3F8F8) /* 326 */, _ULL(0x16CADCE74CFC1063) /* 327 */,
_ULL(0x005C19BDFA52C6DD) /* 328 */, _ULL(0x68868F5D64D46AD3) /* 329 */,
_ULL(0x3A9D512CCF1E186A) /* 330 */, _ULL(0x367E62C2385660AE) /* 331 */,
_ULL(0xE359E7EA77DCB1D7) /* 332 */, _ULL(0x526C0773749ABE6E) /* 333 */,
_ULL(0x735AE5F9D09F734B) /* 334 */, _ULL(0x493FC7CC8A558BA8) /* 335 */,
_ULL(0xB0B9C1533041AB45) /* 336 */, _ULL(0x321958BA470A59BD) /* 337 */,
_ULL(0x852DB00B5F46C393) /* 338 */, _ULL(0x91209B2BD336B0E5) /* 339 */,
_ULL(0x6E604F7D659EF19F) /* 340 */, _ULL(0xB99A8AE2782CCB24) /* 341 */,
_ULL(0xCCF52AB6C814C4C7) /* 342 */, _ULL(0x4727D9AFBE11727B) /* 343 */,
_ULL(0x7E950D0C0121B34D) /* 344 */, _ULL(0x756F435670AD471F) /* 345 */,
_ULL(0xF5ADD442615A6849) /* 346 */, _ULL(0x4E87E09980B9957A) /* 347 */,
_ULL(0x2ACFA1DF50AEE355) /* 348 */, _ULL(0xD898263AFD2FD556) /* 349 */,
_ULL(0xC8F4924DD80C8FD6) /* 350 */, _ULL(0xCF99CA3D754A173A) /* 351 */,
_ULL(0xFE477BACAF91BF3C) /* 352 */, _ULL(0xED5371F6D690C12D) /* 353 */,
_ULL(0x831A5C285E687094) /* 354 */, _ULL(0xC5D3C90A3708A0A4) /* 355 */,
_ULL(0x0F7F903717D06580) /* 356 */, _ULL(0x19F9BB13B8FDF27F) /* 357 */,
_ULL(0xB1BD6F1B4D502843) /* 358 */, _ULL(0x1C761BA38FFF4012) /* 359 */,
_ULL(0x0D1530C4E2E21F3B) /* 360 */, _ULL(0x8943CE69A7372C8A) /* 361 */,
_ULL(0xE5184E11FEB5CE66) /* 362 */, _ULL(0x618BDB80BD736621) /* 363 */,
_ULL(0x7D29BAD68B574D0B) /* 364 */, _ULL(0x81BB613E25E6FE5B) /* 365 */,
_ULL(0x071C9C10BC07913F) /* 366 */, _ULL(0xC7BEEB7909AC2D97) /* 367 */,
_ULL(0xC3E58D353BC5D757) /* 368 */, _ULL(0xEB017892F38F61E8) /* 369 */,
_ULL(0xD4EFFB9C9B1CC21A) /* 370 */, _ULL(0x99727D26F494F7AB) /* 371 */,
_ULL(0xA3E063A2956B3E03) /* 372 */, _ULL(0x9D4A8B9A4AA09C30) /* 373 */,
_ULL(0x3F6AB7D500090FB4) /* 374 */, _ULL(0x9CC0F2A057268AC0) /* 375 */,
_ULL(0x3DEE9D2DEDBF42D1) /* 376 */, _ULL(0x330F49C87960A972) /* 377 */,
_ULL(0xC6B2720287421B41) /* 378 */, _ULL(0x0AC59EC07C00369C) /* 379 */,
_ULL(0xEF4EAC49CB353425) /* 380 */, _ULL(0xF450244EEF0129D8) /* 381 */,
_ULL(0x8ACC46E5CAF4DEB6) /* 382 */, _ULL(0x2FFEAB63989263F7) /* 383 */,
_ULL(0x8F7CB9FE5D7A4578) /* 384 */, _ULL(0x5BD8F7644E634635) /* 385 */,
_ULL(0x427A7315BF2DC900) /* 386 */, _ULL(0x17D0C4AA2125261C) /* 387 */,
_ULL(0x3992486C93518E50) /* 388 */, _ULL(0xB4CBFEE0A2D7D4C3) /* 389 */,
_ULL(0x7C75D6202C5DDD8D) /* 390 */, _ULL(0xDBC295D8E35B6C61) /* 391 */,
_ULL(0x60B369D302032B19) /* 392 */, _ULL(0xCE42685FDCE44132) /* 393 */,
_ULL(0x06F3DDB9DDF65610) /* 394 */, _ULL(0x8EA4D21DB5E148F0) /* 395 */,
_ULL(0x20B0FCE62FCD496F) /* 396 */, _ULL(0x2C1B912358B0EE31) /* 397 */,
_ULL(0xB28317B818F5A308) /* 398 */, _ULL(0xA89C1E189CA6D2CF) /* 399 */,
_ULL(0x0C6B18576AAADBC8) /* 400 */, _ULL(0xB65DEAA91299FAE3) /* 401 */,
_ULL(0xFB2B794B7F1027E7) /* 402 */, _ULL(0x04E4317F443B5BEB) /* 403 */,
_ULL(0x4B852D325939D0A6) /* 404 */, _ULL(0xD5AE6BEEFB207FFC) /* 405 */,
_ULL(0x309682B281C7D374) /* 406 */, _ULL(0xBAE309A194C3B475) /* 407 */,
_ULL(0x8CC3F97B13B49F05) /* 408 */, _ULL(0x98A9422FF8293967) /* 409 */,
_ULL(0x244B16B01076FF7C) /* 410 */, _ULL(0xF8BF571C663D67EE) /* 411 */,
_ULL(0x1F0D6758EEE30DA1) /* 412 */, _ULL(0xC9B611D97ADEB9B7) /* 413 */,
_ULL(0xB7AFD5887B6C57A2) /* 414 */, _ULL(0x6290AE846B984FE1) /* 415 */,
_ULL(0x94DF4CDEACC1A5FD) /* 416 */, _ULL(0x058A5BD1C5483AFF) /* 417 */,
_ULL(0x63166CC142BA3C37) /* 418 */, _ULL(0x8DB8526EB2F76F40) /* 419 */,
_ULL(0xE10880036F0D6D4E) /* 420 */, _ULL(0x9E0523C9971D311D) /* 421 */,
_ULL(0x45EC2824CC7CD691) /* 422 */, _ULL(0x575B8359E62382C9) /* 423 */,
_ULL(0xFA9E400DC4889995) /* 424 */, _ULL(0xD1823ECB45721568) /* 425 */,
_ULL(0xDAFD983B8206082F) /* 426 */, _ULL(0xAA7D29082386A8CB) /* 427 */,
_ULL(0x269FCD4403B87588) /* 428 */, _ULL(0x1B91F5F728BDD1E0) /* 429 */,
_ULL(0xE4669F39040201F6) /* 430 */, _ULL(0x7A1D7C218CF04ADE) /* 431 */,
_ULL(0x65623C29D79CE5CE) /* 432 */, _ULL(0x2368449096C00BB1) /* 433 */,
_ULL(0xAB9BF1879DA503BA) /* 434 */, _ULL(0xBC23ECB1A458058E) /* 435 */,
_ULL(0x9A58DF01BB401ECC) /* 436 */, _ULL(0xA070E868A85F143D) /* 437 */,
_ULL(0x4FF188307DF2239E) /* 438 */, _ULL(0x14D565B41A641183) /* 439 */,
_ULL(0xEE13337452701602) /* 440 */, _ULL(0x950E3DCF3F285E09) /* 441 */,
_ULL(0x59930254B9C80953) /* 442 */, _ULL(0x3BF299408930DA6D) /* 443 */,
_ULL(0xA955943F53691387) /* 444 */, _ULL(0xA15EDECAA9CB8784) /* 445 */,
_ULL(0x29142127352BE9A0) /* 446 */, _ULL(0x76F0371FFF4E7AFB) /* 447 */,
_ULL(0x0239F450274F2228) /* 448 */, _ULL(0xBB073AF01D5E868B) /* 449 */,
_ULL(0xBFC80571C10E96C1) /* 450 */, _ULL(0xD267088568222E23) /* 451 */,
_ULL(0x9671A3D48E80B5B0) /* 452 */, _ULL(0x55B5D38AE193BB81) /* 453 */,
_ULL(0x693AE2D0A18B04B8) /* 454 */, _ULL(0x5C48B4ECADD5335F) /* 455 */,
_ULL(0xFD743B194916A1CA) /* 456 */, _ULL(0x2577018134BE98C4) /* 457 */,
_ULL(0xE77987E83C54A4AD) /* 458 */, _ULL(0x28E11014DA33E1B9) /* 459 */,
_ULL(0x270CC59E226AA213) /* 460 */, _ULL(0x71495F756D1A5F60) /* 461 */,
_ULL(0x9BE853FB60AFEF77) /* 462 */, _ULL(0xADC786A7F7443DBF) /* 463 */,
_ULL(0x0904456173B29A82) /* 464 */, _ULL(0x58BC7A66C232BD5E) /* 465 */,
_ULL(0xF306558C673AC8B2) /* 466 */, _ULL(0x41F639C6B6C9772A) /* 467 */,
_ULL(0x216DEFE99FDA35DA) /* 468 */, _ULL(0x11640CC71C7BE615) /* 469 */,
_ULL(0x93C43694565C5527) /* 470 */, _ULL(0xEA038E6246777839) /* 471 */,
_ULL(0xF9ABF3CE5A3E2469) /* 472 */, _ULL(0x741E768D0FD312D2) /* 473 */,
_ULL(0x0144B883CED652C6) /* 474 */, _ULL(0xC20B5A5BA33F8552) /* 475 */,
_ULL(0x1AE69633C3435A9D) /* 476 */, _ULL(0x97A28CA4088CFDEC) /* 477 */,
_ULL(0x8824A43C1E96F420) /* 478 */, _ULL(0x37612FA66EEEA746) /* 479 */,
_ULL(0x6B4CB165F9CF0E5A) /* 480 */, _ULL(0x43AA1C06A0ABFB4A) /* 481 */,
_ULL(0x7F4DC26FF162796B) /* 482 */, _ULL(0x6CBACC8E54ED9B0F) /* 483 */,
_ULL(0xA6B7FFEFD2BB253E) /* 484 */, _ULL(0x2E25BC95B0A29D4F) /* 485 */,
_ULL(0x86D6A58BDEF1388C) /* 486 */, _ULL(0xDED74AC576B6F054) /* 487 */,
_ULL(0x8030BDBC2B45805D) /* 488 */, _ULL(0x3C81AF70E94D9289) /* 489 */,
_ULL(0x3EFF6DDA9E3100DB) /* 490 */, _ULL(0xB38DC39FDFCC8847) /* 491 */,
_ULL(0x123885528D17B87E) /* 492 */, _ULL(0xF2DA0ED240B1B642) /* 493 */,
_ULL(0x44CEFADCD54BF9A9) /* 494 */, _ULL(0x1312200E433C7EE6) /* 495 */,
_ULL(0x9FFCC84F3A78C748) /* 496 */, _ULL(0xF0CD1F72248576BB) /* 497 */,
_ULL(0xEC6974053638CFE4) /* 498 */, _ULL(0x2BA7B67C0CEC4E4C) /* 499 */,
_ULL(0xAC2F4DF3E5CE32ED) /* 500 */, _ULL(0xCB33D14326EA4C11) /* 501 */,
_ULL(0xA4E9044CC77E58BC) /* 502 */, _ULL(0x5F513293D934FCEF) /* 503 */,
_ULL(0x5DC9645506E55444) /* 504 */, _ULL(0x50DE418F317DE40A) /* 505 */,
_ULL(0x388CB31A69DDE259) /* 506 */, _ULL(0x2DB4A83455820A86) /* 507 */,
_ULL(0x9010A91E84711AE9) /* 508 */, _ULL(0x4DF7F0B7B1498371) /* 509 */,
_ULL(0xD62A2EABC0977179) /* 510 */, _ULL(0x22FAC097AA8D5C0E) /* 511 */,
_ULL(0xF49FCC2FF1DAF39B) /* 512 */, _ULL(0x487FD5C66FF29281) /* 513 */,
_ULL(0xE8A30667FCDCA83F) /* 514 */, _ULL(0x2C9B4BE3D2FCCE63) /* 515 */,
_ULL(0xDA3FF74B93FBBBC2) /* 516 */, _ULL(0x2FA165D2FE70BA66) /* 517 */,
_ULL(0xA103E279970E93D4) /* 518 */, _ULL(0xBECDEC77B0E45E71) /* 519 */,
_ULL(0xCFB41E723985E497) /* 520 */, _ULL(0xB70AAA025EF75017) /* 521 */,
_ULL(0xD42309F03840B8E0) /* 522 */, _ULL(0x8EFC1AD035898579) /* 523 */,
_ULL(0x96C6920BE2B2ABC5) /* 524 */, _ULL(0x66AF4163375A9172) /* 525 */,
_ULL(0x2174ABDCCA7127FB) /* 526 */, _ULL(0xB33CCEA64A72FF41) /* 527 */,
_ULL(0xF04A4933083066A5) /* 528 */, _ULL(0x8D970ACDD7289AF5) /* 529 */,
_ULL(0x8F96E8E031C8C25E) /* 530 */, _ULL(0xF3FEC02276875D47) /* 531 */,
_ULL(0xEC7BF310056190DD) /* 532 */, _ULL(0xF5ADB0AEBB0F1491) /* 533 */,
_ULL(0x9B50F8850FD58892) /* 534 */, _ULL(0x4975488358B74DE8) /* 535 */,
_ULL(0xA3354FF691531C61) /* 536 */, _ULL(0x0702BBE481D2C6EE) /* 537 */,
_ULL(0x89FB24057DEDED98) /* 538 */, _ULL(0xAC3075138596E902) /* 539 */,
_ULL(0x1D2D3580172772ED) /* 540 */, _ULL(0xEB738FC28E6BC30D) /* 541 */,
_ULL(0x5854EF8F63044326) /* 542 */, _ULL(0x9E5C52325ADD3BBE) /* 543 */,
_ULL(0x90AA53CF325C4623) /* 544 */, _ULL(0xC1D24D51349DD067) /* 545 */,
_ULL(0x2051CFEEA69EA624) /* 546 */, _ULL(0x13220F0A862E7E4F) /* 547 */,
_ULL(0xCE39399404E04864) /* 548 */, _ULL(0xD9C42CA47086FCB7) /* 549 */,
_ULL(0x685AD2238A03E7CC) /* 550 */, _ULL(0x066484B2AB2FF1DB) /* 551 */,
_ULL(0xFE9D5D70EFBF79EC) /* 552 */, _ULL(0x5B13B9DD9C481854) /* 553 */,
_ULL(0x15F0D475ED1509AD) /* 554 */, _ULL(0x0BEBCD060EC79851) /* 555 */,
_ULL(0xD58C6791183AB7F8) /* 556 */, _ULL(0xD1187C5052F3EEE4) /* 557 */,
_ULL(0xC95D1192E54E82FF) /* 558 */, _ULL(0x86EEA14CB9AC6CA2) /* 559 */,
_ULL(0x3485BEB153677D5D) /* 560 */, _ULL(0xDD191D781F8C492A) /* 561 */,
_ULL(0xF60866BAA784EBF9) /* 562 */, _ULL(0x518F643BA2D08C74) /* 563 */,
_ULL(0x8852E956E1087C22) /* 564 */, _ULL(0xA768CB8DC410AE8D) /* 565 */,
_ULL(0x38047726BFEC8E1A) /* 566 */, _ULL(0xA67738B4CD3B45AA) /* 567 */,
_ULL(0xAD16691CEC0DDE19) /* 568 */, _ULL(0xC6D4319380462E07) /* 569 */,
_ULL(0xC5A5876D0BA61938) /* 570 */, _ULL(0x16B9FA1FA58FD840) /* 571 */,
_ULL(0x188AB1173CA74F18) /* 572 */, _ULL(0xABDA2F98C99C021F) /* 573 */,
_ULL(0x3E0580AB134AE816) /* 574 */, _ULL(0x5F3B05B773645ABB) /* 575 */,
_ULL(0x2501A2BE5575F2F6) /* 576 */, _ULL(0x1B2F74004E7E8BA9) /* 577 */,
_ULL(0x1CD7580371E8D953) /* 578 */, _ULL(0x7F6ED89562764E30) /* 579 */,
_ULL(0xB15926FF596F003D) /* 580 */, _ULL(0x9F65293DA8C5D6B9) /* 581 */,
_ULL(0x6ECEF04DD690F84C) /* 582 */, _ULL(0x4782275FFF33AF88) /* 583 */,
_ULL(0xE41433083F820801) /* 584 */, _ULL(0xFD0DFE409A1AF9B5) /* 585 */,
_ULL(0x4325A3342CDB396B) /* 586 */, _ULL(0x8AE77E62B301B252) /* 587 */,
_ULL(0xC36F9E9F6655615A) /* 588 */, _ULL(0x85455A2D92D32C09) /* 589 */,
_ULL(0xF2C7DEA949477485) /* 590 */, _ULL(0x63CFB4C133A39EBA) /* 591 */,
_ULL(0x83B040CC6EBC5462) /* 592 */, _ULL(0x3B9454C8FDB326B0) /* 593 */,
_ULL(0x56F56A9E87FFD78C) /* 594 */, _ULL(0x2DC2940D99F42BC6) /* 595 */,
_ULL(0x98F7DF096B096E2D) /* 596 */, _ULL(0x19A6E01E3AD852BF) /* 597 */,
_ULL(0x42A99CCBDBD4B40B) /* 598 */, _ULL(0xA59998AF45E9C559) /* 599 */,
_ULL(0x366295E807D93186) /* 600 */, _ULL(0x6B48181BFAA1F773) /* 601 */,
_ULL(0x1FEC57E2157A0A1D) /* 602 */, _ULL(0x4667446AF6201AD5) /* 603 */,
_ULL(0xE615EBCACFB0F075) /* 604 */, _ULL(0xB8F31F4F68290778) /* 605 */,
_ULL(0x22713ED6CE22D11E) /* 606 */, _ULL(0x3057C1A72EC3C93B) /* 607 */,
_ULL(0xCB46ACC37C3F1F2F) /* 608 */, _ULL(0xDBB893FD02AAF50E) /* 609 */,
_ULL(0x331FD92E600B9FCF) /* 610 */, _ULL(0xA498F96148EA3AD6) /* 611 */,
_ULL(0xA8D8426E8B6A83EA) /* 612 */, _ULL(0xA089B274B7735CDC) /* 613 */,
_ULL(0x87F6B3731E524A11) /* 614 */, _ULL(0x118808E5CBC96749) /* 615 */,
_ULL(0x9906E4C7B19BD394) /* 616 */, _ULL(0xAFED7F7E9B24A20C) /* 617 */,
_ULL(0x6509EADEEB3644A7) /* 618 */, _ULL(0x6C1EF1D3E8EF0EDE) /* 619 */,
_ULL(0xB9C97D43E9798FB4) /* 620 */, _ULL(0xA2F2D784740C28A3) /* 621 */,
_ULL(0x7B8496476197566F) /* 622 */, _ULL(0x7A5BE3E6B65F069D) /* 623 */,
_ULL(0xF96330ED78BE6F10) /* 624 */, _ULL(0xEEE60DE77A076A15) /* 625 */,
_ULL(0x2B4BEE4AA08B9BD0) /* 626 */, _ULL(0x6A56A63EC7B8894E) /* 627 */,
_ULL(0x02121359BA34FEF4) /* 628 */, _ULL(0x4CBF99F8283703FC) /* 629 */,
_ULL(0x398071350CAF30C8) /* 630 */, _ULL(0xD0A77A89F017687A) /* 631 */,
_ULL(0xF1C1A9EB9E423569) /* 632 */, _ULL(0x8C7976282DEE8199) /* 633 */,
_ULL(0x5D1737A5DD1F7ABD) /* 634 */, _ULL(0x4F53433C09A9FA80) /* 635 */,
_ULL(0xFA8B0C53DF7CA1D9) /* 636 */, _ULL(0x3FD9DCBC886CCB77) /* 637 */,
_ULL(0xC040917CA91B4720) /* 638 */, _ULL(0x7DD00142F9D1DCDF) /* 639 */,
_ULL(0x8476FC1D4F387B58) /* 640 */, _ULL(0x23F8E7C5F3316503) /* 641 */,
_ULL(0x032A2244E7E37339) /* 642 */, _ULL(0x5C87A5D750F5A74B) /* 643 */,
_ULL(0x082B4CC43698992E) /* 644 */, _ULL(0xDF917BECB858F63C) /* 645 */,
_ULL(0x3270B8FC5BF86DDA) /* 646 */, _ULL(0x10AE72BB29B5DD76) /* 647 */,
_ULL(0x576AC94E7700362B) /* 648 */, _ULL(0x1AD112DAC61EFB8F) /* 649 */,
_ULL(0x691BC30EC5FAA427) /* 650 */, _ULL(0xFF246311CC327143) /* 651 */,
_ULL(0x3142368E30E53206) /* 652 */, _ULL(0x71380E31E02CA396) /* 653 */,
_ULL(0x958D5C960AAD76F1) /* 654 */, _ULL(0xF8D6F430C16DA536) /* 655 */,
_ULL(0xC8FFD13F1BE7E1D2) /* 656 */, _ULL(0x7578AE66004DDBE1) /* 657 */,
_ULL(0x05833F01067BE646) /* 658 */, _ULL(0xBB34B5AD3BFE586D) /* 659 */,
_ULL(0x095F34C9A12B97F0) /* 660 */, _ULL(0x247AB64525D60CA8) /* 661 */,
_ULL(0xDCDBC6F3017477D1) /* 662 */, _ULL(0x4A2E14D4DECAD24D) /* 663 */,
_ULL(0xBDB5E6D9BE0A1EEB) /* 664 */, _ULL(0x2A7E70F7794301AB) /* 665 */,
_ULL(0xDEF42D8A270540FD) /* 666 */, _ULL(0x01078EC0A34C22C1) /* 667 */,
_ULL(0xE5DE511AF4C16387) /* 668 */, _ULL(0x7EBB3A52BD9A330A) /* 669 */,
_ULL(0x77697857AA7D6435) /* 670 */, _ULL(0x004E831603AE4C32) /* 671 */,
_ULL(0xE7A21020AD78E312) /* 672 */, _ULL(0x9D41A70C6AB420F2) /* 673 */,
_ULL(0x28E06C18EA1141E6) /* 674 */, _ULL(0xD2B28CBD984F6B28) /* 675 */,
_ULL(0x26B75F6C446E9D83) /* 676 */, _ULL(0xBA47568C4D418D7F) /* 677 */,
_ULL(0xD80BADBFE6183D8E) /* 678 */, _ULL(0x0E206D7F5F166044) /* 679 */,
_ULL(0xE258A43911CBCA3E) /* 680 */, _ULL(0x723A1746B21DC0BC) /* 681 */,
_ULL(0xC7CAA854F5D7CDD3) /* 682 */, _ULL(0x7CAC32883D261D9C) /* 683 */,
_ULL(0x7690C26423BA942C) /* 684 */, _ULL(0x17E55524478042B8) /* 685 */,
_ULL(0xE0BE477656A2389F) /* 686 */, _ULL(0x4D289B5E67AB2DA0) /* 687 */,
_ULL(0x44862B9C8FBBFD31) /* 688 */, _ULL(0xB47CC8049D141365) /* 689 */,
_ULL(0x822C1B362B91C793) /* 690 */, _ULL(0x4EB14655FB13DFD8) /* 691 */,
_ULL(0x1ECBBA0714E2A97B) /* 692 */, _ULL(0x6143459D5CDE5F14) /* 693 */,
_ULL(0x53A8FBF1D5F0AC89) /* 694 */, _ULL(0x97EA04D81C5E5B00) /* 695 */,
_ULL(0x622181A8D4FDB3F3) /* 696 */, _ULL(0xE9BCD341572A1208) /* 697 */,
_ULL(0x1411258643CCE58A) /* 698 */, _ULL(0x9144C5FEA4C6E0A4) /* 699 */,
_ULL(0x0D33D06565CF620F) /* 700 */, _ULL(0x54A48D489F219CA1) /* 701 */,
_ULL(0xC43E5EAC6D63C821) /* 702 */, _ULL(0xA9728B3A72770DAF) /* 703 */,
_ULL(0xD7934E7B20DF87EF) /* 704 */, _ULL(0xE35503B61A3E86E5) /* 705 */,
_ULL(0xCAE321FBC819D504) /* 706 */, _ULL(0x129A50B3AC60BFA6) /* 707 */,
_ULL(0xCD5E68EA7E9FB6C3) /* 708 */, _ULL(0xB01C90199483B1C7) /* 709 */,
_ULL(0x3DE93CD5C295376C) /* 710 */, _ULL(0xAED52EDF2AB9AD13) /* 711 */,
_ULL(0x2E60F512C0A07884) /* 712 */, _ULL(0xBC3D86A3E36210C9) /* 713 */,
_ULL(0x35269D9B163951CE) /* 714 */, _ULL(0x0C7D6E2AD0CDB5FA) /* 715 */,
_ULL(0x59E86297D87F5733) /* 716 */, _ULL(0x298EF221898DB0E7) /* 717 */,
_ULL(0x55000029D1A5AA7E) /* 718 */, _ULL(0x8BC08AE1B5061B45) /* 719 */,
_ULL(0xC2C31C2B6C92703A) /* 720 */, _ULL(0x94CC596BAF25EF42) /* 721 */,
_ULL(0x0A1D73DB22540456) /* 722 */, _ULL(0x04B6A0F9D9C4179A) /* 723 */,
_ULL(0xEFFDAFA2AE3D3C60) /* 724 */, _ULL(0xF7C8075BB49496C4) /* 725 */,
_ULL(0x9CC5C7141D1CD4E3) /* 726 */, _ULL(0x78BD1638218E5534) /* 727 */,
_ULL(0xB2F11568F850246A) /* 728 */, _ULL(0xEDFABCFA9502BC29) /* 729 */,
_ULL(0x796CE5F2DA23051B) /* 730 */, _ULL(0xAAE128B0DC93537C) /* 731 */,
_ULL(0x3A493DA0EE4B29AE) /* 732 */, _ULL(0xB5DF6B2C416895D7) /* 733 */,
_ULL(0xFCABBD25122D7F37) /* 734 */, _ULL(0x70810B58105DC4B1) /* 735 */,
_ULL(0xE10FDD37F7882A90) /* 736 */, _ULL(0x524DCAB5518A3F5C) /* 737 */,
_ULL(0x3C9E85878451255B) /* 738 */, _ULL(0x4029828119BD34E2) /* 739 */,
_ULL(0x74A05B6F5D3CECCB) /* 740 */, _ULL(0xB610021542E13ECA) /* 741 */,
_ULL(0x0FF979D12F59E2AC) /* 742 */, _ULL(0x6037DA27E4F9CC50) /* 743 */,
_ULL(0x5E92975A0DF1847D) /* 744 */, _ULL(0xD66DE190D3E623FE) /* 745 */,
_ULL(0x5032D6B87B568048) /* 746 */, _ULL(0x9A36B7CE8235216E) /* 747 */,
_ULL(0x80272A7A24F64B4A) /* 748 */, _ULL(0x93EFED8B8C6916F7) /* 749 */,
_ULL(0x37DDBFF44CCE1555) /* 750 */, _ULL(0x4B95DB5D4B99BD25) /* 751 */,
_ULL(0x92D3FDA169812FC0) /* 752 */, _ULL(0xFB1A4A9A90660BB6) /* 753 */,
_ULL(0x730C196946A4B9B2) /* 754 */, _ULL(0x81E289AA7F49DA68) /* 755 */,
_ULL(0x64669A0F83B1A05F) /* 756 */, _ULL(0x27B3FF7D9644F48B) /* 757 */,
_ULL(0xCC6B615C8DB675B3) /* 758 */, _ULL(0x674F20B9BCEBBE95) /* 759 */,
_ULL(0x6F31238275655982) /* 760 */, _ULL(0x5AE488713E45CF05) /* 761 */,
_ULL(0xBF619F9954C21157) /* 762 */, _ULL(0xEABAC46040A8EAE9) /* 763 */,
_ULL(0x454C6FE9F2C0C1CD) /* 764 */, _ULL(0x419CF6496412691C) /* 765 */,
_ULL(0xD3DC3BEF265B0F70) /* 766 */, _ULL(0x6D0E60F5C3578A9E) /* 767 */,
_ULL(0x5B0E608526323C55) /* 768 */, _ULL(0x1A46C1A9FA1B59F5) /* 769 */,
_ULL(0xA9E245A17C4C8FFA) /* 770 */, _ULL(0x65CA5159DB2955D7) /* 771 */,
_ULL(0x05DB0A76CE35AFC2) /* 772 */, _ULL(0x81EAC77EA9113D45) /* 773 */,
_ULL(0x528EF88AB6AC0A0D) /* 774 */, _ULL(0xA09EA253597BE3FF) /* 775 */,
_ULL(0x430DDFB3AC48CD56) /* 776 */, _ULL(0xC4B3A67AF45CE46F) /* 777 */,
_ULL(0x4ECECFD8FBE2D05E) /* 778 */, _ULL(0x3EF56F10B39935F0) /* 779 */,
_ULL(0x0B22D6829CD619C6) /* 780 */, _ULL(0x17FD460A74DF2069) /* 781 */,
_ULL(0x6CF8CC8E8510ED40) /* 782 */, _ULL(0xD6C824BF3A6ECAA7) /* 783 */,
_ULL(0x61243D581A817049) /* 784 */, _ULL(0x048BACB6BBC163A2) /* 785 */,
_ULL(0xD9A38AC27D44CC32) /* 786 */, _ULL(0x7FDDFF5BAAF410AB) /* 787 */,
_ULL(0xAD6D495AA804824B) /* 788 */, _ULL(0xE1A6A74F2D8C9F94) /* 789 */,
_ULL(0xD4F7851235DEE8E3) /* 790 */, _ULL(0xFD4B7F886540D893) /* 791 */,
_ULL(0x247C20042AA4BFDA) /* 792 */, _ULL(0x096EA1C517D1327C) /* 793 */,
_ULL(0xD56966B4361A6685) /* 794 */, _ULL(0x277DA5C31221057D) /* 795 */,
_ULL(0x94D59893A43ACFF7) /* 796 */, _ULL(0x64F0C51CCDC02281) /* 797 */,
_ULL(0x3D33BCC4FF6189DB) /* 798 */, _ULL(0xE005CB184CE66AF1) /* 799 */,
_ULL(0xFF5CCD1D1DB99BEA) /* 800 */, _ULL(0xB0B854A7FE42980F) /* 801 */,
_ULL(0x7BD46A6A718D4B9F) /* 802 */, _ULL(0xD10FA8CC22A5FD8C) /* 803 */,
_ULL(0xD31484952BE4BD31) /* 804 */, _ULL(0xC7FA975FCB243847) /* 805 */,
_ULL(0x4886ED1E5846C407) /* 806 */, _ULL(0x28CDDB791EB70B04) /* 807 */,
_ULL(0xC2B00BE2F573417F) /* 808 */, _ULL(0x5C9590452180F877) /* 809 */,
_ULL(0x7A6BDDFFF370EB00) /* 810 */, _ULL(0xCE509E38D6D9D6A4) /* 811 */,
_ULL(0xEBEB0F00647FA702) /* 812 */, _ULL(0x1DCC06CF76606F06) /* 813 */,
_ULL(0xE4D9F28BA286FF0A) /* 814 */, _ULL(0xD85A305DC918C262) /* 815 */,
_ULL(0x475B1D8732225F54) /* 816 */, _ULL(0x2D4FB51668CCB5FE) /* 817 */,
_ULL(0xA679B9D9D72BBA20) /* 818 */, _ULL(0x53841C0D912D43A5) /* 819 */,
_ULL(0x3B7EAA48BF12A4E8) /* 820 */, _ULL(0x781E0E47F22F1DDF) /* 821 */,
_ULL(0xEFF20CE60AB50973) /* 822 */, _ULL(0x20D261D19DFFB742) /* 823 */,
_ULL(0x16A12B03062A2E39) /* 824 */, _ULL(0x1960EB2239650495) /* 825 */,
_ULL(0x251C16FED50EB8B8) /* 826 */, _ULL(0x9AC0C330F826016E) /* 827 */,
_ULL(0xED152665953E7671) /* 828 */, _ULL(0x02D63194A6369570) /* 829 */,
_ULL(0x5074F08394B1C987) /* 830 */, _ULL(0x70BA598C90B25CE1) /* 831 */,
_ULL(0x794A15810B9742F6) /* 832 */, _ULL(0x0D5925E9FCAF8C6C) /* 833 */,
_ULL(0x3067716CD868744E) /* 834 */, _ULL(0x910AB077E8D7731B) /* 835 */,
_ULL(0x6A61BBDB5AC42F61) /* 836 */, _ULL(0x93513EFBF0851567) /* 837 */,
_ULL(0xF494724B9E83E9D5) /* 838 */, _ULL(0xE887E1985C09648D) /* 839 */,
_ULL(0x34B1D3C675370CFD) /* 840 */, _ULL(0xDC35E433BC0D255D) /* 841 */,
_ULL(0xD0AAB84234131BE0) /* 842 */, _ULL(0x08042A50B48B7EAF) /* 843 */,
_ULL(0x9997C4EE44A3AB35) /* 844 */, _ULL(0x829A7B49201799D0) /* 845 */,
_ULL(0x263B8307B7C54441) /* 846 */, _ULL(0x752F95F4FD6A6CA6) /* 847 */,
_ULL(0x927217402C08C6E5) /* 848 */, _ULL(0x2A8AB754A795D9EE) /* 849 */,
_ULL(0xA442F7552F72943D) /* 850 */, _ULL(0x2C31334E19781208) /* 851 */,
_ULL(0x4FA98D7CEAEE6291) /* 852 */, _ULL(0x55C3862F665DB309) /* 853 */,
_ULL(0xBD0610175D53B1F3) /* 854 */, _ULL(0x46FE6CB840413F27) /* 855 */,
_ULL(0x3FE03792DF0CFA59) /* 856 */, _ULL(0xCFE700372EB85E8F) /* 857 */,
_ULL(0xA7BE29E7ADBCE118) /* 858 */, _ULL(0xE544EE5CDE8431DD) /* 859 */,
_ULL(0x8A781B1B41F1873E) /* 860 */, _ULL(0xA5C94C78A0D2F0E7) /* 861 */,
_ULL(0x39412E2877B60728) /* 862 */, _ULL(0xA1265EF3AFC9A62C) /* 863 */,
_ULL(0xBCC2770C6A2506C5) /* 864 */, _ULL(0x3AB66DD5DCE1CE12) /* 865 */,
_ULL(0xE65499D04A675B37) /* 866 */, _ULL(0x7D8F523481BFD216) /* 867 */,
_ULL(0x0F6F64FCEC15F389) /* 868 */, _ULL(0x74EFBE618B5B13C8) /* 869 */,
_ULL(0xACDC82B714273E1D) /* 870 */, _ULL(0xDD40BFE003199D17) /* 871 */,
_ULL(0x37E99257E7E061F8) /* 872 */, _ULL(0xFA52626904775AAA) /* 873 */,
_ULL(0x8BBBF63A463D56F9) /* 874 */, _ULL(0xF0013F1543A26E64) /* 875 */,
_ULL(0xA8307E9F879EC898) /* 876 */, _ULL(0xCC4C27A4150177CC) /* 877 */,
_ULL(0x1B432F2CCA1D3348) /* 878 */, _ULL(0xDE1D1F8F9F6FA013) /* 879 */,
_ULL(0x606602A047A7DDD6) /* 880 */, _ULL(0xD237AB64CC1CB2C7) /* 881 */,
_ULL(0x9B938E7225FCD1D3) /* 882 */, _ULL(0xEC4E03708E0FF476) /* 883 */,
_ULL(0xFEB2FBDA3D03C12D) /* 884 */, _ULL(0xAE0BCED2EE43889A) /* 885 */,
_ULL(0x22CB8923EBFB4F43) /* 886 */, _ULL(0x69360D013CF7396D) /* 887 */,
_ULL(0x855E3602D2D4E022) /* 888 */, _ULL(0x073805BAD01F784C) /* 889 */,
_ULL(0x33E17A133852F546) /* 890 */, _ULL(0xDF4874058AC7B638) /* 891 */,
_ULL(0xBA92B29C678AA14A) /* 892 */, _ULL(0x0CE89FC76CFAADCD) /* 893 */,
_ULL(0x5F9D4E0908339E34) /* 894 */, _ULL(0xF1AFE9291F5923B9) /* 895 */,
_ULL(0x6E3480F60F4A265F) /* 896 */, _ULL(0xEEBF3A2AB29B841C) /* 897 */,
_ULL(0xE21938A88F91B4AD) /* 898 */, _ULL(0x57DFEFF845C6D3C3) /* 899 */,
_ULL(0x2F006B0BF62CAAF2) /* 900 */, _ULL(0x62F479EF6F75EE78) /* 901 */,
_ULL(0x11A55AD41C8916A9) /* 902 */, _ULL(0xF229D29084FED453) /* 903 */,
_ULL(0x42F1C27B16B000E6) /* 904 */, _ULL(0x2B1F76749823C074) /* 905 */,
_ULL(0x4B76ECA3C2745360) /* 906 */, _ULL(0x8C98F463B91691BD) /* 907 */,
_ULL(0x14BCC93CF1ADE66A) /* 908 */, _ULL(0x8885213E6D458397) /* 909 */,
_ULL(0x8E177DF0274D4711) /* 910 */, _ULL(0xB49B73B5503F2951) /* 911 */,
_ULL(0x10168168C3F96B6B) /* 912 */, _ULL(0x0E3D963B63CAB0AE) /* 913 */,
_ULL(0x8DFC4B5655A1DB14) /* 914 */, _ULL(0xF789F1356E14DE5C) /* 915 */,
_ULL(0x683E68AF4E51DAC1) /* 916 */, _ULL(0xC9A84F9D8D4B0FD9) /* 917 */,
_ULL(0x3691E03F52A0F9D1) /* 918 */, _ULL(0x5ED86E46E1878E80) /* 919 */,
_ULL(0x3C711A0E99D07150) /* 920 */, _ULL(0x5A0865B20C4E9310) /* 921 */,
_ULL(0x56FBFC1FE4F0682E) /* 922 */, _ULL(0xEA8D5DE3105EDF9B) /* 923 */,
_ULL(0x71ABFDB12379187A) /* 924 */, _ULL(0x2EB99DE1BEE77B9C) /* 925 */,
_ULL(0x21ECC0EA33CF4523) /* 926 */, _ULL(0x59A4D7521805C7A1) /* 927 */,
_ULL(0x3896F5EB56AE7C72) /* 928 */, _ULL(0xAA638F3DB18F75DC) /* 929 */,
_ULL(0x9F39358DABE9808E) /* 930 */, _ULL(0xB7DEFA91C00B72AC) /* 931 */,
_ULL(0x6B5541FD62492D92) /* 932 */, _ULL(0x6DC6DEE8F92E4D5B) /* 933 */,
_ULL(0x353F57ABC4BEEA7E) /* 934 */, _ULL(0x735769D6DA5690CE) /* 935 */,
_ULL(0x0A234AA642391484) /* 936 */, _ULL(0xF6F9508028F80D9D) /* 937 */,
_ULL(0xB8E319A27AB3F215) /* 938 */, _ULL(0x31AD9C1151341A4D) /* 939 */,
_ULL(0x773C22A57BEF5805) /* 940 */, _ULL(0x45C7561A07968633) /* 941 */,
_ULL(0xF913DA9E249DBE36) /* 942 */, _ULL(0xDA652D9B78A64C68) /* 943 */,
_ULL(0x4C27A97F3BC334EF) /* 944 */, _ULL(0x76621220E66B17F4) /* 945 */,
_ULL(0x967743899ACD7D0B) /* 946 */, _ULL(0xF3EE5BCAE0ED6782) /* 947 */,
_ULL(0x409F753600C879FC) /* 948 */, _ULL(0x06D09A39B5926DB6) /* 949 */,
_ULL(0x6F83AEB0317AC588) /* 950 */, _ULL(0x01E6CA4A86381F21) /* 951 */,
_ULL(0x66FF3462D19F3025) /* 952 */, _ULL(0x72207C24DDFD3BFB) /* 953 */,
_ULL(0x4AF6B6D3E2ECE2EB) /* 954 */, _ULL(0x9C994DBEC7EA08DE) /* 955 */,
_ULL(0x49ACE597B09A8BC4) /* 956 */, _ULL(0xB38C4766CF0797BA) /* 957 */,
_ULL(0x131B9373C57C2A75) /* 958 */, _ULL(0xB1822CCE61931E58) /* 959 */,
_ULL(0x9D7555B909BA1C0C) /* 960 */, _ULL(0x127FAFDD937D11D2) /* 961 */,
_ULL(0x29DA3BADC66D92E4) /* 962 */, _ULL(0xA2C1D57154C2ECBC) /* 963 */,
_ULL(0x58C5134D82F6FE24) /* 964 */, _ULL(0x1C3AE3515B62274F) /* 965 */,
_ULL(0xE907C82E01CB8126) /* 966 */, _ULL(0xF8ED091913E37FCB) /* 967 */,
_ULL(0x3249D8F9C80046C9) /* 968 */, _ULL(0x80CF9BEDE388FB63) /* 969 */,
_ULL(0x1881539A116CF19E) /* 970 */, _ULL(0x5103F3F76BD52457) /* 971 */,
_ULL(0x15B7E6F5AE47F7A8) /* 972 */, _ULL(0xDBD7C6DED47E9CCF) /* 973 */,
_ULL(0x44E55C410228BB1A) /* 974 */, _ULL(0xB647D4255EDB4E99) /* 975 */,
_ULL(0x5D11882BB8AAFC30) /* 976 */, _ULL(0xF5098BBB29D3212A) /* 977 */,
_ULL(0x8FB5EA14E90296B3) /* 978 */, _ULL(0x677B942157DD025A) /* 979 */,
_ULL(0xFB58E7C0A390ACB5) /* 980 */, _ULL(0x89D3674C83BD4A01) /* 981 */,
_ULL(0x9E2DA4DF4BF3B93B) /* 982 */, _ULL(0xFCC41E328CAB4829) /* 983 */,
_ULL(0x03F38C96BA582C52) /* 984 */, _ULL(0xCAD1BDBD7FD85DB2) /* 985 */,
_ULL(0xBBB442C16082AE83) /* 986 */, _ULL(0xB95FE86BA5DA9AB0) /* 987 */,
_ULL(0xB22E04673771A93F) /* 988 */, _ULL(0x845358C9493152D8) /* 989 */,
_ULL(0xBE2A488697B4541E) /* 990 */, _ULL(0x95A2DC2DD38E6966) /* 991 */,
_ULL(0xC02C11AC923C852B) /* 992 */, _ULL(0x2388B1990DF2A87B) /* 993 */,
_ULL(0x7C8008FA1B4F37BE) /* 994 */, _ULL(0x1F70D0C84D54E503) /* 995 */,
_ULL(0x5490ADEC7ECE57D4) /* 996 */, _ULL(0x002B3C27D9063A3A) /* 997 */,
_ULL(0x7EAEA3848030A2BF) /* 998 */, _ULL(0xC602326DED2003C0) /* 999 */,
_ULL(0x83A7287D69A94086) /* 1000 */, _ULL(0xC57A5FCB30F57A8A) /* 1001 */,
_ULL(0xB56844E479EBE779) /* 1002 */, _ULL(0xA373B40F05DCBCE9) /* 1003 */,
_ULL(0xD71A786E88570EE2) /* 1004 */, _ULL(0x879CBACDBDE8F6A0) /* 1005 */,
_ULL(0x976AD1BCC164A32F) /* 1006 */, _ULL(0xAB21E25E9666D78B) /* 1007 */,
_ULL(0x901063AAE5E5C33C) /* 1008 */, _ULL(0x9818B34448698D90) /* 1009 */,
_ULL(0xE36487AE3E1E8ABB) /* 1010 */, _ULL(0xAFBDF931893BDCB4) /* 1011 */,
_ULL(0x6345A0DC5FBBD519) /* 1012 */, _ULL(0x8628FE269B9465CA) /* 1013 */,
_ULL(0x1E5D01603F9C51EC) /* 1014 */, _ULL(0x4DE44006A15049B7) /* 1015 */,
_ULL(0xBF6C70E5F776CBB1) /* 1016 */, _ULL(0x411218F2EF552BED) /* 1017 */,
_ULL(0xCB0C0708705A36A3) /* 1018 */, _ULL(0xE74D14754F986044) /* 1019 */,
_ULL(0xCD56D9430EA8280E) /* 1020 */, _ULL(0xC12591D7535F5065) /* 1021 */,
_ULL(0xC83223F1720AEF96) /* 1022 */, _ULL(0xC3A0396F7363A51F) /* 1023 */
};
}

66
src/adchpp/TigerHash.h Normal file
View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_TIGER_HASH_H
#define ADCHPP_TIGER_HASH_H
namespace adchpp {
class TigerHash : private boost::noncopyable {
public:
/** Hash size */
static const size_t BITS = 192;
static const size_t BYTES = BITS / 8;
TigerHash() : pos(0) {
res[0]=_ULL(0x0123456789ABCDEF);
res[1]=_ULL(0xFEDCBA9876543210);
res[2]=_ULL(0xF096A5B4C3B2E187);
}
TigerHash(uint64_t pos, uint64_t initial_res[3]) : pos(pos) {
res[0] = initial_res[0];
res[1] = initial_res[1];
res[2] = initial_res[2];
}
~TigerHash() { }
/** Calculates the Tiger hash of the data. */
ADCHPP_DLL void update(const void* data, size_t len);
/** Call once all data has been processed. */
ADCHPP_DLL uint8_t* finalize();
uint8_t* getResult() { return (uint8_t*) res; }
private:
enum { BLOCK_SIZE = 512/8 };
/** 512 bit blocks for the compress function */
uint8_t tmp[512/8];
/** State / final hash value */
uint64_t res[3];
/** Total number of bytes compressed */
uint64_t pos;
/** S boxes */
static uint64_t table[];
void tigerCompress(const uint64_t* data, uint64_t state[3]);
};
}
#endif // _TIGER_HASH

14
src/adchpp/TimeUtil.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef ADCHPP_ADCHPP_TIME_H_
#define ADCHPP_ADCHPP_TIME_H_
#include <boost/date_time/posix_time/posix_time.hpp>
namespace adchpp {
namespace time {
using namespace boost::posix_time;
inline ptime now() { return microsec_clock::local_time(); }
}
}
#endif /* TIME_H_ */

365
src/adchpp/Util.cpp Normal file
View File

@ -0,0 +1,365 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include <random>
#include "Util.h"
#include "FastAlloc.h"
#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/utsname.h>
#include <ctype.h>
#endif
#include "TimeUtil.h"
namespace adchpp {
using namespace std;
#ifdef NDEBUG
FastMutex FastAllocBase::mtx;
#endif
#ifndef _WIN32
string Util::appName;
string Util::appPath;
#endif
string Util::emptyString;
wstring Util::emptyStringW;
/**
* Decodes a URL the best it can...
* Default ports:
* http:// -> port 80
* dchub:// -> port 411
*/
void Util::decodeUrl(const string& url, string& aServer, short& aPort, string& aFile) {
// First, check for a protocol: xxxx://
string::size_type i = 0, j, k;
aServer.clear();
aFile.clear();
if( (j=url.find("://", i)) != string::npos) {
// Protocol found
string protocol = url.substr(0, j);
i = j + 3;
if(protocol == "http") {
aPort = 80;
} else if(protocol == "dchub") {
aPort = 411;
}
}
if( (j=url.find('/', i)) != string::npos) {
// We have a filename...
aFile = url.substr(j);
}
if( (k=url.find(':', i)) != string::npos) {
// Port
if(k < j)
aPort = (short)Util::toInt(url.substr(k+1, j-k-1));
} else {
k = j;
}
// Only the server should be left now...
aServer = url.substr(i, k-i);
}
void Util::tokenize(StringList& lst, const string& str, char sep, string::size_type j) {
string::size_type i = 0;
while( (i=str.find_first_of(sep, j)) != string::npos ) {
lst.push_back(str.substr(j, i-j));
j = i + 1;
}
if(j <= str.size())
lst.push_back(str.substr(j, str.size()-j));
}
#ifdef _WIN32
string Util::getAppPath() {
string tmp = getAppName();
string::size_type i = tmp.rfind('\\');
if(i != string::npos)
tmp.erase(i+1);
return tmp;
}
string Util::getAppName() {
string tmp(MAX_PATH + 1, '\0');
tmp.resize(::GetModuleFileNameA(NULL, &tmp[0], MAX_PATH));
return tmp;
}
#else // WIN32
void Util::setApp(const string& app) {
string::size_type i = app.rfind('/');
if(i != string::npos) {
appPath = app.substr(0, i+1);
appName = app;
}
}
string Util::getAppPath() {
return appPath;
}
string Util::getAppName() {
return appName;
}
#endif // WIN32
string Util::getLocalIp() {
string tmp;
char buf[256];
gethostname(buf, 255);
hostent* he = gethostbyname(buf);
if(he == NULL || he->h_addr_list[0] == 0)
return Util::emptyString;
sockaddr_in dest;
int i = 0;
// We take the first ip as default, but if we can find a better one, use it instead...
memcpy(&(dest.sin_addr), he->h_addr_list[i++], he->h_length);
tmp = inet_ntoa(dest.sin_addr);
if( strncmp(tmp.c_str(), "192", 3) == 0 ||
strncmp(tmp.c_str(), "169", 3) == 0 ||
strncmp(tmp.c_str(), "127", 3) == 0 ||
strncmp(tmp.c_str(), "10", 2) == 0 ) {
while(he->h_addr_list[i]) {
memcpy(&(dest.sin_addr), he->h_addr_list[i], he->h_length);
string tmp2 = inet_ntoa(dest.sin_addr);
if( strncmp(tmp2.c_str(), "192", 3) != 0 &&
strncmp(tmp2.c_str(), "169", 3) != 0 &&
strncmp(tmp2.c_str(), "127", 3) != 0 &&
strncmp(tmp2.c_str(), "10", 2) != 0) {
tmp = tmp2;
}
i++;
}
}
return tmp;
}
string Util::formatBytes(int64_t aBytes) {
char buf[64];
if(aBytes < 1024) {
sprintf(buf, "%d B", (int)(aBytes&0xffffffff));
} else if(aBytes < 1024*1024) {
sprintf(buf, "%.02f KiB", (double)aBytes/(1024.0));
} else if(aBytes < 1024*1024*1024) {
sprintf(buf, "%.02f MiB", (double)aBytes/(1024.0*1024.0));
} else if(aBytes < (int64_t)1024*1024*1024*1024) {
sprintf(buf, "%.02f GiB", (double)aBytes/(1024.0*1024.0*1024.0));
} else {
sprintf(buf, "%.02f TiB", (double)aBytes/(1024.0*1024.0*1024.0*1024.0));
}
return buf;
}
string Util::getShortTimeString() {
char buf[8];
time_t _tt;
std::time(&_tt);
tm* _tm = localtime(&_tt);
strftime(buf, 8, "%H:%M", _tm);
return buf;
}
string Util::getTimeString() {
char buf[64];
time_t _tt;
std::time(&_tt);
tm* _tm = localtime(&_tt);
if(_tm == NULL) {
strcpy(buf, "xx:xx:xx");
} else {
strftime(buf, 64, "%X", _tm);
}
return buf;
}
string Util::formatTime(const string& msg, time_t t /* = time(NULL) */) {
size_t bufsize = msg.size() + 64;
char* buf = new char[bufsize];
while(!strftime(buf, bufsize-1, msg.c_str(), localtime(&t))) {
delete buf;
bufsize+=64;
buf = new char[bufsize];
}
string result = buf;
delete[] buf;
return result;
}
string Util::translateError(int aError) {
#ifdef _WIN32
LPVOID lpMsgBuf;
::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
aError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
#ifdef _UNICODE
string tmp = Util::toAcp((LPCTSTR)lpMsgBuf);
#else
string tmp = (LPCTSTR)lpMsgBuf;
#endif
// Free the buffer.
LocalFree( lpMsgBuf );
#else // WIN32
string tmp = strerror(aError);
#endif // WIN32
string::size_type i = 0;
while( (i = tmp.find_first_of("\r\n", i)) != string::npos) {
tmp.erase(i, 1);
}
return tmp;
}
string Util::getOsVersion() {
#ifdef _WIN32
string os;
OSVERSIONINFOEX ver;
memset(&ver, 0, sizeof(OSVERSIONINFOEX));
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if(!GetVersionEx((OSVERSIONINFO*)&ver)) {
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(!GetVersionEx((OSVERSIONINFO*)&ver)) {
os = "Windows (version unknown)";
}
}
if(os.empty()) {
if(ver.dwPlatformId != VER_PLATFORM_WIN32_NT) {
os = "Win9x/ME/Junk";
} else if(ver.dwMajorVersion == 4) {
os = "WinNT4";
} else if(ver.dwMajorVersion == 5) {
if(ver.dwMinorVersion == 0) {
os = "Win2000";
} else if(ver.dwMinorVersion == 1) {
os = "WinXP";
} else if(ver.dwMinorVersion == 2) {
os = "Win2003";
} else {
os = "WinUnknown";
}
if(ver.wProductType == VER_NT_WORKSTATION)
os += " Pro";
else if(ver.wProductType == VER_NT_SERVER)
os += " Server";
else if(ver.wProductType == VER_NT_DOMAIN_CONTROLLER)
os += " DC";
}
if(ver.wServicePackMajor > 0) {
os += " SP" + Util::toString(ver.wServicePackMajor);
}
}
return os;
#else // WIN32
utsname n;
if(uname(&n) != 0) {
return "unix (unknown version)";
}
return string(n.sysname) + " " + string(n.release) + " (" + string(n.machine) + ")";
#endif // WIN32
}
#ifdef __MINGW32__
// creating a random_device throws an exception in MinGW with GCC 4.6; simpler alternative...
uint32_t Util::rand() {
static bool init = false;
if(!init) {
::srand(::time(0));
init = true;
}
return ::rand();
}
#else
uint32_t Util::rand() {
static std::random_device rd;
static std::default_random_engine dre(rd());
return dre();
}
#endif
bool Util::isPrivateIp(std::string const& ip) {
struct in_addr addr;
addr.s_addr = inet_addr(ip.c_str());
if (addr.s_addr != INADDR_NONE) {
unsigned long haddr = ntohl(addr.s_addr);
return ((haddr & 0xff000000) == 0x0a000000 || // 10.0.0.0/8
(haddr & 0xff000000) == 0x7f000000 || // 127.0.0.0/8
(haddr & 0xfff00000) == 0xac100000 || // 172.16.0.0/12
(haddr & 0xffff0000) == 0xc0a80000); // 192.168.0.0/16
}
return false;
}
bool Util::validateCharset(std::string const& field, int p) {
for(string::size_type i = 0; i < field.length(); ++i) {
if((uint8_t) field[i] < p) {
return false;
}
}
return true;
}
}

237
src/adchpp/Util.h Normal file
View File

@ -0,0 +1,237 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_UTIL_H
#define ADCHPP_UTIL_H
#include "common.h"
namespace adchpp {
/** Evaluates op(pair<T1, T2>.first, compareTo) */
template<class T1, class T2, class op = std::equal_to<T1> >
class CompareFirst {
public:
CompareFirst(const T1& compareTo) : a(compareTo) { }
bool operator()(const std::pair<T1, T2>& p) { return op()(p.first, a); }
private:
CompareFirst& operator=(const CompareFirst&);
const T1& a;
};
/** Evaluates op(pair<T1, T2>.second, compareTo) */
template<class T1, class T2, class op = std::equal_to<T2> >
class CompareSecond {
public:
CompareSecond(const T2& compareTo) : a(compareTo) { }
bool operator()(const std::pair<T1, T2>& p) { return op()(p.second, a); }
private:
CompareSecond& operator=(const CompareSecond&);
const T2& a;
};
struct DeleteFunction {
template<typename T>
void operator()(T* ptr) { delete ptr; }
};
/**
* Compares two values
* @return -1 if v1 < v2, 0 if v1 == v2 and 1 if v1 > v2
*/
template<typename T1>
inline int compare(const T1& v1, const T1& v2) { return (v1 < v2) ? -1 : ((v1 == v2) ? 0 : 1); }
class Flags {
public:
typedef size_t MaskType;
Flags() : flags(0) { }
Flags(const Flags& rhs) : flags(rhs.flags) { }
Flags(MaskType f) : flags(f) { }
MaskType getFlags() const { return flags; }
bool isSet(MaskType aFlag) const { return (flags & aFlag) == aFlag; }
bool isAnySet(MaskType aFlag) const { return (flags & aFlag) != 0; }
void setFlag(MaskType aFlag) { flags |= aFlag; }
void unsetFlag(MaskType aFlag) { flags &= ~aFlag; }
Flags& operator=(const Flags& rhs) { flags = rhs.flags; return *this; }
private:
MaskType flags;
};
class Util
{
public:
enum Reason {
REASON_BAD_STATE,
REASON_CID_CHANGE,
REASON_CID_TAKEN,
REASON_FLOODING,
REASON_HUB_FULL,
REASON_INVALID_COMMAND_TYPE,
REASON_INVALID_IP,
REASON_INVALID_SID,
REASON_LOGIN_TIMEOUT,
REASON_MAX_COMMAND_SIZE,
REASON_NICK_INVALID,
REASON_NICK_TAKEN,
REASON_NO_BASE_SUPPORT,
REASON_NO_TIGR_SUPPORT,
REASON_PID_MISSING,
REASON_PID_CID_LENGTH,
REASON_PID_CID_MISMATCH,
REASON_PID_WITHOUT_CID,
REASON_PLUGIN,
REASON_WRITE_OVERFLOW,
REASON_NO_BANDWIDTH,
REASON_INVALID_DESCRIPTION,
REASON_WRITE_TIMEOUT,
REASON_SOCKET_ERROR,
REASON_LAST,
};
ADCHPP_DLL static std::string emptyString;
static std::wstring emptyStringW;
ADCHPP_DLL static std::string getOsVersion();
ADCHPP_DLL static void decodeUrl(const std::string& aUrl, std::string& aServer, short& aPort, std::string& aFile);
ADCHPP_DLL static std::string formatTime(const std::string& msg, time_t t = std::time(NULL));
ADCHPP_DLL static std::string getAppPath();
ADCHPP_DLL static std::string getAppName();
#ifndef _WIN32
ADCHPP_DLL static void setApp(const std::string& app);
static std::string appPath;
static std::string appName;
#endif
ADCHPP_DLL static std::string translateError(int aError);
static std::string formatBytes(const std::string& aString) { return formatBytes(toInt64(aString)); }
ADCHPP_DLL static std::string getShortTimeString();
ADCHPP_DLL static std::string getTimeString();
ADCHPP_DLL static std::string formatBytes(int64_t aBytes);
ADCHPP_DLL static void tokenize(StringList& lst, const std::string& str, char sep, std::string::size_type j = 0);
static std::string formatSeconds(int64_t aSec) {
char buf[64];
sprintf(buf, "%01d:%02d:%02d:%02d", (int)(aSec / (24*60*60)), (int)((aSec / (60*60)) % 24), (int)((aSec / 60) % 60), (int)(aSec % 60));
return buf;
}
static bool toBool(const std::string& aString) { return toBool(aString.c_str()); }
static int toInt(const std::string& aString) { return toInt(aString.c_str()); }
static double toDouble(const std::string& aString) { return toDouble(aString.c_str()); }
static float toFloat(const std::string& aString) { return toFloat(aString.c_str()); }
static int64_t toInt64(const std::string& aString) { return toInt64(aString.c_str()); }
static bool toBool(const char* aString) { return toInt(aString) > 0; }
static int toInt(const char* aString) { return ::atoi(aString); }
static double toDouble(const char* aString) { return ::atof(aString); }
static float toFloat(const char* aString) { return (float)::atof(aString); }
static int64_t toInt64(const char* aString) {
#ifdef _MSC_VER
return _atoi64(aString);
#else
return atoll(aString);
#endif
}
static std::string toString(bool val) {
return val ? "1" : "0";
}
static std::string toString(short val) {
char buf[8];
sprintf(buf, "%d", (int)val);
return buf;
}
static std::string toString(unsigned short val) {
char buf[8];
sprintf(buf, "%u", (unsigned int)val);
return buf;
}
static std::string toString(int val) {
char buf[16];
sprintf(buf, "%d", val);
return buf;
}
static std::string toString(unsigned int val) {
char buf[16];
sprintf(buf, "%u", val);
return buf;
}
static std::string toString(long val) {
char buf[32];
sprintf(buf, "%ld", val);
return buf;
}
static std::string toString(unsigned long val) {
char buf[32];
sprintf(buf, "%lu", val);
return buf;
}
static std::string toString(long long val) {
char buf[32];
#if defined(_MSC_VER) || defined(__MINGW32__)
sprintf(buf, "%I64d", val);
#else
sprintf(buf, "%lld", val);
#endif
return buf;
}
static std::string toString(unsigned long long val) {
char buf[32];
#if defined(_MSC_VER) || defined(__MINGW32__)
sprintf(buf, "%I64u", val);
#else
sprintf(buf, "%llu", val);
#endif
return buf;
}
static std::string toString(double val, int maxDec = 2) {
char buf[32];
sprintf(buf, "%.*f", maxDec, val);
return buf;
}
static const std::string& toString(const std::string& aString) {
return aString;
}
/** Avoid this! Use the one of a connected socket instead... */
ADCHPP_DLL static std::string getLocalIp();
ADCHPP_DLL static uint32_t rand();
static uint32_t rand(uint32_t high) { return rand() % high; }
static uint32_t rand(uint32_t low, uint32_t high) { return rand(high-low) + low; }
static double randd() { return ((double)rand()) / ((double)0xffffffff); }
ADCHPP_DLL static bool isPrivateIp(std::string const& ip);
ADCHPP_DLL static bool validateCharset(std::string const& field, int p);
};
}
#endif // UTIL_H

19
src/adchpp/adchpp.cpp Normal file
View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"

75
src/adchpp/adchpp.h Normal file
View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_ADCHPP_H
#define ADCHPP_ADCHPP_H
#include "compiler.h"
#include "config.h"
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#include <tchar.h>
#else
#include <sys/time.h>
#endif
#include <cerrno>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <ctime>
#include <string>
#include <vector>
#include <list>
#include <functional>
#include <memory>
#include <algorithm>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include "shared_ptr.h"
#include "nullptr.h"
#include <boost/noncopyable.hpp>
#ifdef _UNICODE
# ifndef _T
# define _T(s) L##s
# endif
#else
# ifndef _T
# define _T(s) s
# endif
#endif
#if defined(max) || defined(min)
#error min/max defined
#endif
#endif // STDINC_H

42
src/adchpp/common.cpp Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "File.h"
namespace adchpp {
using namespace std;
const char compileTime[] = __DATE__ " " __TIME__;
//#ifdef _DEBUG
void logAssert(const char* file, int line, const char* exp) {
try {
//File f(Util::getCfgPath() + _T("exceptioninfo.txt"), File::WRITE, File::OPEN | File::CREATE);
//f.setEndPos(0);
//f.write(string(file) + "(" + Util::toString(line) + "): " + string(exp) + "\r\n");
} catch (const FileException& e) {
dcdebug("logAssert: %s\n", e.getError().c_str());
}
}
//#endif // _DEBUG
}

91
src/adchpp/common.h Normal file
View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
/**
* @mainpage
*
* ADCH++ is a server application meant to be used in the Direct Connect network,
* released under the GPL-2 license.
*
* There's a plugin API about which you can find some general
* information on the @ref PluginAPI page.
*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*
* Please see License.txt for full details regarding licensing.
*/
#ifndef ADCHPP_COMMON_H
#define ADCHPP_COMMON_H
namespace adchpp {
extern ADCHPP_DLL const char compileTime[];
extern ADCHPP_DLL void logAssert(const char* file, int line, const char* exp);
#ifndef NDEBUG
inline void debugTrace(const char* format, ...)
{
va_list args;
va_start(args, format);
#ifdef _MSC_VER
char buf[512];
_vsnprintf(buf, sizeof(buf), format, args);
OutputDebugStringA(buf);
fputs(buf, stderr);
#else // _MSC_VER
vfprintf(stdout, format, args);
#endif // _MSC_VER
va_end(args);
}
#define dcdebug debugTrace
#define dcassert(exp) do { if(!(exp)) logAssert(__FILE__, __LINE__, #exp); } while(false)
//#define dcassert(exp) do { if(!(exp)) __asm { int 3}; } while(0)
#define dcasserta(exp) dcassert(exp)
#define dcdrun(exp) exp
#else //NDEBUG
#define dcdebug if(false) printf
//#define dcassert(exp) do { if(!(exp)) logAssert(__FILE__, __LINE__, #exp); } while(0)
#define dcassert(exp)
#ifdef _MSC_VER
#define dcasserta(exp) __assume(exp)
#else
#define dcasserta(exp)
#endif // WIN32
#define dcdrun(exp)
#endif //NDEBUG
typedef std::vector<std::string> StringList;
typedef StringList::iterator StringIter;
typedef StringList::const_iterator StringIterC;
typedef std::vector<uint8_t> ByteVector;
typedef ByteVector::iterator ByteIter;
}
#endif // COMMON_H

37
src/adchpp/compiler.h Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#if defined(__GNUC__)
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)
#error GCC 4.4 is required
#endif
#if __GNUC_MINOR__ == 4
// GCC 4.4 is missing this type
#define default_random_engine minstd_rand0
#endif
#elif defined(_MSC_VER)
#if _MSC_VER < 1600
#error MSVC 10 (2010) is required
#endif
#else
#error No supported compiler found
#endif

91
src/adchpp/config.h Normal file
View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_ADCHPP_CONFIG_H_
#define ADCHPP_ADCHPP_CONFIG_H_
#ifndef _REENTRANT
# define _REENTRANT 1
#endif
#ifdef _MSC_VER
//disable the deprecated warnings for the CRT functions.
# define _CRT_SECURE_NO_DEPRECATE 1
# define _ATL_SECURE_NO_DEPRECATE 1
# define _CRT_NON_CONFORMING_SWPRINTFS 1
#endif
#if defined(_MSC_VER) || defined(__MINGW32__)
# define _LL(x) x##ll
# define _ULL(x) x##ull
# define I64_FMT "%I64d"
#elif defined(SIZEOF_LONG) && SIZEOF_LONG == 8
# define _LL(x) x##l
# define _ULL(x) x##ul
# define I64_FMT "%ld"
#else
# define _LL(x) x##ll
# define _ULL(x) x##ull
# define I64_FMT "%lld"
#endif
#ifdef _WIN32
#define PATH_SEPARATOR '\\'
#define PATH_SEPARATOR_STR "\\"
#else
#define PATH_SEPARATOR '/'
#define PATH_SEPARATOR_STR "/"
#endif
#ifdef _WIN32
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0501
# endif
# ifndef _WIN32_IE
# define _WIN32_IE 0x0501
# endif
# ifndef WINVER
# define WINVER 0x0501
# endif
# ifndef STRICT
# define STRICT 1
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN 1
# endif
# ifndef NOMINMAX
# define NOMINMAX
# endif
# define ADCHPP_VISIBLE
# ifdef BUILDING_ADCHPP
# define ADCHPP_DLL __declspec(dllexport)
# else
# define ADCHPP_DLL __declspec(dllimport)
# endif // DLLEXPORT
#else
# define ADCHPP_DLL __attribute__ ((visibility("default")))
# define ADCHPP_VISIBLE __attribute__ ((visibility("default")))
#endif
#endif /* CONFIG_H_ */

56
src/adchpp/forward.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_ADCHPP_FORWARD_H_
#define ADCHPP_ADCHPP_FORWARD_H_
#include <vector>
#include "shared_ptr.h"
namespace adchpp {
class Client;
class ClientManager;
class Core;
class Entity;
class LogManager;
class ManagedSocket;
typedef shared_ptr<ManagedSocket> ManagedSocketPtr;
class PluginManager;
struct ServerInfo;
typedef shared_ptr<ServerInfo> ServerInfoPtr;
typedef std::vector<ServerInfoPtr> ServerInfoList;
class SimpleXML;
class SocketFactory;
typedef shared_ptr<SocketFactory> SocketFactoryPtr;
class SocketManager;
}
#endif /*FORWARD_H_*/

27
src/adchpp/nullptr.h Normal file
View File

@ -0,0 +1,27 @@
// for compilers that don't support nullptr, use the workaround in section 1.1 of the proposal.
#ifndef ADCHPP_NULLPTR_H
#define ADCHPP_NULLPTR_H
#ifdef __GNUC__
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) // GCC 4.6 is the first GCC to implement nullptr.
#define FAKE_NULLPTR
const // this is a const object...
class {
public:
template<class T> // convertible to any type
operator T*() const // of null non-member
{ return 0; } // pointer...
template<class C, class T> // or any type of null
operator T C::*() const // member pointer...
{ return 0; }
private:
void operator&() const; // whose address can't be taken
} nullptr = {}; // and whose name is nullptr
#endif
#endif
#endif // ADCHPP_NULLPTR_H

58
src/adchpp/shared_ptr.h Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_ADCHPP_SHARED_PTR_H_
#define ADCHPP_ADCHPP_SHARED_PTR_H_
#ifdef __MINGW32__
/* the shared_ptr implementation provided by MinGW / GCC 4.5's libstdc++ consumes too many
semaphores, so we prefer boost's one. see <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46455>. */
// enabling this on newer GCC versions as well as handle leaks still appear when running scripts.
/// @todo hopefully remove this someday...
#define BOOST_ASIO_DISABLE_STD_SHARED_PTR 1
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
#define SHARED_PTR_NS boost
#else
#include <memory>
#define SHARED_PTR_NS std
#endif
namespace adchpp {
using SHARED_PTR_NS::shared_ptr;
using SHARED_PTR_NS::make_shared;
using SHARED_PTR_NS::enable_shared_from_this;
using SHARED_PTR_NS::static_pointer_cast;
using SHARED_PTR_NS::dynamic_pointer_cast;
}
#undef SHARED_PTR_NS
#endif /* SHARED_PTR_H_ */

50
src/adchpp/version.cpp Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include "adchpp.h"
#include "version.h"
#ifndef ADCHPP_REVISION
#define ADCHPP_REVISION 0
#endif
#define xstrver(s) strver(s)
#define strver(s) #s
// don't forget to also update the .rc file of adchppd!
#define APPNAME "ADCH++"
#define VERSIONSTRING "2.12.1 (r\"" xstrver(ADCHPP_REVISION) "\")"
#define VERSIONFLOAT 2.96
#ifndef NDEBUG
#define BUILDSTRING "Debug"
#else
#define BUILDSTRING "Release"
#endif
#define FULLVERSIONSTRING VERSIONSTRING " " BUILDSTRING
namespace adchpp {
using namespace std;
string appName = APPNAME;
string versionString = FULLVERSIONSTRING;
float versionFloat = VERSIONFLOAT;
}

31
src/adchpp/version.h Normal file
View File

@ -0,0 +1,31 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#ifndef ADCHPP_VERSION_H
#define ADCHPP_VERSION_H
namespace adchpp {
ADCHPP_DLL extern std::string appName;
ADCHPP_DLL extern std::string versionString;
ADCHPP_DLL extern float versionFloat;
}
// This should be updated whenever the plugin API changes
#define PLUGINVERSION 1
#endif // VERSION_H

28
src/adchppd/SConscript Normal file
View File

@ -0,0 +1,28 @@
# vim: set filetype=py
Import('dev source_path')
env, target, sources = dev.prepare_build(source_path, 'adchppd', 'adchppd.cpp')
if dev.is_win32():
sources += [dev.get_build_path(source_path) + 'adchppdw.cpp', env.RES(dev.get_sources(source_path, 'res/*.rc'))]
else:
sources += [dev.get_build_path(source_path) + 'adchppdu.cpp']
env.Append(CPPPATH = ['.', '#'])
env.Append(LIBS=['adchpp'])
if env['CC'] == 'cl': # MSVC
from build_util import array_remove
array_remove(env['CCFLAGS'], '/LD')
array_remove(env['CCFLAGS'], '/LDd')
env.Append(LIBS = ['advapi32'])
#if env['nls']:
# headers=dev.get_sources(source_path, "*.h")
# dev.i18n(source_path, env, [sources,headers], 'adchppd')
ret = env.Program(target, sources)
Return('ret')

123
src/adchppd/adchppd.cpp Normal file
View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include <adchpp/adchpp.h>
#include <adchpp/common.h>
#include "adchppd.h"
#include <adchpp/Util.h>
#include <adchpp/ClientManager.h>
#include <adchpp/LogManager.h>
#include <adchpp/SocketManager.h>
#include <adchpp/PluginManager.h>
#include <adchpp/Entity.h>
#include <adchpp/File.h>
#include <adchpp/SimpleXML.h>
#include <adchpp/Core.h>
using namespace adchpp;
using namespace std;
void loadXML(Core &core, const string& aFileName)
{
try {
SimpleXML xml;
xml.fromXML(File(aFileName, File::READ, File::OPEN).read());
xml.resetCurrentChild();
xml.stepIn();
while(xml.findChild(Util::emptyString)) {
if(xml.getChildName() == "Settings") {
xml.stepIn();
while(xml.findChild(Util::emptyString)) {
printf("Processing %s\n", xml.getChildName().c_str());
if(xml.getChildName() == "HubName") {
core.getClientManager().getEntity(AdcCommand::HUB_SID)->setField("NI", xml.getChildData());
} else if(xml.getChildName() == "Description") {
core.getClientManager().getEntity(AdcCommand::HUB_SID)->setField("DE", xml.getChildData());
} else if(xml.getChildName() == "Log") {
core.getLogManager().setEnabled(xml.getChildData() == "1");
} else if(xml.getChildName() == "LogFile") {
core.getLogManager().setLogFile(xml.getChildData());
} else if(xml.getChildName() == "MaxCommandSize") {
core.getClientManager().setMaxCommandSize(Util::toInt(xml.getChildData()));
} else if(xml.getChildName() == "BufferSize") {
core.getSocketManager().setBufferSize(Util::toInt(xml.getChildData()));
} else if(xml.getChildName() == "MaxBufferSize") {
core.getSocketManager().setMaxBufferSize(Util::toInt(xml.getChildData()));
} else if(xml.getChildName() == "OverflowTimeout") {
core.getSocketManager().setOverflowTimeout(Util::toInt(xml.getChildData()));
} else if(xml.getChildName() == "DisconnectTimeout") {
core.getSocketManager().setDisconnectTimeout(Util::toInt(xml.getChildData()));
} else if(xml.getChildName() == "LogTimeout") {
core.getClientManager().setLogTimeout(Util::toInt(xml.getChildData()));
}
}
xml.stepOut();
} else if(xml.getChildName() == "Servers") {
xml.stepIn();
ServerInfoList servers;
while(xml.findChild("Server")) {
ServerInfoPtr server = make_shared<ServerInfo>();
server->port = xml.getChildAttrib("Port", Util::emptyString);
if(xml.getBoolChildAttrib("TLS")) {
server->TLSParams.cert = File::makeAbsolutePath(xml.getChildAttrib("Certificate"));
server->TLSParams.pkey = File::makeAbsolutePath(xml.getChildAttrib("PrivateKey"));
server->TLSParams.trustedPath = File::makeAbsolutePath(xml.getChildAttrib("TrustedPath"));
server->TLSParams.dh = File::makeAbsolutePath(xml.getChildAttrib("DHParams"));
}
#ifndef HAVE_OPENSSL
if(server->secure())
fprintf(stderr, "Error listening on port %s: This ADCH++ hasn't been compiled with support for secure connections\n", server->port.c_str());
else
#endif
servers.push_back(server);
}
core.getSocketManager().setServers(servers);
xml.stepOut();
} else if(xml.getChildName() == "Plugins") {
core.getPluginManager().setPluginPath(xml.getChildAttrib("Path"));
xml.stepIn();
StringList plugins;
while(xml.findChild("Plugin")) {
plugins.push_back(xml.getChildData());
}
core.getPluginManager().setPluginList(plugins);
xml.stepOut();
}
}
xml.stepOut();
} catch(const Exception& e) {
printf("Unable to load adchpp.xml, using defaults: %s\n", e.getError().c_str());
}
}

21
src/adchppd/adchppd.h Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include <adchpp/Core.h>
void loadXML(adchpp::Core &core, const std::string& fileName);

247
src/adchppd/adchppdu.cpp Normal file
View File

@ -0,0 +1,247 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include <adchpp/adchpp.h>
#include <adchpp/common.h>
#include <adchpp/Util.h>
#include <adchpp/version.h>
#include <adchpp/File.h>
#include <adchpp/Core.h>
#include <adchpp/shared_ptr.h>
#include <signal.h>
#include <limits.h>
#include <locale.h>
#include "adchppd.h"
using namespace std;
using namespace adchpp;
static FILE* pidFile;
static string pidFileName;
static bool asdaemon = false;
static shared_ptr<Core> core;
static void installHandler();
void breakHandler(int) {
if(core) {
core->shutdown();
}
installHandler();
}
static void init() {
// Ignore SIGPIPE...
struct sigaction sa = { 0 };
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigset_t mask;
sigfillset(&mask); /* Mask all allowed signals, the other threads should inherit
this... */
sigdelset(&mask, SIGCONT);
sigdelset(&mask, SIGFPE);
sigdelset(&mask, SIGILL);
sigdelset(&mask, SIGSEGV);
sigdelset(&mask, SIGBUS);
sigdelset(&mask, SIGINT);
sigdelset(&mask, SIGTRAP);
pthread_sigmask(SIG_SETMASK, &mask, NULL);
installHandler();
if(pidFile != NULL) {
fprintf(pidFile, "%d", (int)getpid());
fflush(pidFile);
}
loadXML(*core, File::makeAbsolutePath(core->getConfigPath(), "adchpp.xml"));
}
static void installHandler() {
struct sigaction sa = { 0 };
sa.sa_handler = breakHandler;
sigaction(SIGINT, &sa, NULL);
}
static void uninit() {
if(!asdaemon)
printf("Shut down");
if(pidFile != NULL)
fclose(pidFile);
pidFile = NULL;
if(!pidFileName.empty())
unlink(pidFileName.c_str());
}
#include <fcntl.h>
static void daemonize() {
switch(fork()) {
case -1:
fprintf(stderr, "First fork failed: %s\n", strerror(errno));
exit(5);
case 0: break;
default: _exit(0);
}
if(setsid() < 0) {
fprintf(stderr, "setsid failed: %s\n", strerror(errno));
exit(6);
}
switch(fork()) {
case -1:
fprintf(stderr, "Second fork failed: %s\n", strerror(errno));
exit(7);
case 0: break;
default: exit(0);
}
chdir("/");
close(0);
close(1);
close(2);
open("/dev/null", O_RDWR);
dup(0); dup(0);
}
#include <sys/wait.h>
static void runDaemon(const string& configPath) {
daemonize();
try {
core = Core::create(configPath);
init();
core->run();
core.reset();
} catch(const adchpp::Exception& e) {
fprintf(stderr, "Failed to start: %s\n", e.what());
}
uninit();
}
static void runConsole(const string& configPath) {
printf("Starting."); fflush(stdout);
try {
core = Core::create(configPath);
printf("."); fflush(stdout);
init();
printf(".\n%s running, press ctrl-c to exit...\n", versionString.c_str());
core->run();
core.reset();
} catch(const Exception& e) {
fprintf(stderr, "\nFATAL: Can't start ADCH++: %s\n", e.what());
}
uninit();
}
static void printUsage() {
printf("Usage: adchpp [[-c <configdir>] [-d]] | [-v] | [-h]\n");
}
int main(int argc, char* argv[]) {
setlocale(LC_ALL, "");
char buf[PATH_MAX + 1] = { 0 };
char* path = buf;
if (readlink("/proc/self/exe", buf, sizeof (buf)) == -1) {
path = getenv("_");
}
Util::setApp(path == NULL ? argv[0] : path);
string configPath = "/etc/adchpp/";
for(int i = 1; i < argc; i++) {
if(strcmp(argv[i], "-d") == 0) {
asdaemon = true;
} else if(strcmp(argv[i], "-v") == 0) {
printf("%s\n", versionString.c_str());
return 0;
} else if(strcmp(argv[i], "-c") == 0) {
if((i + 1) == argc) {
fprintf(stderr, "-c <directory>\n");
return 1;
}
i++;
string cfg = argv[i];
if(cfg[0] != '/') {
fprintf(stderr, "Config dir must be an absolute path\n");
return 2;
}
if(cfg[cfg.length() - 1] != '/') {
cfg+='/';
}
configPath = cfg;
} else if(strcmp(argv[i], "-p") == 0) {
if((i+1) == argc) {
fprintf(stderr, "-p <pid-file>\n");
return 1;
}
i++;
pidFileName = argv[i];
} else if(strcmp(argv[i], "-h") == 0) {
printUsage();
return 0;
} else {
fprintf(stderr, "Unknown parameter: %s\n", argv[i]);
return 4;
}
}
if(!pidFileName.empty()) {
pidFileName = File::makeAbsolutePath(configPath, pidFileName);
pidFile = fopen(pidFileName.c_str(), "w");
if(pidFile == NULL) {
fprintf(stderr, "Can't open %s for writing\n", pidFileName.c_str());
return 1;
}
}
if(asdaemon) {
runDaemon(configPath);
} else {
runConsole(configPath);
}
}

309
src/adchppd/adchppdw.cpp Normal file
View File

@ -0,0 +1,309 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*/
#include <adchpp/adchpp.h>
#include <adchpp/common.h>
#include <adchpp/LogManager.h>
#include <adchpp/Util.h>
#include <adchpp/version.h>
#include <adchpp/File.h>
#include <adchpp/shared_ptr.h>
#include "adchppd.h"
#include <locale.h>
using namespace adchpp;
using namespace std;
static const string modName = "adchpp";
#define LOGERROR(func) LOG(modName, func " failed: " + Util::translateError(GetLastError()))
#define PRINTERROR(func) fprintf(stderr, func " failed: code %lu: %s\n", GetLastError(), Util::translateError(GetLastError()).c_str())
bool asService = true;
static const TCHAR* serviceName = _T("adchpp");
static adchpp::shared_ptr<Core> core;
static string configPath;
static void installService() {
SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if(scm == NULL) {
PRINTERROR("OpenSCManager");
return;
}
string cmdLine = '"' + Util::getAppName() + "\" -c \"" + configPath + "\\\" -d \"" + string(serviceName) + "\"";
SC_HANDLE service = CreateService(scm, serviceName, serviceName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, cmdLine.c_str(),
NULL, NULL, NULL, NULL, NULL);
if(service == NULL) {
PRINTERROR("CreateService");
CloseServiceHandle(scm);
return;
}
SERVICE_DESCRIPTION description = { const_cast<LPTSTR>(cmdLine.c_str()) };
ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
fprintf(stdout, "ADCH++ service \"%s\" successfully installed; command line:\n%s\n", serviceName, cmdLine.c_str());
CloseServiceHandle(service);
CloseServiceHandle(scm);
}
static void removeService() {
SC_HANDLE scm = OpenSCManager(NULL, NULL, STANDARD_RIGHTS_WRITE);
if(scm == NULL) {
PRINTERROR("OpenSCManager");
return;
}
SC_HANDLE service = OpenService(scm, serviceName, DELETE);
if(service == NULL) {
PRINTERROR("OpenService");
CloseServiceHandle(scm);
return;
}
if(!DeleteService(service)) {
PRINTERROR("DeleteService");
CloseServiceHandle(service);
CloseServiceHandle(scm);
}
fprintf(stdout, "ADCH++ service \"%s\" successfully removed\n", serviceName);
CloseServiceHandle(service);
CloseServiceHandle(scm);
}
static void init() {
//if(asService)
//LOG(modName, versionString + " started as a service");
//else
//LOG(modName, versionString + " started from console");
loadXML(*core, File::makeAbsolutePath(core->getConfigPath(), "adchpp.xml"));
}
static void uninit() {
//LOG(modName, versionString + " shut down");
}
static SERVICE_STATUS_HANDLE ssh = 0;
static SERVICE_STATUS ss;
void WINAPI handler(DWORD code) {
switch(code) {
case SERVICE_CONTROL_SHUTDOWN: // Fallthrough
case SERVICE_CONTROL_STOP:
if(core) {
ss.dwCurrentState = SERVICE_STOP_PENDING;
core->shutdown();
} else {
ss.dwCurrentState = SERVICE_STOPPED;
}
break;
case SERVICE_CONTROL_INTERROGATE: break;
default: ; //LOG(modName, "Unknown service handler code " + Util::toString(code));
}
if(!SetServiceStatus(ssh, &ss)) {
//LOGERROR("handler::SetServiceStatus");
}
}
static void WINAPI serviceStart(DWORD, TCHAR* argv[]) {
ssh = ::RegisterServiceCtrlHandler(argv[0], handler);
if(ssh == 0) {
//LOGERROR("RegisterServiceCtrlHandler");
uninit();
return;
}
ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ss.dwCurrentState = SERVICE_START_PENDING;
ss.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
ss.dwWin32ExitCode = NO_ERROR;
ss.dwCheckPoint = 0;
ss.dwWaitHint = 10 * 1000;
if(!SetServiceStatus(ssh, &ss)) {
//LOGERROR("SetServiceStatus");
uninit();
return;
}
try {
core = Core::create(configPath);
init();
} catch(const adchpp::Exception& e) {
//LOG(modName, "Failed to start: " + e.getError());
}
ss.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(ssh, &ss);
try {
core->run();
} catch(const Exception& e) {
//LOG(modName, "ADCH++ startup failed because: " + e.getError());
}
ss.dwCurrentState = SERVICE_STOPPED;
if(!SetServiceStatus(ssh, &ss)) {
//LOGERROR("SetServiceStatus");
uninit();
return;
}
uninit();
}
static void runService() {
SERVICE_TABLE_ENTRY DispatchTable[] = {
{ (LPTSTR)serviceName, &serviceStart },
{ NULL, NULL }
};
if (!StartServiceCtrlDispatcher(DispatchTable)) {
//LOGERROR("StartServiceCtrlDispatcher");
}
}
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType) {
if(core && dwCtrlType == CTRL_C_EVENT) {
core->shutdown();
return TRUE;
}
return FALSE;
}
static void runConsole() {
SetConsoleCtrlHandler(&HandlerRoutine, TRUE);
printf("Starting."); fflush(stdout);
try {
core = Core::create(configPath);
printf("."); fflush(stdout);
init();
// LOG(modName, versionString + " starting from console");
printf(".\n%s running, press ctrl-c to exit...\n", versionString.c_str());
core->run();
core.reset();
} catch(const Exception& e) {
printf("\n\nFATAL: Can't start ADCH++: %s\n", e.getError().c_str());
}
uninit();
}
static void printUsage() {
const char* text =
"Usage: adchpp [[-c <configdir>] [-i <servicename> | -u <servicename>]] | [-v] | [-h]\n\n"
"-c Specify the path of the configuration directory (default: .\\config)\n"
"-i <service name> Install a service instance (name defaults to 'adchpp')\n"
"-u <service name> Uninstall a service instance\n"
"-v Print version number\n"
"-h Show this help message\n";
printf(text);
}
int CDECL main(int argc, char* argv[]) {
setlocale(LC_ALL, "");
configPath = Util::getAppPath() + "config\\";
int task = 0;
for(int i = 1; i < argc; ++i) {
if(_tcscmp(argv[i], _T("-d")) == 0) {
if(i+1 == argc) {
// Not much to do...
return 1;
}
i++;
serviceName = argv[i];
task = 1;
} else if(_tcscmp(argv[i],_T("-c")) == 0) {
if((i + 1) == argc) {
printf("-c <directory>\n");
return 1;
}
i++;
string cfg = argv[i];
if(cfg.empty()) {
printf("-c <directory>\n");
return 2;
}
if(!File::isAbsolutePath(cfg)) {
printf("Config dir must be an absolute path\n");
return 2;
}
if(cfg[cfg.length() - 1] != '\\') {
cfg += '\\';
}
configPath = cfg;
} else if(_tcscmp(argv[i], _T("-i")) == 0) {
i++;
serviceName = (i >= argc) ? serviceName : argv[i];
task = 2;
} else if(_tcscmp(argv[i], _T("-u")) == 0) {
i++;
serviceName = (i >= argc) ? serviceName : argv[i];
task = 3;
} else if(_tcscmp(argv[i], _T("-v")) == 0) {
printf("%s compiled on " __DATE__ " " __TIME__ "\n", versionString.c_str());
return 0;
} else if(_tcscmp(argv[i], _T("-h")) == 0) {
printUsage();
return 0;
} else {
printf("Invalid parameter: %s\n", argv[i]);
printUsage();
return 4;
}
}
switch(task) {
case 0: runConsole(); break;
case 1: runService(); break;
case 2: installService(); break;
case 3: removeService(); break;
}
return 0;
}

BIN
src/adchppd/res/adchppd.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

View File

@ -0,0 +1,34 @@
0 ICON "adchppd.ico"
1 VERSIONINFO
FILEVERSION 2,12,1,0
PRODUCTVERSION 2,12,1,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "http://adchpp.sourceforge.net"
VALUE "FileDescription", "ADCH++"
VALUE "FileVersion", "2, 12, 1, 0"
VALUE "InternalName", "ADCH++"
VALUE "LegalCopyright", "Copyright 2006-2014 Jacek Sieka"
VALUE "OriginalFilename", "adchppd.exe"
VALUE "ProductName", "ADCH++"
VALUE "ProductVersion", "2, 12, 1, 0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

23
src/boost/LICENSE_1_0.txt Normal file
View File

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,27 @@
///////////////////////////////////////////////////////////////////////////////
/// \file accumulators.hpp
/// Includes all of the Accumulators Framework
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_ACCUMULATORS_HPP_EAN_28_10_2005
#define BOOST_ACCUMULATORS_ACCUMULATORS_HPP_EAN_28_10_2005
#include <boost/accumulators/framework/accumulator_set.hpp>
#include <boost/accumulators/framework/accumulator_concept.hpp>
#include <boost/accumulators/framework/accumulator_base.hpp>
#include <boost/accumulators/framework/extractor.hpp>
#include <boost/accumulators/framework/external.hpp>
#include <boost/accumulators/framework/features.hpp>
#include <boost/accumulators/framework/parameters/accumulator.hpp>
#include <boost/accumulators/framework/parameters/sample.hpp>
#include <boost/accumulators/framework/parameters/weight.hpp>
#include <boost/accumulators/framework/parameters/weights.hpp>
#include <boost/accumulators/framework/accumulators/external_accumulator.hpp>
#include <boost/accumulators/framework/accumulators/droppable_accumulator.hpp>
#include <boost/accumulators/framework/accumulators/reference_accumulator.hpp>
#include <boost/accumulators/framework/accumulators/value_accumulator.hpp>
#endif

View File

@ -0,0 +1,219 @@
///////////////////////////////////////////////////////////////////////////////
// accumulators_fwd.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_ACCUMULATORS_FWD_HPP_EAN_28_10_2005
#define BOOST_ACCUMULATORS_ACCUMULATORS_FWD_HPP_EAN_28_10_2005
#include <boost/config.hpp>
#include <boost/mpl/apply_fwd.hpp> // for mpl::na
#include <boost/mpl/limits/vector.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/accumulators/numeric/functional_fwd.hpp>
#ifndef BOOST_ACCUMULATORS_MAX_FEATURES
/// The maximum number of accumulators that may be put in an accumulator_set.
/// Defaults to BOOST_MPL_LIMIT_VECTOR_SIZE (which defaults to 20).
# define BOOST_ACCUMULATORS_MAX_FEATURES BOOST_MPL_LIMIT_VECTOR_SIZE
#endif
#if BOOST_ACCUMULATORS_MAX_FEATURES > BOOST_MPL_LIMIT_VECTOR_SIZE
# error BOOST_ACCUMULATORS_MAX_FEATURES cannot be larger than BOOST_MPL_LIMIT_VECTOR_SIZE
#endif
#ifndef BOOST_ACCUMULATORS_MAX_ARGS
/// The maximum number of arguments that may be specified to an accumulator_set's
/// accumulation function. Defaults to 15.
# define BOOST_ACCUMULATORS_MAX_ARGS 15
#endif
#if BOOST_WORKAROUND(__GNUC__, == 3) \
|| BOOST_WORKAROUND(__EDG_VERSION__, BOOST_TESTED_AT(306))
# define BOOST_ACCUMULATORS_BROKEN_CONST_OVERLOADS
#endif
#ifdef BOOST_ACCUMULATORS_BROKEN_CONST_OVERLOADS
# include <boost/utility/enable_if.hpp>
# include <boost/type_traits/is_const.hpp>
# define BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(T)\
, typename boost::disable_if<boost::is_const<T> >::type * = 0
#else
# define BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(T)
#endif
#define BOOST_ACCUMULATORS_GCC_VERSION \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
namespace boost { namespace accumulators
{
///////////////////////////////////////////////////////////////////////////////
// Named parameters tags
//
namespace tag
{
struct sample;
struct weight;
struct accumulator;
struct weights;
}
///////////////////////////////////////////////////////////////////////////////
// User-level features
//
namespace tag
{
template<typename ValueType, typename Tag>
struct value;
template<typename Tag>
struct value_tag;
template<typename Referent, typename Tag>
struct reference;
template<typename Tag>
struct reference_tag;
template<typename Type, typename Tag = void, typename AccumulatorSet = void>
struct external;
template<typename Feature>
struct droppable;
}
template<typename Accumulator>
struct droppable_accumulator_base;
template<typename Accumulator>
struct droppable_accumulator;
template<typename Accumulator>
struct with_cached_result;
template<typename Sample, typename Features, typename Weight = void>
struct accumulator_set;
template<typename Feature>
struct extractor;
template<typename Feature>
struct feature_of;
template<typename Feature>
struct as_feature;
template<typename Feature>
struct as_weighted_feature;
template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_ACCUMULATORS_MAX_FEATURES, typename Feature, mpl::na)>
struct depends_on;
template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_ACCUMULATORS_MAX_FEATURES, typename Feature, mpl::na)>
struct features;
template<typename Feature, typename AccumulatorSet>
typename mpl::apply<AccumulatorSet, Feature>::type const &
find_accumulator(AccumulatorSet const &acc);
template<typename Feature, typename AccumulatorSet>
typename mpl::apply<AccumulatorSet, Feature>::type::result_type
extract_result(AccumulatorSet const &acc);
template<typename Feature, typename AccumulatorSet, typename A1>
typename mpl::apply<AccumulatorSet, Feature>::type::result_type
extract_result(AccumulatorSet const &acc, A1 const &a1);
// ... other overloads generated by Boost.Preprocessor:
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_EXTRACT_RESULT_FWD(z, n, _) \
template< \
typename Feature \
, typename AccumulatorSet \
BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
> \
typename mpl::apply<AccumulatorSet, Feature>::type::result_type \
extract_result( \
AccumulatorSet const &acc \
BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \
);
/// INTERNAL ONLY
///
BOOST_PP_REPEAT_FROM_TO(
2
, BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
, BOOST_ACCUMULATORS_EXTRACT_RESULT_FWD
, _
)
#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
template<typename Feature, typename AccumulatorSet, typename A1, typename A2 ...>
typename mpl::apply<AccumulatorSet, Feature>::type::result_type
extract_result(AccumulatorSet const &acc, A1 const &a1, A2 const &a2 ...);
#endif
namespace impl
{
using namespace numeric::operators;
template<typename Accumulator, typename Tag>
struct external_impl;
}
namespace detail
{
template<typename Accumulator>
struct feature_tag;
template<typename Feature, typename Sample, typename Weight>
struct to_accumulator;
struct accumulator_set_base;
template<typename T>
struct is_accumulator_set;
inline void ignore_variable(void const *) {}
#define BOOST_ACCUMULATORS_IGNORE_GLOBAL(X)\
namespace detail { inline void BOOST_PP_CAT(ignore_, X)() { boost::accumulators::detail::ignore_variable(&X); } }
}
}} // namespace boost::accumulators
// For defining boost::parameter keywords that can be inherited from to
// get a nested, class-scoped keyword with the requested alias
#define BOOST_PARAMETER_NESTED_KEYWORD(tag_namespace, name, alias) \
namespace tag_namespace \
{ \
template<int Dummy = 0> \
struct name ## _ \
{ \
static char const* keyword_name() \
{ \
return #name; \
} \
static ::boost::parameter::keyword<name ## _<Dummy> > &alias; \
}; \
template<int Dummy> \
::boost::parameter::keyword<name ## _<Dummy> > &name ## _<Dummy>::alias = \
::boost::parameter::keyword<name ## _<Dummy> >::get(); \
typedef name ## _ <> name; \
} \
namespace \
{ \
::boost::parameter::keyword<tag_namespace::name> &name = \
::boost::parameter::keyword<tag_namespace::name>::get(); \
}
#endif

View File

@ -0,0 +1,65 @@
///////////////////////////////////////////////////////////////////////////////
// accumulator_base.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_BASE_HPP_EAN_28_10_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_BASE_HPP_EAN_28_10_2005
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/joint_view.hpp>
#include <boost/mpl/single_view.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/mpl/empty_sequence.hpp>
#include <boost/accumulators/framework/accumulator_concept.hpp>
namespace boost { namespace accumulators
{
namespace detail
{
typedef void void_;
}
///////////////////////////////////////////////////////////////////////////////
// dont_care
//
struct dont_care
{
template<typename Args>
dont_care(Args const &)
{
}
};
///////////////////////////////////////////////////////////////////////////////
// accumulator_base
//
struct accumulator_base
{
// hidden if defined in derived classes
detail::void_ operator ()(dont_care)
{
}
typedef mpl::false_ is_droppable;
detail::void_ add_ref(dont_care)
{
}
detail::void_ drop(dont_care)
{
}
detail::void_ on_drop(dont_care)
{
}
};
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,29 @@
///////////////////////////////////////////////////////////////////////////////
// accumulator_concept.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_CONCEPT_HPP_EAN_28_10_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_CONCEPT_HPP_EAN_28_10_2005
#include <boost/concept_check.hpp>
namespace boost { namespace accumulators
{
template<typename Stat>
struct accumulator_concept
{
void constraints()
{
// TODO: define the stat concept
}
Stat stat;
};
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,401 @@
///////////////////////////////////////////////////////////////////////////////
// accumulator_set.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005
#include <boost/version.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/protect.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/is_sequence.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/parameter/parameters.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/accumulators/accumulators_fwd.hpp>
#include <boost/accumulators/framework/depends_on.hpp>
#include <boost/accumulators/framework/accumulator_concept.hpp>
#include <boost/accumulators/framework/parameters/accumulator.hpp>
#include <boost/accumulators/framework/parameters/sample.hpp>
#include <boost/accumulators/framework/accumulators/external_accumulator.hpp>
#include <boost/accumulators/framework/accumulators/droppable_accumulator.hpp>
#include <boost/fusion/include/any.hpp>
#include <boost/fusion/include/find_if.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/filter_view.hpp>
namespace boost { namespace accumulators
{
namespace detail
{
///////////////////////////////////////////////////////////////////////////////
// accumulator_visitor
// wrap a boost::parameter argument pack in a Fusion extractor object
template<typename Args>
struct accumulator_visitor
{
explicit accumulator_visitor(Args const &a)
: args(a)
{
}
template<typename Accumulator>
void operator ()(Accumulator &accumulator) const
{
accumulator(this->args);
}
private:
accumulator_visitor &operator =(accumulator_visitor const &);
Args const &args;
};
template<typename Args>
inline accumulator_visitor<Args> const make_accumulator_visitor(Args const &args)
{
return accumulator_visitor<Args>(args);
}
typedef
parameter::parameters<
parameter::required<tag::accumulator>
, parameter::optional<tag::sample>
// ... and others which are not specified here...
>
accumulator_params;
///////////////////////////////////////////////////////////////////////////////
// accumulator_set_base
struct accumulator_set_base
{
};
///////////////////////////////////////////////////////////////////////////////
// is_accumulator_set
template<typename T>
struct is_accumulator_set
: is_base_and_derived<accumulator_set_base, T>
{
};
} // namespace detail
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4355) // warning C4355: 'this' : used in base member initializer list
#endif
///////////////////////////////////////////////////////////////////////////////
/// \brief A set of accumulators.
///
/// accumulator_set resolves the dependencies between features and ensures that
/// the accumulators in the set are updated in the proper order.
///
/// acccumulator_set provides a general mechanism to visit the accumulators
/// in the set in order, with or without a filter. You can also fetch a reference
/// to an accumulator that corresponds to a feature.
///
template<typename Sample, typename Features, typename Weight>
struct accumulator_set
: detail::accumulator_set_base
{
typedef Sample sample_type; ///< The type of the samples that will be accumulated
typedef Features features_type; ///< An MPL sequence of the features that should be accumulated.
typedef Weight weight_type; ///< The type of the weight parameter. Must be a scalar. Defaults to void.
/// INTERNAL ONLY
///
typedef
typename detail::make_accumulator_tuple<
Features
, Sample
, Weight
>::type
accumulators_mpl_vector;
// generate a fusion::list of accumulators
/// INTERNAL ONLY
///
typedef
typename detail::meta::make_acc_list<
accumulators_mpl_vector
>::type
accumulators_type;
/// INTERNAL ONLY
///
//BOOST_MPL_ASSERT((mpl::is_sequence<accumulators_type>));
///////////////////////////////////////////////////////////////////////////////
/// default-construct all contained accumulators
accumulator_set()
: accumulators(
detail::make_acc_list(
accumulators_mpl_vector()
, detail::accumulator_params()(*this)
)
)
{
// Add-ref the Features that the user has specified
this->template visit_if<detail::contains_feature_of_<Features> >(
detail::make_add_ref_visitor(detail::accumulator_params()(*this))
);
}
/// \overload
///
/// \param a1 Optional named parameter to be passed to all the accumulators
template<typename A1>
explicit accumulator_set(A1 const &a1)
: accumulators(
detail::make_acc_list(
accumulators_mpl_vector()
, detail::accumulator_params()(*this, a1)
)
)
{
// Add-ref the Features that the user has specified
this->template visit_if<detail::contains_feature_of_<Features> >(
detail::make_add_ref_visitor(detail::accumulator_params()(*this))
);
}
// ... other overloads generated by Boost.Preprocessor:
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR(z, n, _) \
template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
accumulator_set(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a)) \
: accumulators( \
detail::make_acc_list( \
accumulators_mpl_vector() \
, detail::accumulator_params()( \
*this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
) \
) \
) \
{ \
/* Add-ref the Features that the user has specified */ \
this->template visit_if<detail::contains_feature_of_<Features> >( \
detail::make_add_ref_visitor(detail::accumulator_params()(*this)) \
); \
}
/// INTERNAL ONLY
///
BOOST_PP_REPEAT_FROM_TO(
2
, BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
, BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR
, _
)
#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
/// \overload
///
template<typename A1, typename A2, ...>
accumulator_set(A1 const &a1, A2 const &a2, ...);
#endif
// ... other overloads generated by Boost.Preprocessor below ...
///////////////////////////////////////////////////////////////////////////////
/// Visitation
/// \param func UnaryFunction which is invoked with each accumulator in turn.
template<typename UnaryFunction>
void visit(UnaryFunction const &func)
{
fusion::for_each(this->accumulators, func);
}
///////////////////////////////////////////////////////////////////////////////
/// Conditional visitation
/// \param func UnaryFunction which is invoked with each accumulator in turn,
/// provided the accumulator satisfies the MPL predicate FilterPred.
template<typename FilterPred, typename UnaryFunction>
void visit_if(UnaryFunction const &func)
{
fusion::filter_view<accumulators_type, FilterPred> filtered_accs(this->accumulators);
fusion::for_each(filtered_accs, func);
}
///////////////////////////////////////////////////////////////////////////////
/// The return type of the operator() overloads is void.
typedef void result_type;
///////////////////////////////////////////////////////////////////////////////
/// Accumulation
/// \param a1 Optional named parameter to be passed to all the accumulators
void operator ()()
{
this->visit(
detail::make_accumulator_visitor(
detail::accumulator_params()(*this)
)
);
}
template<typename A1>
void operator ()(A1 const &a1)
{
this->visit(
detail::make_accumulator_visitor(
detail::accumulator_params()(*this, a1)
)
);
}
// ... other overloads generated by Boost.Preprocessor:
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP(z, n, _) \
template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
void operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a)) \
{ \
this->visit( \
detail::make_accumulator_visitor( \
detail::accumulator_params()( \
*this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
) \
) \
); \
}
/// INTERNAL ONLY
///
BOOST_PP_REPEAT_FROM_TO(
2
, BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
, BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP
, _
)
#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
/// \overload
///
template<typename A1, typename A2, ...>
void operator ()(A1 const &a1, A2 const &a2, ...);
#endif
///////////////////////////////////////////////////////////////////////////////
/// Extraction
template<typename Feature>
struct apply
: fusion::result_of::value_of<
typename fusion::result_of::find_if<
accumulators_type
, detail::matches_feature<Feature>
>::type
>
{
};
///////////////////////////////////////////////////////////////////////////////
/// Extraction
template<typename Feature>
typename apply<Feature>::type &extract()
{
return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
}
/// \overload
template<typename Feature>
typename apply<Feature>::type const &extract() const
{
return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
}
///////////////////////////////////////////////////////////////////////////////
/// Drop
template<typename Feature>
void drop()
{
// You can only drop the features that you have specified explicitly
typedef typename apply<Feature>::type the_accumulator;
BOOST_MPL_ASSERT((detail::contains_feature_of<Features, the_accumulator>));
typedef
typename feature_of<typename as_feature<Feature>::type>::type
the_feature;
(*fusion::find_if<detail::matches_feature<Feature> >(this->accumulators))
.drop(detail::accumulator_params()(*this));
// Also drop accumulators that this feature depends on
typedef typename the_feature::dependencies dependencies;
this->template visit_if<detail::contains_feature_of_<dependencies> >(
detail::make_drop_visitor(detail::accumulator_params()(*this))
);
}
private:
accumulators_type accumulators;
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
///////////////////////////////////////////////////////////////////////////////
// find_accumulator
// find an accumulator in an accumulator_set corresponding to a feature
template<typename Feature, typename AccumulatorSet>
typename mpl::apply<AccumulatorSet, Feature>::type &
find_accumulator(AccumulatorSet &acc BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(AccumulatorSet))
{
return acc.template extract<Feature>();
}
/// \overload
template<typename Feature, typename AccumulatorSet>
typename mpl::apply<AccumulatorSet, Feature>::type const &
find_accumulator(AccumulatorSet const &acc)
{
return acc.template extract<Feature>();
}
///////////////////////////////////////////////////////////////////////////////
// extract_result
// extract a result from an accumulator set
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN(z, n, _) \
template< \
typename Feature \
, typename AccumulatorSet \
BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
> \
typename mpl::apply<AccumulatorSet, Feature>::type::result_type \
extract_result( \
AccumulatorSet const &acc \
BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \
) \
{ \
return find_accumulator<Feature>(acc).result( \
detail::accumulator_params()( \
acc \
BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
) \
); \
}
BOOST_PP_REPEAT(
BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
, BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN
, _
)
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,328 @@
///////////////////////////////////////////////////////////////////////////////
// droppable_accumulator.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_DROPPABLE_ACCUMULATOR_HPP_EAN_13_12_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_DROPPABLE_ACCUMULATOR_HPP_EAN_13_12_2005
#include <new>
#include <boost/assert.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/aligned_storage.hpp>
#include <boost/accumulators/framework/depends_on.hpp> // for feature_of
#include <boost/accumulators/framework/parameters/accumulator.hpp> // for accumulator
namespace boost { namespace accumulators
{
template<typename Accumulator>
struct droppable_accumulator;
namespace detail
{
///////////////////////////////////////////////////////////////////////////////
// add_ref_visitor
// a fusion function object for add_ref'ing accumulators
template<typename Args>
struct add_ref_visitor
{
explicit add_ref_visitor(Args const &args)
: args_(args)
{
}
template<typename Accumulator>
void operator ()(Accumulator &acc) const
{
typedef typename Accumulator::feature_tag::dependencies dependencies;
acc.add_ref(this->args_);
// Also add_ref accumulators that this feature depends on
this->args_[accumulator].template
visit_if<detail::contains_feature_of_<dependencies> >(
*this
);
}
private:
add_ref_visitor &operator =(add_ref_visitor const &);
Args const &args_;
};
template<typename Args>
add_ref_visitor<Args> make_add_ref_visitor(Args const &args)
{
return add_ref_visitor<Args>(args);
}
///////////////////////////////////////////////////////////////////////////////
// drop_visitor
// a fusion function object for dropping accumulators
template<typename Args>
struct drop_visitor
{
explicit drop_visitor(Args const &args)
: args_(args)
{
}
template<typename Accumulator>
void operator ()(Accumulator &acc) const
{
if(typename Accumulator::is_droppable())
{
typedef typename Accumulator::feature_tag::dependencies dependencies;
acc.drop(this->args_);
// Also drop accumulators that this feature depends on
this->args_[accumulator].template
visit_if<detail::contains_feature_of_<dependencies> >(
*this
);
}
}
private:
drop_visitor &operator =(drop_visitor const &);
Args const &args_;
};
template<typename Args>
drop_visitor<Args> make_drop_visitor(Args const &args)
{
return drop_visitor<Args>(args);
}
}
//////////////////////////////////////////////////////////////////////////
// droppable_accumulator_base
template<typename Accumulator>
struct droppable_accumulator_base
: Accumulator
{
typedef droppable_accumulator_base base;
typedef mpl::true_ is_droppable;
typedef typename Accumulator::result_type result_type;
template<typename Args>
droppable_accumulator_base(Args const &args)
: Accumulator(args)
, ref_count_(0)
{
}
droppable_accumulator_base(droppable_accumulator_base const &that)
: Accumulator(*static_cast<Accumulator const *>(&that))
, ref_count_(that.ref_count_)
{
}
template<typename Args>
void operator ()(Args const &args)
{
if(!this->is_dropped())
{
this->Accumulator::operator ()(args);
}
}
template<typename Args>
void add_ref(Args const &)
{
++this->ref_count_;
}
template<typename Args>
void drop(Args const &args)
{
BOOST_ASSERT(0 < this->ref_count_);
if(1 == this->ref_count_)
{
static_cast<droppable_accumulator<Accumulator> *>(this)->on_drop(args);
}
--this->ref_count_;
}
bool is_dropped() const
{
return 0 == this->ref_count_;
}
private:
int ref_count_;
};
//////////////////////////////////////////////////////////////////////////
// droppable_accumulator
// this can be specialized for any type that needs special handling
template<typename Accumulator>
struct droppable_accumulator
: droppable_accumulator_base<Accumulator>
{
template<typename Args>
droppable_accumulator(Args const &args)
: droppable_accumulator::base(args)
{
}
droppable_accumulator(droppable_accumulator const &that)
: droppable_accumulator::base(*static_cast<typename droppable_accumulator::base const *>(&that))
{
}
};
//////////////////////////////////////////////////////////////////////////
// with_cached_result
template<typename Accumulator>
struct with_cached_result
: Accumulator
{
typedef typename Accumulator::result_type result_type;
template<typename Args>
with_cached_result(Args const &args)
: Accumulator(args)
, cache()
{
}
with_cached_result(with_cached_result const &that)
: Accumulator(*static_cast<Accumulator const *>(&that))
, cache()
{
if(that.has_result())
{
this->set(that.get());
}
}
~with_cached_result()
{
// Since this is a base class of droppable_accumulator_base,
// this destructor is called before any of droppable_accumulator_base's
// members get cleaned up, including is_dropped, so the following
// call to has_result() is valid.
if(this->has_result())
{
this->get().~result_type();
}
}
template<typename Args>
void on_drop(Args const &args)
{
// cache the result at the point this calcuation was dropped
BOOST_ASSERT(!this->has_result());
this->set(this->Accumulator::result(args));
}
template<typename Args>
result_type result(Args const &args) const
{
return this->has_result() ? this->get() : this->Accumulator::result(args);
}
private:
with_cached_result &operator =(with_cached_result const &);
void set(result_type const &r)
{
::new(this->cache.address()) result_type(r);
}
result_type const &get() const
{
return *static_cast<result_type const *>(this->cache.address());
}
bool has_result() const
{
typedef with_cached_result<Accumulator> this_type;
typedef droppable_accumulator_base<this_type> derived_type;
return static_cast<derived_type const *>(this)->is_dropped();
}
aligned_storage<sizeof(result_type)> cache;
};
namespace tag
{
template<typename Feature>
struct as_droppable
{
typedef droppable<Feature> type;
};
template<typename Feature>
struct as_droppable<droppable<Feature> >
{
typedef droppable<Feature> type;
};
//////////////////////////////////////////////////////////////////////////
// droppable
template<typename Feature>
struct droppable
: as_feature<Feature>::type
{
typedef typename as_feature<Feature>::type feature_type;
typedef typename feature_type::dependencies tmp_dependencies_;
typedef
typename mpl::transform<
typename feature_type::dependencies
, as_droppable<mpl::_1>
>::type
dependencies;
struct impl
{
template<typename Sample, typename Weight>
struct apply
{
typedef
droppable_accumulator<
typename mpl::apply2<typename feature_type::impl, Sample, Weight>::type
>
type;
};
};
};
}
// make droppable<tag::feature(modifier)> work
template<typename Feature>
struct as_feature<tag::droppable<Feature> >
{
typedef tag::droppable<typename as_feature<Feature>::type> type;
};
// make droppable<tag::mean> work with non-void weights (should become
// droppable<tag::weighted_mean>
template<typename Feature>
struct as_weighted_feature<tag::droppable<Feature> >
{
typedef tag::droppable<typename as_weighted_feature<Feature>::type> type;
};
// for the purposes of feature-based dependency resolution,
// droppable<Foo> provides the same feature as Foo
template<typename Feature>
struct feature_of<tag::droppable<Feature> >
: feature_of<Feature>
{
};
// Note: Usually, the extractor is pulled into the accumulators namespace with
// a using directive, not the tag. But the droppable<> feature doesn't have an
// extractor, so we can put the droppable tag in the accumulators namespace
// without fear of a name conflict.
using tag::droppable;
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,108 @@
///////////////////////////////////////////////////////////////////////////////
// external_accumulator.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_EXTERNAL_ACCUMULATOR_HPP_EAN_01_12_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_EXTERNAL_ACCUMULATOR_HPP_EAN_01_12_2005
#include <boost/mpl/placeholders.hpp>
#include <boost/parameter/keyword.hpp>
#include <boost/accumulators/framework/extractor.hpp>
#include <boost/accumulators/framework/depends_on.hpp> // for feature_tag
#include <boost/accumulators/framework/accumulator_base.hpp>
#include <boost/accumulators/framework/accumulators/reference_accumulator.hpp>
namespace boost { namespace accumulators { namespace impl
{
//////////////////////////////////////////////////////////////////////////
// external_impl
/// INTERNAL ONLY
///
template<typename Accumulator, typename Tag>
struct external_impl
: accumulator_base
{
typedef typename Accumulator::result_type result_type;
typedef typename detail::feature_tag<Accumulator>::type feature_tag;
external_impl(dont_care) {}
template<typename Args>
result_type result(Args const &args) const
{
return this->extract_(args, args[parameter::keyword<Tag>::get() | 0]);
}
private:
template<typename Args>
static result_type extract_(Args const &args, int)
{
// No named parameter passed to the extractor. Maybe the external
// feature is held by reference<>.
extractor<feature_tag> extract;
return extract(accumulators::reference_tag<Tag>(args));
}
template<typename Args, typename AccumulatorSet>
static result_type extract_(Args const &, AccumulatorSet const &acc)
{
// OK, a named parameter for this external feature was passed to the
// extractor, so use that.
extractor<feature_tag> extract;
return extract(acc);
}
};
} // namespace impl
namespace tag
{
//////////////////////////////////////////////////////////////////////////
// external
template<typename Feature, typename Tag, typename AccumulatorSet>
struct external
: depends_on<reference<AccumulatorSet, Tag> >
{
typedef
accumulators::impl::external_impl<
detail::to_accumulator<Feature, mpl::_1, mpl::_2>
, Tag
>
impl;
};
template<typename Feature, typename Tag>
struct external<Feature, Tag, void>
: depends_on<>
{
typedef
accumulators::impl::external_impl<
detail::to_accumulator<Feature, mpl::_1, mpl::_2>
, Tag
>
impl;
};
}
// for the purposes of feature-based dependency resolution,
// external_accumulator<Feature, Tag> provides the same feature as Feature
template<typename Feature, typename Tag, typename AccumulatorSet>
struct feature_of<tag::external<Feature, Tag, AccumulatorSet> >
: feature_of<Feature>
{
};
// Note: Usually, the extractor is pulled into the accumulators namespace with
// a using directive, not the tag. But the external<> feature doesn't have an
// extractor, so we can put the external tag in the accumulators namespace
// without fear of a name conflict.
using tag::external;
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,89 @@
///////////////////////////////////////////////////////////////////////////////
// reference_accumulator.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_REFERENCE_ACCUMULATOR_HPP_EAN_03_23_2006
#define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_REFERENCE_ACCUMULATOR_HPP_EAN_03_23_2006
#include <boost/ref.hpp>
#include <boost/mpl/always.hpp>
#include <boost/parameter/keyword.hpp>
#include <boost/accumulators/framework/depends_on.hpp> // for feature_tag
#include <boost/accumulators/framework/accumulator_base.hpp>
#include <boost/accumulators/framework/extractor.hpp>
namespace boost { namespace accumulators
{
namespace impl
{
//////////////////////////////////////////////////////////////////////////
// reference_accumulator_impl
//
template<typename Referent, typename Tag>
struct reference_accumulator_impl
: accumulator_base
{
typedef Referent &result_type;
template<typename Args>
reference_accumulator_impl(Args const &args)
: ref(args[parameter::keyword<Tag>::get()])
{
}
result_type result(dont_care) const
{
return this->ref;
}
private:
reference_wrapper<Referent> ref;
};
} // namespace impl
namespace tag
{
//////////////////////////////////////////////////////////////////////////
// reference_tag
template<typename Tag>
struct reference_tag
{
};
//////////////////////////////////////////////////////////////////////////
// reference
template<typename Referent, typename Tag>
struct reference
: depends_on<>
{
/// INTERNAL ONLY
///
typedef mpl::always<accumulators::impl::reference_accumulator_impl<Referent, Tag> > impl;
};
}
namespace extract
{
BOOST_ACCUMULATORS_DEFINE_EXTRACTOR(tag, reference, (typename)(typename))
BOOST_ACCUMULATORS_DEFINE_EXTRACTOR(tag, reference_tag, (typename))
}
using extract::reference;
using extract::reference_tag;
// Map all reference<V,T> features to reference_tag<T> so
// that references can be extracted using reference_tag<T>
// without specifying the referent type.
template<typename ValueType, typename Tag>
struct feature_of<tag::reference<ValueType, Tag> >
: feature_of<tag::reference_tag<Tag> >
{
};
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,89 @@
///////////////////////////////////////////////////////////////////////////////
// value_accumulator.hpp
//
// Copyright 2005 Eric Niebler, Daniel Egloff. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_VALUE_ACCUMULATOR_HPP_EAN_03_23_2006
#define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_VALUE_ACCUMULATOR_HPP_EAN_03_23_2006
#include <boost/mpl/always.hpp>
#include <boost/parameter/keyword.hpp>
#include <boost/accumulators/framework/depends_on.hpp> // for feature_tag
#include <boost/accumulators/framework/accumulator_base.hpp>
#include <boost/accumulators/framework/extractor.hpp>
namespace boost { namespace accumulators
{
namespace impl
{
//////////////////////////////////////////////////////////////////////////
// value_accumulator_impl
template<typename ValueType, typename Tag>
struct value_accumulator_impl
: accumulator_base
{
typedef ValueType result_type;
template<typename Args>
value_accumulator_impl(Args const &args)
: val(args[parameter::keyword<Tag>::get()])
{
}
result_type result(dont_care) const
{
return this->val;
}
private:
ValueType val;
};
} // namespace impl
namespace tag
{
//////////////////////////////////////////////////////////////////////////
// value_tag
template<typename Tag>
struct value_tag
{
};
//////////////////////////////////////////////////////////////////////////
// value
template<typename ValueType, typename Tag>
struct value
: depends_on<>
{
/// INTERNAL ONLY
///
typedef mpl::always<accumulators::impl::value_accumulator_impl<ValueType, Tag> > impl;
};
}
namespace extract
{
BOOST_ACCUMULATORS_DEFINE_EXTRACTOR(tag, value, (typename)(typename))
BOOST_ACCUMULATORS_DEFINE_EXTRACTOR(tag, value_tag, (typename))
}
using extract::value;
using extract::value_tag;
// Map all value<V,T> features to value_tag<T> so
// that values can be extracted using value_tag<T>
// without specifying the value type.
template<typename ValueType, typename Tag>
struct feature_of<tag::value<ValueType, Tag> >
: feature_of<tag::value_tag<Tag> >
{
};
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,448 @@
///////////////////////////////////////////////////////////////////////////////
// depends_on.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_DEPENDS_ON_HPP_EAN_28_10_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_DEPENDS_ON_HPP_EAN_28_10_2005
#include <boost/version.hpp>
#include <boost/mpl/end.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/sort.hpp>
#include <boost/mpl/insert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/remove.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/is_sequence.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/insert_range.hpp>
#include <boost/mpl/back_inserter.hpp>
#include <boost/mpl/transform_view.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/accumulators/accumulators_fwd.hpp>
#include <boost/fusion/include/next.hpp>
#include <boost/fusion/include/equal_to.hpp>
#include <boost/fusion/include/value_of.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/include/end.hpp>
#include <boost/fusion/include/begin.hpp>
#include <boost/fusion/include/cons.hpp>
namespace boost { namespace accumulators
{
///////////////////////////////////////////////////////////////////////////
// as_feature
template<typename Feature>
struct as_feature
{
typedef Feature type;
};
///////////////////////////////////////////////////////////////////////////
// weighted_feature
template<typename Feature>
struct as_weighted_feature
{
typedef Feature type;
};
///////////////////////////////////////////////////////////////////////////
// feature_of
template<typename Feature>
struct feature_of
{
typedef Feature type;
};
namespace detail
{
///////////////////////////////////////////////////////////////////////////
// feature_tag
template<typename Accumulator>
struct feature_tag
{
typedef typename Accumulator::feature_tag type;
};
template<typename Feature>
struct undroppable
{
typedef Feature type;
};
template<typename Feature>
struct undroppable<tag::droppable<Feature> >
{
typedef Feature type;
};
// For the purpose of determining whether one feature depends on another,
// disregard whether the feature is droppable or not.
template<typename A, typename B>
struct is_dependent_on
: is_base_and_derived<
typename feature_of<typename undroppable<B>::type>::type
, typename undroppable<A>::type
>
{};
template<typename Feature>
struct dependencies_of
{
typedef typename Feature::dependencies type;
};
// Should use mpl::insert_range, but doesn't seem to work with mpl sets
template<typename Set, typename Range>
struct set_insert_range
: mpl::fold<
Range
, Set
, mpl::insert<mpl::_1, mpl::_2>
>
{};
template<typename Features>
struct collect_abstract_features
: mpl::fold<
Features
, mpl::set0<>
, set_insert_range<
mpl::insert<mpl::_1, feature_of<mpl::_2> >
, collect_abstract_features<dependencies_of<mpl::_2> >
>
>
{};
template<typename Features>
struct depends_on_base
: mpl::inherit_linearly<
typename mpl::sort<
typename mpl::copy<
typename collect_abstract_features<Features>::type
, mpl::back_inserter<mpl::vector0<> >
>::type
, is_dependent_on<mpl::_1, mpl::_2>
>::type
// Don't inherit multiply from a feature
, mpl::if_<
is_dependent_on<mpl::_1, mpl::_2>
, mpl::_1
, mpl::inherit<mpl::_1, mpl::_2>
>
>::type
{
};
}
///////////////////////////////////////////////////////////////////////////
/// depends_on
template<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, typename Feature)>
struct depends_on
: detail::depends_on_base<
typename mpl::transform<
mpl::vector<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, Feature)>
, as_feature<mpl::_1>
>::type
>
{
typedef mpl::false_ is_weight_accumulator;
typedef
typename mpl::transform<
mpl::vector<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, Feature)>
, as_feature<mpl::_1>
>::type
dependencies;
};
namespace detail
{
template<typename Feature>
struct matches_feature
{
template<typename Accumulator>
struct apply
: is_same<
typename feature_of<typename as_feature<Feature>::type>::type
, typename feature_of<typename as_feature<typename feature_tag<Accumulator>::type>::type>::type
>
{};
};
template<typename Features, typename Accumulator>
struct contains_feature_of
{
typedef
mpl::transform_view<Features, feature_of<as_feature<mpl::_> > >
features_list;
typedef
typename feature_of<typename feature_tag<Accumulator>::type>::type
the_feature;
typedef
typename mpl::contains<features_list, the_feature>::type
type;
};
// This is to work around a bug in early versions of Fusion which caused
// a compile error if contains_feature_of<List, mpl::_> is used as a
// predicate to fusion::find_if
template<typename Features>
struct contains_feature_of_
{
template<typename Accumulator>
struct apply
: contains_feature_of<Features, Accumulator>
{};
};
template<
typename First
, typename Last
, bool is_empty = fusion::result_of::equal_to<First, Last>::value
>
struct build_acc_list;
template<typename First, typename Last>
struct build_acc_list<First, Last, true>
{
typedef fusion::nil type;
template<typename Args>
static fusion::nil
call(Args const &, First const&, Last const&)
{
return fusion::nil();
}
};
template<typename First, typename Last>
struct build_acc_list<First, Last, false>
{
typedef
build_acc_list<typename fusion::result_of::next<First>::type, Last>
next_build_acc_list;
typedef fusion::cons<
typename fusion::result_of::value_of<First>::type
, typename next_build_acc_list::type>
type;
template<typename Args>
static type
call(Args const &args, First const& f, Last const& l)
{
return type(args, next_build_acc_list::call(args, fusion::next(f), l));
}
};
namespace meta
{
template<typename Sequence>
struct make_acc_list
: build_acc_list<
typename fusion::result_of::begin<Sequence>::type
, typename fusion::result_of::end<Sequence>::type
>
{};
}
template<typename Sequence, typename Args>
typename meta::make_acc_list<Sequence>::type
make_acc_list(Sequence const &seq, Args const &args)
{
return meta::make_acc_list<Sequence>::call(args, fusion::begin(seq), fusion::end(seq));
}
///////////////////////////////////////////////////////////////////////////
// checked_as_weighted_feature
template<typename Feature>
struct checked_as_weighted_feature
{
typedef typename as_feature<Feature>::type feature_type;
typedef typename as_weighted_feature<feature_type>::type type;
// weighted and non-weighted flavors should provide the same feature.
BOOST_MPL_ASSERT((
is_same<
typename feature_of<feature_type>::type
, typename feature_of<type>::type
>
));
};
///////////////////////////////////////////////////////////////////////////
// as_feature_list
template<typename Features, typename Weight>
struct as_feature_list
: mpl::transform_view<Features, checked_as_weighted_feature<mpl::_1> >
{
};
template<typename Features>
struct as_feature_list<Features, void>
: mpl::transform_view<Features, as_feature<mpl::_1> >
{
};
///////////////////////////////////////////////////////////////////////////
// accumulator_wrapper
template<typename Accumulator, typename Feature>
struct accumulator_wrapper
: Accumulator
{
typedef Feature feature_tag;
accumulator_wrapper(accumulator_wrapper const &that)
: Accumulator(*static_cast<Accumulator const *>(&that))
{
}
template<typename Args>
accumulator_wrapper(Args const &args)
: Accumulator(args)
{
}
};
///////////////////////////////////////////////////////////////////////////
// to_accumulator
template<typename Feature, typename Sample, typename Weight>
struct to_accumulator
{
typedef
accumulator_wrapper<
typename mpl::apply2<typename Feature::impl, Sample, Weight>::type
, Feature
>
type;
};
template<typename Feature, typename Sample, typename Weight, typename Tag, typename AccumulatorSet>
struct to_accumulator<Feature, Sample, tag::external<Weight, Tag, AccumulatorSet> >
{
BOOST_MPL_ASSERT((is_same<Tag, void>));
BOOST_MPL_ASSERT((is_same<AccumulatorSet, void>));
typedef
accumulator_wrapper<
typename mpl::apply2<typename Feature::impl, Sample, Weight>::type
, Feature
>
accumulator_type;
typedef
typename mpl::if_<
typename Feature::is_weight_accumulator
, accumulator_wrapper<impl::external_impl<accumulator_type, tag::weights>, Feature>
, accumulator_type
>::type
type;
};
// BUGBUG work around an MPL bug wrt map insertion
template<typename FeatureMap, typename Feature>
struct insert_feature
: mpl::eval_if<
mpl::has_key<FeatureMap, typename feature_of<Feature>::type>
, mpl::identity<FeatureMap>
, mpl::insert<FeatureMap, mpl::pair<typename feature_of<Feature>::type, Feature> >
>
{
};
template<typename FeatureMap, typename Feature, typename Weight>
struct insert_dependencies
: mpl::fold<
as_feature_list<typename Feature::dependencies, Weight>
, FeatureMap
, insert_dependencies<
insert_feature<mpl::_1, mpl::_2>
, mpl::_2
, Weight
>
>
{
};
template<typename FeatureMap, typename Features, typename Weight>
struct insert_sequence
: mpl::fold< // BUGBUG should use insert_range, but doesn't seem to work for maps
as_feature_list<Features, Weight>
, FeatureMap
, insert_feature<mpl::_1, mpl::_2>
>
{
};
template<typename Features, typename Sample, typename Weight>
struct make_accumulator_tuple
{
typedef
typename mpl::fold<
as_feature_list<Features, Weight>
, mpl::map0<>
, mpl::if_<
mpl::is_sequence<mpl::_2>
, insert_sequence<mpl::_1, mpl::_2, Weight>
, insert_feature<mpl::_1, mpl::_2>
>
>::type
feature_map;
// for each element in the map, add its dependencies also
typedef
typename mpl::fold<
feature_map
, feature_map
, insert_dependencies<mpl::_1, mpl::second<mpl::_2>, Weight>
>::type
feature_map_with_dependencies;
// turn the map into a vector so we can sort it
typedef
typename mpl::insert_range<
mpl::vector<>
, mpl::end<mpl::vector<> >::type
, mpl::transform_view<feature_map_with_dependencies, mpl::second<mpl::_1> >
>::type
feature_vector_with_dependencies;
// sort the features according to which is derived from which
typedef
typename mpl::sort<
feature_vector_with_dependencies
, is_dependent_on<mpl::_2, mpl::_1>
>::type
sorted_feature_vector;
// From the vector of features, construct a vector of accumulators
typedef
typename mpl::transform<
sorted_feature_vector
, to_accumulator<mpl::_1, Sample, Weight>
>::type
type;
};
} // namespace detail
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,27 @@
///////////////////////////////////////////////////////////////////////////////
// external.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_EXTERNAL_HPP_EAN_01_12_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_EXTERNAL_HPP_EAN_01_12_2005
#include <boost/mpl/apply.hpp>
#include <boost/accumulators/framework/accumulators/external_accumulator.hpp>
//namespace boost { namespace accumulators
//{
//
/////////////////////////////////////////////////////////////////////////////////
//// external
////
//template<typename Type>
//struct external
//{
//};
//
//}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,229 @@
///////////////////////////////////////////////////////////////////////////////
// extractor.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_EXTRACTOR_HPP_EAN_28_10_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_EXTRACTOR_HPP_EAN_28_10_2005
#include <boost/preprocessor/tuple/rem.hpp>
#include <boost/preprocessor/array/size.hpp>
#include <boost/preprocessor/array/data.hpp>
#include <boost/preprocessor/array/elem.hpp>
#include <boost/preprocessor/seq/to_array.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
#include <boost/parameter/binding.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/accumulators/accumulators_fwd.hpp>
#include <boost/accumulators/framework/parameters/accumulator.hpp>
namespace boost { namespace accumulators
{
namespace detail
{
template<typename AccumulatorSet, typename Feature>
struct accumulator_set_result
{
typedef typename as_feature<Feature>::type feature_type;
typedef typename mpl::apply<AccumulatorSet, feature_type>::type::result_type type;
};
template<typename Args, typename Feature>
struct argument_pack_result
: accumulator_set_result<
typename remove_reference<
typename parameter::binding<Args, tag::accumulator>::type
>::type
, Feature
>
{
};
template<typename A, typename Feature>
struct extractor_result
: mpl::eval_if<
detail::is_accumulator_set<A>
, accumulator_set_result<A, Feature>
, argument_pack_result<A, Feature>
>
{
};
template<typename Feature, typename AccumulatorSet>
typename extractor_result<AccumulatorSet, Feature>::type
do_extract(AccumulatorSet const &acc, mpl::true_)
{
typedef typename as_feature<Feature>::type feature_type;
return extract_result<feature_type>(acc);
}
template<typename Feature, typename Args>
typename extractor_result<Args, Feature>::type
do_extract(Args const &args, mpl::false_)
{
typedef typename as_feature<Feature>::type feature_type;
return find_accumulator<feature_type>(args[accumulator]).result(args);
}
} // namespace detail
///////////////////////////////////////////////////////////////////////////////
/// Extracts the result associated with Feature from the specified accumulator_set.
template<typename Feature>
struct extractor
{
typedef extractor<Feature> this_type;
/// The result meta-function for determining the return type of the extractor
template<typename F>
struct result;
template<typename A1>
struct result<this_type(A1)>
: detail::extractor_result<A1, Feature>
{
};
/// Extract the result associated with Feature from the accumulator set
/// \param acc The accumulator set object from which to extract the result
template<typename Arg1>
typename detail::extractor_result<Arg1, Feature>::type
operator ()(Arg1 const &arg1) const
{
// Arg1 could be an accumulator_set or an argument pack containing
// an accumulator_set. Dispatch accordingly.
return detail::do_extract<Feature>(arg1, detail::is_accumulator_set<Arg1>());
}
/// \overload
///
/// \param a1 Optional named parameter to be passed to the accumulator's result() function.
template<typename AccumulatorSet, typename A1>
typename detail::extractor_result<AccumulatorSet, Feature>::type
operator ()(AccumulatorSet const &acc, A1 const &a1) const
{
BOOST_MPL_ASSERT((detail::is_accumulator_set<AccumulatorSet>));
typedef typename as_feature<Feature>::type feature_type;
return extract_result<feature_type>(acc, a1);
}
// ... other overloads generated by Boost.Preprocessor:
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_EXTRACTOR_FUN_OP(z, n, _) \
template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
struct result<this_type(BOOST_PP_ENUM_PARAMS_Z(z, n, A))> \
: detail::extractor_result<A1, Feature> \
{}; \
template< \
typename AccumulatorSet \
BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
> \
typename detail::extractor_result<AccumulatorSet, Feature>::type \
operator ()( \
AccumulatorSet const &acc \
BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \
) const \
{ \
BOOST_MPL_ASSERT((detail::is_accumulator_set<AccumulatorSet>)); \
typedef typename as_feature<Feature>::type feature_type; \
return extract_result<feature_type>(acc BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a));\
}
BOOST_PP_REPEAT_FROM_TO(
2
, BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
, BOOST_ACCUMULATORS_EXTRACTOR_FUN_OP
, _
)
#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
/// \overload
///
template<typename AccumulatorSet, typename A1, typename A2, ...>
typename detail::extractor_result<AccumulatorSet, Feature>::type
operator ()(AccumulatorSet const &acc, A1 const &a1, A2 const &a2, ...);
#endif
};
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_ARRAY_REM(Array) \
BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_ARRAY_SIZE(Array), BOOST_PP_ARRAY_DATA(Array))
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_SEQ_REM(Seq) \
BOOST_ACCUMULATORS_ARRAY_REM(BOOST_PP_SEQ_TO_ARRAY(Seq))
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_ARGS_OP(s, data, elem) \
T ## s
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_PARAMS_OP(s, data, elem) \
elem T ## s
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_MAKE_FEATURE(Tag, Feature, ParamsSeq) \
Tag::Feature< \
BOOST_ACCUMULATORS_SEQ_REM( \
BOOST_PP_SEQ_TRANSFORM(BOOST_ACCUMULATORS_ARGS_OP, ~, ParamsSeq) \
) \
>
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_DEFINE_EXTRACTOR_FUN_IMPL(z, n, Tag, Feature, ParamsSeq) \
template< \
BOOST_ACCUMULATORS_SEQ_REM( \
BOOST_PP_SEQ_TRANSFORM(BOOST_ACCUMULATORS_PARAMS_OP, ~, ParamsSeq) \
) \
, typename Arg1 \
BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
> \
typename boost::accumulators::detail::extractor_result< \
Arg1 \
, BOOST_ACCUMULATORS_MAKE_FEATURE(Tag, Feature, ParamsSeq) \
>::type \
Feature(Arg1 const &arg1 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) ) \
{ \
typedef BOOST_ACCUMULATORS_MAKE_FEATURE(Tag, Feature, ParamsSeq) feature_type; \
return boost::accumulators::extractor<feature_type>()( \
arg1 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a)); \
}
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_DEFINE_EXTRACTOR_FUN(z, n, _) \
BOOST_ACCUMULATORS_DEFINE_EXTRACTOR_FUN_IMPL( \
z \
, n \
, BOOST_PP_ARRAY_ELEM(0, _) \
, BOOST_PP_ARRAY_ELEM(1, _) \
, BOOST_PP_ARRAY_ELEM(2, _) \
)
#define BOOST_ACCUMULATORS_DEFINE_EXTRACTOR(Tag, Feature, ParamSeq) \
BOOST_PP_REPEAT( \
BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS) \
, BOOST_ACCUMULATORS_DEFINE_EXTRACTOR_FUN \
, (3, (Tag, Feature, ParamSeq)) \
)
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,29 @@
///////////////////////////////////////////////////////////////////////////////
// features.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_STATISTICS_STATS_HPP_EAN_08_12_2005
#define BOOST_ACCUMULATORS_STATISTICS_STATS_HPP_EAN_08_12_2005
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/accumulators/accumulators_fwd.hpp>
namespace boost { namespace accumulators
{
///////////////////////////////////////////////////////////////////////////////
// features
//
template<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, typename Feature)>
struct features
: mpl::vector<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, Feature)>
{
};
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,20 @@
///////////////////////////////////////////////////////////////////////////////
// accumulator.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_PARAMETERS_ACCUMULATOR_HPP_EAN_31_10_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_PARAMETERS_ACCUMULATOR_HPP_EAN_31_10_2005
#include <boost/parameter/keyword.hpp>
namespace boost { namespace accumulators
{
BOOST_PARAMETER_KEYWORD(tag, accumulator)
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,20 @@
///////////////////////////////////////////////////////////////////////////////
// sample.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_PARAMETERS_SAMPLE_HPP_EAN_31_10_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_PARAMETERS_SAMPLE_HPP_EAN_31_10_2005
#include <boost/parameter/keyword.hpp>
namespace boost { namespace accumulators
{
BOOST_PARAMETER_KEYWORD(tag, sample)
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,21 @@
///////////////////////////////////////////////////////////////////////////////
// weight.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_PARAMETERS_WEIGHT_HPP_EAN_31_10_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_PARAMETERS_WEIGHT_HPP_EAN_31_10_2005
#include <boost/parameter/keyword.hpp>
namespace boost { namespace accumulators
{
// The weight of a single sample
BOOST_PARAMETER_KEYWORD(tag, weight)
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,21 @@
///////////////////////////////////////////////////////////////////////////////
// weights.hpp
//
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_PARAMETERS_WEIGHTS_HPP_EAN_28_10_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_PARAMETERS_WEIGHTS_HPP_EAN_28_10_2005
#include <boost/parameter/keyword.hpp>
namespace boost { namespace accumulators
{
// The weight accumulator
BOOST_PARAMETER_KEYWORD(tag, weights)
}} // namespace boost::accumulators
#endif

View File

@ -0,0 +1,75 @@
// Copyright David Abrahams 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_DETAIL_FUNCTION1_DWA200655_HPP
# define BOOST_DETAIL_FUNCTION1_DWA200655_HPP
# include <boost/concept_check.hpp>
# include <boost/type_traits/remove_reference.hpp>
# include <boost/type_traits/add_const.hpp>
# include <boost/mpl/apply.hpp>
namespace boost { namespace detail {
// A utility for creating unary function objects that play nicely with
// boost::result_of and that handle the forwarding problem.
//
// mpl::apply<F, A0>::type is expected to be a stateless function
// object that accepts an argument of type A0&. It is also expected
// to have a nested ::result_type identical to its return type.
template<typename F>
struct function1
{
template<typename Signature>
struct result
{};
template<typename This, typename A0>
struct result<This(A0)>
{
// How adding const to arguments handles rvalues.
//
// if A0 is arg0 is represents actual argument
// -------- ------- --------------------------
// T const & T const const T lvalue
// T & T non-const T lvalue
// T const T const const T rvalue
// T T const non-const T rvalue
typedef typename remove_reference<
typename add_const< A0 >::type
>::type arg0;
typedef typename mpl::apply1<F, arg0>::type impl;
typedef typename impl::result_type type;
};
// Handles mutable lvalues
template<typename A0>
typename result<function1(A0 &)>::type
operator ()(A0 &a0) const
{
typedef typename result<function1(A0 &)>::impl impl;
typedef typename result<function1(A0 &)>::type type;
typedef A0 &arg0;
BOOST_CONCEPT_ASSERT((UnaryFunction<impl, type, arg0>));
//boost::function_requires<UnaryFunctionConcept<impl, type, arg0> >();
return impl()(a0);
}
// Handles const lvalues and all rvalues
template<typename A0>
typename result<function1(A0 const &)>::type
operator ()(A0 const &a0) const
{
typedef typename result<function1(A0 const &)>::impl impl;
typedef typename result<function1(A0 const &)>::type type;
typedef A0 const &arg0;
BOOST_CONCEPT_ASSERT((UnaryFunction<impl, type, arg0>));
//boost::function_requires<UnaryFunctionConcept<impl, type, arg0> >();
return impl()(a0);
}
};
}} // namespace boost::detail
#endif // BOOST_DETAIL_FUNCTION1_DWA200655_HPP

View File

@ -0,0 +1,10 @@
// Copyright David Abrahams 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_DETAIL_FUNCTION2_DWA200655_HPP
# define BOOST_DETAIL_FUNCTION2_DWA200655_HPP
# define args (2)
# include <boost/accumulators/numeric/detail/function_n.hpp>
#endif // BOOST_DETAIL_FUNCTION2_DWA200655_HPP

View File

@ -0,0 +1,10 @@
// Copyright David Abrahams 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_DETAIL_FUNCTION3_DWA2006514_HPP
# define BOOST_DETAIL_FUNCTION3_DWA2006514_HPP
# define args (3)
# include <boost/accumulators/numeric/detail/function_n.hpp>
#endif // BOOST_DETAIL_FUNCTION3_DWA2006514_HPP

View File

@ -0,0 +1,10 @@
// Copyright David Abrahams 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_DETAIL_FUNCTION4_DWA2006514_HPP
# define BOOST_DETAIL_FUNCTION4_DWA2006514_HPP
# define args (4)
# include <boost/accumulators/numeric/detail/function_n.hpp>
#endif // BOOST_DETAIL_FUNCTION4_DWA2006514_HPP

View File

@ -0,0 +1,148 @@
// Copyright David Abrahams 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// #include guards intentionally disabled.
// #ifndef BOOST_DETAIL_FUNCTION_N_DWA2006514_HPP
// # define BOOST_DETAIL_FUNCTION_N_DWA2006514_HPP
#include <boost/mpl/void.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/seq/fold_left.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/for_each_product.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/type_traits/add_const.hpp>
#include <boost/type_traits/remove_reference.hpp>
namespace boost { namespace detail {
# define BOOST_DETAIL_default_arg(z, n, _) \
typedef mpl::void_ BOOST_PP_CAT(arg, n);
# define BOOST_DETAIL_function_arg(z, n, _) \
typedef typename remove_reference< \
typename add_const< BOOST_PP_CAT(A, n) >::type \
>::type BOOST_PP_CAT(arg, n);
#define BOOST_DETAIL_cat_arg_counts(s, state, n) \
BOOST_PP_IF( \
n \
, BOOST_PP_CAT(state, BOOST_PP_CAT(_, n)) \
, state \
) \
/**/
#define function_name \
BOOST_PP_SEQ_FOLD_LEFT( \
BOOST_DETAIL_cat_arg_counts \
, BOOST_PP_CAT(function, BOOST_PP_SEQ_HEAD(args)) \
, BOOST_PP_SEQ_TAIL(args)(0) \
) \
/**/
template<typename F>
struct function_name
{
BOOST_PP_REPEAT(
BOOST_MPL_LIMIT_METAFUNCTION_ARITY
, BOOST_DETAIL_default_arg
, ~
)
template<typename Signature>
struct result {};
#define BOOST_DETAIL_function_result(r, _, n) \
template<typename This BOOST_PP_ENUM_TRAILING_PARAMS(n, typename A)> \
struct result<This(BOOST_PP_ENUM_PARAMS(n, A))> \
{ \
BOOST_PP_REPEAT(n, BOOST_DETAIL_function_arg, ~) \
typedef \
typename BOOST_PP_CAT(mpl::apply, BOOST_MPL_LIMIT_METAFUNCTION_ARITY)<\
F \
BOOST_PP_ENUM_TRAILING_PARAMS( \
BOOST_MPL_LIMIT_METAFUNCTION_ARITY \
, arg \
) \
>::type \
impl; \
typedef typename impl::result_type type; \
}; \
/**/
BOOST_PP_SEQ_FOR_EACH(BOOST_DETAIL_function_result, _, args)
# define arg_type(r, _, i, is_const) \
BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(A, i) BOOST_PP_CAT(const_if, is_const) &
# define result_(r, n, constness) \
typename result< \
function_name( \
BOOST_PP_SEQ_FOR_EACH_I_R(r, arg_type, ~, constness) \
) \
> \
/**/
# define param(r, _, i, is_const) BOOST_PP_COMMA_IF(i) \
BOOST_PP_CAT(A, i) BOOST_PP_CAT(const_if, is_const) & BOOST_PP_CAT(x, i)
# define param_list(r, n, constness) \
BOOST_PP_SEQ_FOR_EACH_I_R(r, param, ~, constness)
# define call_operator(r, constness) \
template<BOOST_PP_ENUM_PARAMS(BOOST_PP_SEQ_SIZE(constness), typename A)> \
result_(r, BOOST_PP_SEQ_SIZE(constness), constness)::type \
operator ()( param_list(r, BOOST_PP_SEQ_SIZE(constness), constness) ) const \
{ \
typedef result_(r, BOOST_PP_SEQ_SIZE(constness), constness)::impl impl; \
return impl()(BOOST_PP_ENUM_PARAMS(BOOST_PP_SEQ_SIZE(constness), x)); \
} \
/**/
# define const_if0
# define const_if1 const
# define bits(z, n, _) ((0)(1))
# define gen_operator(r, _, n) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT_R( \
r \
, call_operator \
, BOOST_PP_REPEAT(n, bits, ~) \
) \
/**/
BOOST_PP_SEQ_FOR_EACH(
gen_operator
, ~
, args
)
# undef bits
# undef const_if1
# undef const_if0
# undef call_operator
# undef param_list
# undef param
# undef result_
# undef default_
# undef arg_type
# undef gen_operator
# undef function_name
# undef args
};
}} // namespace boost::detail
//#endif // BOOST_DETAIL_FUNCTION_N_DWA2006514_HPP

View File

@ -0,0 +1,20 @@
// Copyright David Abrahams 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_DETAIL_POD_SINGLETON_DWA200655_HPP
# define BOOST_DETAIL_POD_SINGLETON_DWA200655_HPP
namespace boost { namespace detail {
template<typename T>
struct pod_singleton
{
static T instance;
};
template<typename T>
T pod_singleton<T>::instance;
}} // namespace boost::detail
#endif // BOOST_DETAIL_POD_SINGLETON_DWA200655_HPP

View File

@ -0,0 +1,497 @@
///////////////////////////////////////////////////////////////////////////////
/// \file functional.hpp
///
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_NUMERIC_FUNCTIONAL_HPP_EAN_08_12_2005
#define BOOST_NUMERIC_FUNCTIONAL_HPP_EAN_08_12_2005
#include <limits>
#include <functional>
#include <boost/static_assert.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <boost/type_traits/is_empty.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/accumulators/numeric/functional_fwd.hpp>
#include <boost/accumulators/numeric/detail/function1.hpp>
#include <boost/accumulators/numeric/detail/function2.hpp>
#include <boost/accumulators/numeric/detail/pod_singleton.hpp>
#ifdef BOOST_NUMERIC_FUNCTIONAL_STD_VECTOR_SUPPORT
# include <boost/accumulators/numeric/functional/vector.hpp>
#endif
#ifdef BOOST_NUMERIC_FUNCTIONAL_STD_VALARRAY_SUPPORT
# include <boost/accumulators/numeric/functional/valarray.hpp>
#endif
#ifdef BOOST_NUMERIC_FUNCTIONAL_STD_COMPLEX_SUPPORT
# include <boost/accumulators/numeric/functional/complex.hpp>
#endif
/// INTERNAL ONLY
///
#define BOOST_NUMERIC_FUNCTIONAL_HPP_INCLUDED
#ifdef BOOST_NUMERIC_FUNCTIONAL_DOXYGEN_INVOKED
// Hack to make Doxygen show the inheritance relationships
/// INTERNAL ONLY
///
namespace std
{
/// INTERNAL ONLY
///
template<class Arg, class Ret> struct unary_function {};
/// INTERNAL ONLY
///
template<class Left, class Right, class Ret> struct binary_function {};
}
#endif
namespace boost { namespace numeric
{
namespace functional
{
/// INTERNAL ONLY
///
template<typename A0, typename A1>
struct are_integral
: mpl::and_<is_integral<A0>, is_integral<A1> >
{};
template<typename Left, typename Right>
struct left_ref
{
typedef Left &type;
};
namespace detail
{
template<typename T>
T &lvalue_of();
}
}
// TODO: handle complex weight, valarray, MTL vectors
/// INTERNAL ONLY
///
#define BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(Name, Op) \
namespace functional \
{ \
template<typename Arg> \
struct result_of_ ## Name \
{ \
BOOST_TYPEOF_NESTED_TYPEDEF_TPL( \
nested \
, Op boost::numeric::functional::detail::lvalue_of<Arg>() \
) \
typedef typename nested::type type; \
}; \
template<typename Arg, typename EnableIf> \
struct Name ## _base \
: std::unary_function< \
typename remove_const<Arg>::type \
, typename result_of_ ## Name<Arg>::type \
> \
{ \
typename result_of_ ## Name<Arg>::type operator ()(Arg &arg) const \
{ \
return Op arg; \
} \
}; \
template<typename Arg, typename ArgTag> \
struct Name \
: Name ## _base<Arg, void> \
{}; \
} \
namespace op \
{ \
struct Name \
: boost::detail::function1<functional::Name<_, functional::tag<_> > > \
{}; \
} \
namespace \
{ \
op::Name const &Name = boost::detail::pod_singleton<op::Name>::instance; \
} \
/**/
/// INTERNAL ONLY
///
#define BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(Name, Op, RetType) \
namespace functional \
{ \
template<typename Left, typename Right, typename EnableIf> \
struct result_of_ ## Name \
{ \
RetType(Left, Op, Right) \
}; \
template<typename Left, typename Right, typename EnableIf> \
struct Name ## _base \
: std::binary_function< \
typename remove_const<Left>::type \
, typename remove_const<Right>::type \
, typename result_of_ ## Name<Left, Right>::type \
> \
{ \
typename result_of_ ## Name<Left, Right>::type \
operator ()(Left &left, Right &right) const \
{ \
return left Op right; \
} \
}; \
template<typename Left, typename Right, typename LeftTag, typename RightTag> \
struct Name \
: Name ## _base<Left, Right, void> \
{}; \
} \
namespace op \
{ \
struct Name \
: boost::detail::function2< \
functional::Name<_1, _2, functional::tag<_1>, functional::tag<_2> > \
> \
{}; \
} \
namespace \
{ \
op::Name const &Name = boost::detail::pod_singleton<op::Name>::instance; \
} \
/**/
/// INTERNAL ONLY
///
#define BOOST_NUMERIC_FUNCTIONAL_DEDUCED(Left, Op, Right) \
BOOST_TYPEOF_NESTED_TYPEDEF_TPL( \
nested \
, boost::numeric::functional::detail::lvalue_of<Left>() Op \
boost::numeric::functional::detail::lvalue_of<Right>() \
) \
typedef typename nested::type type; \
/**/
/// INTERNAL ONLY
///
#define BOOST_NUMERIC_FUNCTIONAL_LEFT(Left, Op, Right) \
typedef Left &type; \
/**/
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(plus, +, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(minus, -, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(multiplies, *, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(divides, /, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(modulus, %, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(greater, >, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(greater_equal, >=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(less, <, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(less_equal, <=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(equal_to, ==, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(not_equal_to, !=, BOOST_NUMERIC_FUNCTIONAL_DEDUCED)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(assign, =, BOOST_NUMERIC_FUNCTIONAL_LEFT)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(plus_assign, +=, BOOST_NUMERIC_FUNCTIONAL_LEFT)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(minus_assign, -=, BOOST_NUMERIC_FUNCTIONAL_LEFT)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(multiplies_assign, *=, BOOST_NUMERIC_FUNCTIONAL_LEFT)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(divides_assign, /=, BOOST_NUMERIC_FUNCTIONAL_LEFT)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(modulus_assign, %=, BOOST_NUMERIC_FUNCTIONAL_LEFT)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(unary_plus, +)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(unary_minus, -)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(complement, ~)
BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(logical_not, !)
#undef BOOST_NUMERIC_FUNCTIONAL_LEFT
#undef BOOST_NUMERIC_FUNCTIONAL_DEDUCED
#undef BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP
#undef BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP
namespace functional
{
template<typename Left, typename Right, typename EnableIf>
struct min_assign_base
: std::binary_function<Left, Right, void>
{
void operator ()(Left &left, Right &right) const
{
if(numeric::less(right, left))
{
left = right;
}
}
};
template<typename Left, typename Right, typename EnableIf>
struct max_assign_base
: std::binary_function<Left, Right, void>
{
void operator ()(Left &left, Right &right) const
{
if(numeric::greater(right, left))
{
left = right;
}
}
};
template<typename Left, typename Right, typename EnableIf>
struct average_base
: functional::divides<Left, Right>
{};
// partial specialization that promotes the arguments to double for
// integral division.
template<typename Left, typename Right>
struct average_base<Left, Right, typename enable_if<are_integral<Left, Right> >::type>
: functional::divides<double const, double const>
{};
template<typename To, typename From, typename EnableIf>
struct promote_base
: std::unary_function<From, To>
{
To operator ()(From &from) const
{
return from;
}
};
template<typename ToFrom>
struct promote_base<ToFrom, ToFrom, void>
: std::unary_function<ToFrom, ToFrom>
{
ToFrom &operator ()(ToFrom &tofrom)
{
return tofrom;
}
};
template<typename Arg, typename EnableIf>
struct as_min_base
: std::unary_function<Arg, typename remove_const<Arg>::type>
{
BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized);
typename remove_const<Arg>::type operator ()(Arg &) const
{
return (std::numeric_limits<typename remove_const<Arg>::type>::min)();
}
};
template<typename Arg>
struct as_min_base<Arg, typename enable_if<is_floating_point<Arg> >::type>
: std::unary_function<Arg, typename remove_const<Arg>::type>
{
BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized);
typename remove_const<Arg>::type operator ()(Arg &) const
{
return -(std::numeric_limits<typename remove_const<Arg>::type>::max)();
}
};
template<typename Arg, typename EnableIf>
struct as_max_base
: std::unary_function<Arg, typename remove_const<Arg>::type>
{
BOOST_STATIC_ASSERT(std::numeric_limits<typename remove_const<Arg>::type>::is_specialized);
typename remove_const<Arg>::type operator ()(Arg &) const
{
return (std::numeric_limits<typename remove_const<Arg>::type>::max)();
}
};
template<typename Arg, typename EnableIf>
struct as_zero_base
: std::unary_function<Arg, typename remove_const<Arg>::type>
{
typename remove_const<Arg>::type operator ()(Arg &) const
{
return numeric::zero<typename remove_const<Arg>::type>::value;
}
};
template<typename Arg, typename EnableIf>
struct as_one_base
: std::unary_function<Arg, typename remove_const<Arg>::type>
{
typename remove_const<Arg>::type operator ()(Arg &) const
{
return numeric::one<typename remove_const<Arg>::type>::value;
}
};
template<typename To, typename From, typename ToTag, typename FromTag>
struct promote
: promote_base<To, From, void>
{};
template<typename Left, typename Right, typename LeftTag, typename RightTag>
struct min_assign
: min_assign_base<Left, Right, void>
{};
template<typename Left, typename Right, typename LeftTag, typename RightTag>
struct max_assign
: max_assign_base<Left, Right, void>
{};
template<typename Left, typename Right, typename LeftTag, typename RightTag>
struct average
: average_base<Left, Right, void>
{};
template<typename Arg, typename Tag>
struct as_min
: as_min_base<Arg, void>
{};
template<typename Arg, typename Tag>
struct as_max
: as_max_base<Arg, void>
{};
template<typename Arg, typename Tag>
struct as_zero
: as_zero_base<Arg, void>
{};
template<typename Arg, typename Tag>
struct as_one
: as_one_base<Arg, void>
{};
}
namespace op
{
template<typename To>
struct promote
: boost::detail::function1<functional::promote<To, _, typename functional::tag<To>::type, functional::tag<_> > >
{};
struct min_assign
: boost::detail::function2<functional::min_assign<_1, _2, functional::tag<_1>, functional::tag<_2> > >
{};
struct max_assign
: boost::detail::function2<functional::max_assign<_1, _2, functional::tag<_1>, functional::tag<_2> > >
{};
struct average
: boost::detail::function2<functional::average<_1, _2, functional::tag<_1>, functional::tag<_2> > >
{};
struct as_min
: boost::detail::function1<functional::as_min<_, functional::tag<_> > >
{};
struct as_max
: boost::detail::function1<functional::as_max<_, functional::tag<_> > >
{};
struct as_zero
: boost::detail::function1<functional::as_zero<_, functional::tag<_> > >
{};
struct as_one
: boost::detail::function1<functional::as_one<_, functional::tag<_> > >
{};
}
namespace
{
op::min_assign const &min_assign = boost::detail::pod_singleton<op::min_assign>::instance;
op::max_assign const &max_assign = boost::detail::pod_singleton<op::max_assign>::instance;
op::average const &average = boost::detail::pod_singleton<op::average>::instance;
op::as_min const &as_min = boost::detail::pod_singleton<op::as_min>::instance;
op::as_max const &as_max = boost::detail::pod_singleton<op::as_max>::instance;
op::as_zero const &as_zero = boost::detail::pod_singleton<op::as_zero>::instance;
op::as_one const &as_one = boost::detail::pod_singleton<op::as_one>::instance;
}
///////////////////////////////////////////////////////////////////////////////
// promote
template<typename To, typename From>
typename lazy_disable_if<is_const<From>, mpl::if_<is_same<To, From>, To &, To> >::type
promote(From &from)
{
return functional::promote<To, From>()(from);
}
template<typename To, typename From>
typename mpl::if_<is_same<To const, From const>, To const &, To const>::type
promote(From const &from)
{
return functional::promote<To const, From const>()(from);
}
template<typename T>
struct default_
{
typedef default_ type;
typedef T value_type;
static T const value;
operator T const & () const
{
return default_::value;
}
};
template<typename T>
T const default_<T>::value = T();
template<typename T>
struct one
{
typedef one type;
typedef T value_type;
static T const value;
operator T const & () const
{
return one::value;
}
};
template<typename T>
T const one<T>::value = T(1);
template<typename T>
struct zero
{
typedef zero type;
typedef T value_type;
static T const value;
operator T const & () const
{
return zero::value;
}
};
template<typename T>
T const zero<T>::value = T();
template<typename T>
struct one_or_default
: mpl::if_<is_empty<T>, default_<T>, one<T> >::type
{};
template<typename T>
struct zero_or_default
: mpl::if_<is_empty<T>, default_<T>, zero<T> >::type
{};
}} // namespace boost::numeric
#endif

View File

@ -0,0 +1,82 @@
///////////////////////////////////////////////////////////////////////////////
/// \file complex.hpp
///
// Copyright 2005 Eric Niebler. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_NUMERIC_FUNCTIONAL_COMPLEX_HPP_EAN_01_17_2006
#define BOOST_NUMERIC_FUNCTIONAL_COMPLEX_HPP_EAN_01_17_2006
#ifdef BOOST_NUMERIC_FUNCTIONAL_HPP_INCLUDED
# error Include this file before boost/accumulators/numeric/functional.hpp
#endif
#include <complex>
#include <boost/mpl/or.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/typeof/std/complex.hpp>
#include <boost/accumulators/numeric/functional_fwd.hpp>
namespace boost { namespace numeric { namespace operators
{
// So that the stats compile when Sample type is std::complex
template<typename T, typename U>
typename
disable_if<
mpl::or_<is_same<T, U>, is_same<std::complex<T>, U> >
, std::complex<T>
>::type
operator *(std::complex<T> ri, U const &u)
{
// BUGBUG promote result to typeof(T()*u) ?
return ri *= static_cast<T>(u);
}
template<typename T, typename U>
typename
disable_if<
mpl::or_<is_same<T, U>, is_same<std::complex<T>, U> >
, std::complex<T>
>::type
operator /(std::complex<T> ri, U const &u)
{
// BUGBUG promote result to typeof(T()*u) ?
return ri /= static_cast<T>(u);
}
}}} // namespace boost::numeric::operators
namespace boost { namespace numeric
{
namespace detail
{
template<typename T>
struct one_complex
{
static std::complex<T> const value;
};
template<typename T>
std::complex<T> const one_complex<T>::value
= std::complex<T>(numeric::one<T>::value, numeric::one<T>::value);
}
/// INTERNAL ONLY
///
template<typename T>
struct one<std::complex<T> >
: detail::one_complex<T>
{
typedef one type;
typedef std::complex<T> value_type;
operator value_type const & () const
{
return detail::one_complex<T>::value;
}
};
}} // namespace boost::numeric
#endif

Some files were not shown because too many files have changed in this diff Show More