This commit is contained in:
2025-11-24 14:19:51 +05:30
commit f5c1412b28
6734 changed files with 1527575 additions and 0 deletions

View File

@ -0,0 +1,31 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Include all libcat Codec headers
#include <cat/codec/RangeCoder.hpp>

View File

@ -0,0 +1,50 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Include all libcat Common headers
#include <cat/time/Clock.hpp>
#include <cat/rand/IRandom.hpp>
#include <cat/rand/MersenneTwister.hpp>
#include <cat/rand/StdRand.hpp>
#include <cat/hash/MurmurHash2.hpp>
#include <cat/threads/Atomic.hpp>
#include <cat/threads/Mutex.hpp>
#include <cat/threads/RWLock.hpp>
#include <cat/threads/Thread.hpp>
#include <cat/threads/WaitableFlag.hpp>
#include <cat/math/BitMath.hpp>
#include <cat/port/AlignedAlloc.hpp>
#include <cat/port/EndianNeutral.hpp>
#include <cat/lang/Strings.hpp>

View File

@ -0,0 +1,45 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Include all libcat Crypt headers
#include <cat/AllMath.hpp>
#include <cat/crypt/symmetric/ChaCha.hpp>
#include <cat/crypt/hash/ICryptHash.hpp>
#include <cat/crypt/hash/Skein.hpp>
#include <cat/crypt/hash/HMAC_MD5.hpp>
#include <cat/crypt/cookie/CookieJar.hpp>
#include <cat/crypt/SecureCompare.hpp>
#include <cat/crypt/rand/Fortuna.hpp>
#include <cat/crypt/pass/Passwords.hpp>

View File

@ -0,0 +1,81 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Include all libcat Framework headers
#ifndef CAT_ALL_FRAMEWORK_HPP
#define CAT_ALL_FRAMEWORK_HPP
#include <cat/AllCommon.hpp>
#include <cat/AllMath.hpp>
#include <cat/AllCrypt.hpp>
#include <cat/AllCodec.hpp>
#include <cat/AllTunnel.hpp>
#include <cat/AllGraphics.hpp>
#include <cat/threads/ThreadPool.hpp>
#include <cat/threads/LocklessFIFO.hpp>
#include <cat/threads/Mutex.hpp>
#include <cat/threads/RegionAllocator.hpp>
#include <cat/io/Logging.hpp>
#include <cat/io/MMapFile.hpp>
#include <cat/io/Settings.hpp>
#include <cat/io/Base64.hpp>
#include <cat/parse/BufferStream.hpp>
#include <cat/parse/BitStream.hpp>
#include <cat/parse/BufferTok.hpp>
#include <cat/parse/MessageRouter.hpp>
#include <cat/net/Sockets.hpp>
#include <cat/io/ThreadPoolFiles.hpp>
#include <cat/net/ThreadPoolSockets.hpp>
#include <cat/net/DNSClient.hpp>
#include <cat/net/SphynxTransport.hpp>
#include <cat/net/SphynxServer.hpp>
#include <cat/net/SphynxClient.hpp>
#include <cat/db/BombayTableIndex.hpp>
#include <cat/db/BombayTable.hpp>
namespace cat {
// Specifying a service name will set up service mode
bool InitializeFramework(const char *settings_file, const char *service_name = 0);
void ShutdownFramework(bool WriteSettings = true);
} // namespace cat
#endif // CAT_ALL_FRAMEWORK_HPP

View File

@ -0,0 +1,36 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Include all libcat Graphics headers
#include <cat/AllCommon.hpp>
#include <cat/gfx/Scalar.hpp>
#include <cat/gfx/Vector.hpp>
#include <cat/gfx/Matrix.hpp>
#include <cat/gfx/Quaternion.hpp>

View File

@ -0,0 +1,36 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Include all libcat Math headers
#include <cat/AllCommon.hpp>
#include <cat/math/BigRTL.hpp>
#include <cat/math/BigMontgomery.hpp>
#include <cat/math/BigPseudoMersenne.hpp>
#include <cat/math/BigTwistedEdwards.hpp>

View File

@ -0,0 +1,41 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Include all libcat Tunnel headers
#include <cat/AllCrypt.hpp>
#include <cat/crypt/tunnel/KeyMaker.hpp>
#include <cat/crypt/tunnel/KeyAgreement.hpp>
#include <cat/crypt/tunnel/KeyAgreementInitiator.hpp>
#include <cat/crypt/tunnel/KeyAgreementResponder.hpp>
#include <cat/crypt/tunnel/AuthenticatedEncryption.hpp>
#include <cat/crypt/tunnel/EasyHandshake.hpp>

View File

@ -0,0 +1,59 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_CONFIG_HPP
#define CAT_CONFIG_HPP
namespace cat {
// This definition overrides CAT_BUILD_DLL below. Neuters CAT_EXPORT macro so symbols are
// neither exported or imported.
//#define CAT_NEUTER_EXPORT
// This definition changes the meaning of the CAT_EXPORT macro on Windows. When defined,
// the CAT_EXPORT macro will export the associated symbol. When undefined, it will import it.
//#define CAT_BUILD_DLL
// If you want to remove server-side code from a binary distribution of a client program:
//#define CAT_OMIT_SERVER_CODE
// If you know the endianness of your target, uncomment one of these for better performance.
//#define __LITTLE_ENDIAN__
//#define __BIG_ENDIAN__
// If you want to use faster 384-bit or 512-bit math, define this:
//#define CAT_UNROLL_OVER_256_BITS
// Adjust if your architecture uses larger than 128-byte cache line
#define CAT_DEFAULT_CACHE_LINE_SIZE 128
} // namespace cat
#endif // CAT_CONFIG_HPP

View File

@ -0,0 +1,113 @@
___ _ _____ _ ___
/ __\__ _| |_ \_ \__| | / __\___ _ __ ___ _ __ ___ ___ _ __
/ / / _` | __| / /\/ _` | / / / _ \| '_ ` _ \| '_ ` _ \ / _ \| '_ \
/ /__| (_| | |_/\/ /_| (_| | / /__| (_) | | | | | | | | | | | (_) | | | |
\____/\__,_|\__\____/ \__,_| \____/\___/|_| |_| |_|_| |_| |_|\___/|_| |_|
___ _ __ _ _ _ ___
/ __\___ __| | ___ / /(_) |__ _ __ __ _ _ __ _ _ / | / _ \
/ / / _ \ / _` |/ _ \ / / | | '_ \| '__/ _` | '__| | | | | || | | |
/ /__| (_) | (_| | __/ / /__| | |_) | | | (_| | | | |_| | | || |_| |
\____/\___/ \__,_|\___| \____/_|_.__/|_| \__,_|_| \__, | |_(_)___/
|___/
CatId Common Code Library 1.0 07/23/2009
Released under a BSD-style license
------------------------------------------------------------------------
======================= Contact the Author =============================
------------------------------------------------------------------------
Christopher A. Taylor
Email: mrcatid@gmail.com
AIM: MrCatid
MSN: MrCatid@hotmail.com
WWW: http://catid.org
------------------------------------------------------------------------
=========================== What's New =================================
------------------------------------------------------------------------
Latest revisions are available in the SVN log at libcatid.googlecode.com
------------------------------------------------------------------------
============================== TODO ====================================
------------------------------------------------------------------------
Tunnel:
Update the documentation
.docx and .pdfs with lots of pictures
Portability:
Port the code to Mac
------------------------------------------------------------------------
============================= History ==================================
------------------------------------------------------------------------
07/23/2009 - Added switches for demo of 384-bit and 512-bit security
Fixed 384-bit version of BigRTL::Load and BigRTL::Store
Implemented template metaprogramming Comba Multiply
07/22/2009 - Visual Studio 2005 version works again
07/21/2009 - Split math code across many source files
Reorganized the project for easier reuse
07/20/2009 - New key agreement protocol "Tabby" is working
New functions added to BigTwistedEdward to support it
Added <cat/port/AlignedAlloc.hpp> to align all math regs
Optimized 32-bit version; now twice as fast as before
07/19/2009 - Pulled out all the old Tunnel code and rewrote it
07/17/2009 - Added <cat/crypt/rand/Fortuna.hpp>
07/15/2009 - Half way through writing Fortuna
Slightly faster scalar point multiplication precomputation
Worked on basic outline for new AKE protocol
07/14/2009 - Implemented and tested HMAC-MD5; this is now the Tunnel MAC
Several bug fixes
07/13/2009 - Fixed Tunnel vulnerability to active small subgroup attack
Fixed a bug in MrNegate()
07/12/2009 - Added inline assembly code for MultiplyXAdd()
Added fast timing-attack resistant modular inversion
Optimized MrSquareRoot() with a smaller window
07/11/2009 - All the math code is working again! Woohoo! =)
Added <cat/crypt/SecureCompare.hpp> to replace memcmp()
07/10/2009 - Wrote 64-bit assembly code version of Divide()
07/09/2009 - In the middle of getting math working again
07/07/2009 - Merged Skein256 and Skein512 into the same object
07/02/2009 - Refactored math code; put a lot of unused code in the attic
Added specialized 256-bit assembly code to math library
06/25/2009 - Improved replay attack protection to 1024 bits
06/24/2009 - Increased IV bits to 24 and moved IV code to TunnelSession
Tunnel now has replay attack protection
Fix: Tunnel only updates remote IV if it increased
Split BigInt source across many files
06/23/2009 - Tunnel uses Skein for a MAC
Tunnel no longer requires a cookie exchange
Removed support for SHA-2 in favor of Skein
Added math/EndianNeutral.hpp to Common
Added math/BitMath.hpp to Common
Added threads/Atomic.hpp to Common
06/20/2009 - Supports 512-bit ECC
CookieJar now Supports IPv6 and variable-length addresses
Put CAT_ before global macros
Split up library into even more projects
06/19/2009 - Now can select a bit-twiddling version of w-MOF
06/16/2009 - Implemented Skein-256 and Skein-512 and timing tests
06/15/2009 - Implemented SHA-512 (and SHA-384) and unit tests
ChaCha cipher now accepts up to 384-bit keys
Hash and PRNG objects are now implemented from an interface
Improved lockless FIFO code with opportunistic algorithm
Now supports 384-bit ECC
06/14/2009 - Added <cat/crypto/Tunnel.hpp> and /docs/tunnel.pdf
06/13/2009 - Added ChaCha::ReconstructIV
06/12/2009 - Fixed endian neutrality of the Sha256 hash, so also ECC
Added full handshake demo to the ECC unit test
06/11/2009 - Split the math code off from the framework code
06/10/2009 - Merged my code into this library for the first time

View File

@ -0,0 +1,583 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_PLATFORM_HPP
#define CAT_PLATFORM_HPP
#include <cat/Config.hpp>
#include <string.h>
namespace cat {
//// Compiler ////
// Mac OS X additional compilation flags
#ifdef __APPLE__
# include <TargetConditionals.h>
#endif
//-----------------------------------------------------------------------------
// Intel C++ Compiler : Interoperates with MSVC and GCC
#if defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)
# define CAT_COMPILER_ICC
# define CAT_FENCE_COMPILER __memory_barrier();
#endif
//-----------------------------------------------------------------------------
// Borland C++ Compiler : Compatible with MSVC syntax
#if defined(__BORLANDC__)
# define CAT_COMPILER_BORLAND
# define CAT_COMPILER_COMPAT_MSVC
# define CAT_INLINE __inline
# define CAT_ASM_EMIT __emit__
//-----------------------------------------------------------------------------
// Digital Mars C++ Compiler (previously known as Symantec C++)
#elif defined(__DMC__) || defined(__SC__) || defined(__SYMANTECC__)
# define CAT_COMPILER_DMARS
# define CAT_COMPILER_COMPAT_MSVC
# define CAT_INLINE __inline
# define CAT_ASM_EMIT __emit__
//-----------------------------------------------------------------------------
// Codeplay VectorC C++ Compiler : Compatible with GCC and MSVC syntax, prefer GCC
#elif defined(__VECTORC__)
# define CAT_COMPILER_CODEPLAY
# define CAT_COMPILER_COMPAT_GCC
//-----------------------------------------------------------------------------
// Pathscale C++ Compiler : Compatible with GCC syntax
#elif defined(__PATHSCALE__)
# define CAT_COMPILER_PATHSCALE
# define CAT_COMPILER_COMPAT_GCC
//-----------------------------------------------------------------------------
// Watcom C++ Compiler : Compatible with GCC and MSVC syntax, prefer GCC
#elif defined(__WATCOMC__)
# define CAT_COMPILER_WATCOM
# define CAT_COMPILER_COMPAT_GCC
//-----------------------------------------------------------------------------
// SUN C++ Compiler : Compatible with GCC syntax
#elif defined(__SUNPRO_CC)
# define CAT_COMPILER_SUN
# define CAT_COMPILER_COMPAT_GCC
//-----------------------------------------------------------------------------
// Metrowerks C++ Compiler : Compatible with MSVC syntax
#elif defined(__MWERKS__)
# define CAT_COMPILER_MWERKS
# define CAT_COMPILER_COMPAT_MSVC
# define CAT_INLINE inline
# define CAT_ASM_BEGIN _asm {
# define CAT_ASM_EMIT __emit__
//-----------------------------------------------------------------------------
// GNU C++ Compiler
// SN Systems ProDG C++ Compiler : Compatible with GCC
#elif defined(__GNUC__) || defined(__APPLE_CC__) || defined(__SNC__)
# define CAT_COMPILER_GCC
# define CAT_COMPILER_COMPAT_GCC
# define CAT_FASTCALL __attribute__ ((fastcall))
//-----------------------------------------------------------------------------
// Microsoft Visual Studio C++ Compiler
#elif defined(_MSC_VER)
# define CAT_COMPILER_MSVC
# define CAT_COMPILER_COMPAT_MSVC
# define CAT_FASTCALL __fastcall
} // namespace cat
# include <cstdlib> // Intrinsics
# include <intrin.h> // Intrinsics
namespace cat {
//-----------------------------------------------------------------------------
// Otherwise unknown compiler
#else
# define CAT_COMPILER_UNKNOWN
# define CAT_ALIGNED(n) /* no way to detect alignment syntax */
# define CAT_PACKED /* no way to detect packing syntax */
# define CAT_INLINE inline
// No way to support inline assembly code here
# define CAT_RESTRICT
#endif
/*
A lot of compilers have similar syntax to MSVC or GCC,
so for simplicity I have those two defined below, and
any deviations are implemented with overrides above.
*/
// MSVC-compatible compilers
#if defined(CAT_COMPILER_COMPAT_MSVC)
#if !defined(CAT_ALIGNED)
# define CAT_ALIGNED(n) __declspec(align(n))
#endif
#if !defined(CAT_PACKED)
# define CAT_PACKED
# define CAT_PRAGMA_PACK
#endif
#if !defined(CAT_INLINE)
# define CAT_INLINE __forceinline
#endif
#if !defined(CAT_ASM_INTEL)
# define CAT_ASM_INTEL
#endif
#if !defined(CAT_ASM_BEGIN)
# define CAT_ASM_BEGIN __asm {
#endif
#if !defined(CAT_ASM_EMIT)
# define CAT_ASM_EMIT _emit
#endif
#if !defined(CAT_ASM_END)
# define CAT_ASM_END }
#endif
#if !defined(CAT_TLS)
# define CAT_TLS __declspec( thread )
#endif
#if !defined(CAT_RESTRICT)
# define CAT_RESTRICT __restrict
#endif
#if !defined(CAT_FENCE_COMPILER)
# if defined(CAT_COMPILER_MSVC)
# pragma intrinsic(_ReadWriteBarrier)
# endif
# define CAT_FENCE_COMPILER _ReadWriteBarrier();
#endif
#if !defined(CAT_DLL_EXPORT)
# define CAT_DLL_EXPORT __declspec(dllexport)
#endif
#if !defined(CAT_DLL_IMPORT)
# define CAT_DLL_IMPORT __declspec(dllimport)
#endif
// GCC-compatible compilers
#elif defined(CAT_COMPILER_COMPAT_GCC)
#if !defined(CAT_ALIGNED)
# define CAT_ALIGNED(n) __attribute__ ((aligned (n)))
#endif
#if !defined(CAT_PACKED)
# define CAT_PACKED __attribute__ ((packed))
#endif
#if !defined(CAT_INLINE)
# define CAT_INLINE inline /* __inline__ __attribute__((always_inline)) */
#endif
#if !defined(CAT_ASM_ATT)
# define CAT_ASM_ATT
#endif
#if !defined(CAT_ASM_BEGIN)
# define CAT_ASM_BEGIN __asm__ __volatile__ (
#endif
#if !defined(CAT_ASM_EMIT)
# define CAT_ASM_EMIT .byte
#endif
#if !defined(CAT_ASM_END)
# define CAT_ASM_END );
#endif
#if !defined(CAT_TLS)
# define CAT_TLS __thread
#endif
#if !defined(CAT_RESTRICT)
# define CAT_RESTRICT __restrict__
#endif
#if !defined(CAT_FENCE_COMPILER)
# define CAT_FENCE_COMPILER CAT_ASM_BEGIN "" ::: "memory" CAT_ASM_END
#endif
#if !defined(CAT_DLL_EXPORT)
# define CAT_DLL_EXPORT __attribute__((dllexport))
#endif
#if !defined(CAT_DLL_IMPORT)
# define CAT_DLL_IMPORT __attribute__((dllimport))
#endif
#endif // CAT_COMPILER_COMPAT_*
//// Debug Flag ////
#if defined(CAT_COMPILER_MSVC)
# if defined(_DEBUG)
# define CAT_DEBUG
# endif
#else
# if !defined(NDEBUG)
# define CAT_DEBUG
# endif
#endif
//// Instruction Set Architecture ////
#if defined(__powerpc__) || defined(__ppc__) || defined(_POWER) || defined(_M_PPC) || \
defined(_M_MPPC) || defined(__POWERPC) || defined(powerpc) || defined(__ppc64__) || \
defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3) || defined(__POWERPC__)
# define CAT_ISA_PPC
#elif defined(__i386__) || defined(i386) || defined(intel) || defined(_M_IX86) || \
defined(__ia64) || defined(__ia64__) || defined(__x86_64) || defined(_M_IA64) || \
defined(_M_X64)
# define CAT_ISA_X86
#elif defined(TARGET_CPU_ARM)
# define CAT_ISA_ARM
#elif defined(__mips__)
# define CAT_ISA_MIPS
#elif defined(__ALPHA__)
# define CAT_ISA_ALPHA
#else
# define CAT_ISA_UNKNOWN
#endif
//// Endianness ////
// Okay -- Technically IA64 and PPC can switch endianness with an MSR bit
// flip, but come on no one does that! ...Right?
// If it's not right, make sure that one of the first two flags are defined.
#if defined(__LITTLE_ENDIAN__)
# define CAT_ENDIAN_LITTLE
#elif defined(__BIG_ENDIAN__)
# define CAT_ENDIAN_BIG
#elif defined(CAT_ISA_X86)
# define CAT_ENDIAN_LITTLE
#elif defined(CAT_ISA_PPC)
# define CAT_ENDIAN_BIG
#else
# define CAT_ENDIAN_UNKNOWN /* Must be detected at runtime */
#endif
//// Word Size ////
#if defined(_LP64) || defined(__LP64__) || defined(__arch64__) || \
defined(_WIN64) || defined(_M_X64) || defined(__ia64) || \
defined(__ia64__) || defined(__x86_64) || defined(_M_IA64) || \
defined(__mips64)
# define CAT_WORD_64
// 64-bit MSVC does not support inline assembly
# if defined(CAT_COMPILER_MSVC)
# undef CAT_ASM_INTEL
# endif
#else // Assuming 32-bit otherwise!
# define CAT_WORD_32
#endif
// __fastcall calling convention is rarely supported, and doesn't make sense for 64-bit targets
#if !defined(CAT_FASTCALL)
# define CAT_FASTCALL
#elif !defined(CAT_ISA_X86) || defined(CAT_WORD_64)
# undef CAT_FASTCALL
# define CAT_FASTCALL
#endif
//// Operating System ////
#if defined(__APPLE__) && defined(TARGET_OS_IPHONE)
# define CAT_OS_IPHONE
# define CAT_OS_APPLE
#elif defined(__APPLE__) && (defined(__MACH__) || defined(__DARWIN__))
# define CAT_OS_OSX
# define CAT_OS_APPLE
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
# define CAT_OS_BSD
#elif defined(__linux__) || defined(__unix__)
# define CAT_OS_LINUX
#elif defined(_WIN32_WCE)
# define CAT_OS_WINDOWS_CE
# define CAT_OS_WINDOWS /* Also defined */
#elif defined(_WIN32)
# define CAT_OS_WINDOWS
#elif defined(_XBOX) || defined(_X360)
# define CAT_OS_XBOX
#elif defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3)
# define CAT_OS_PS3
#elif defined(__OS2__)
# define CAT_OS_OS2
#elif defined(__APPLE__)
# define CAT_OS_APPLE
#else
# define CAT_OS_UNKNOWN
#endif
// Detect CYGWIN environment
#if defined(__CYGWIN__) || defined(__CYGWIN32__)
# define CAT_CYGWIN
#endif
// DLL import/export macros based on OS
#if defined(CAT_OS_WINDOWS) || defined(CAT_CYGWIN)
# if defined(CAT_NEUTER_EXPORT)
# define CAT_EXPORT /* Do not import or export any symbols */
# elif defined(CAT_BUILD_DLL)
# define CAT_EXPORT CAT_DLL_EXPORT /* Implementing a DLL so export this symbol */
# else
# define CAT_EXPORT CAT_DLL_IMPORT /* Using a DLL so import this symbol, faster on Windows */
# endif
#else
# undef CAT_DLL_EXPORT
# undef CAT_DLL_IMPORT
# define CAT_DLL_EXPORT
# define CAT_DLL_IMPORT
# define CAT_EXPORT
#endif
//// Basic types ////
#if defined(CAT_COMPILER_MSVC)
// MSVC does not ship with stdint.h (C99 standard...)
typedef unsigned __int8 u8;
typedef signed __int8 s8;
typedef unsigned __int16 u16;
typedef signed __int16 s16;
typedef unsigned __int32 u32;
typedef signed __int32 s32;
typedef unsigned __int64 u64;
typedef signed __int64 s64;
#else
} // namespace cat
#include <stdint.h>
namespace cat {
// All other compilers use this
typedef uint8_t u8;
typedef int8_t s8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef int32_t s32;
typedef uint64_t u64;
typedef int64_t s64;
#endif
#if defined(CAT_COMPILER_GCC) && defined(CAT_WORD_64)
// GCC also adds 128-bit types :D
typedef __uint128_t u128;
typedef __int128_t s128;
#endif
typedef float f32;
typedef double f64;
union Float32 {
float f;
u32 i;
Float32(float n) { f = n; }
Float32(u32 n) { i = n; }
};
//// String and buffer macros ////
// Same as strncpy() in all ways except that the result is guaranteed to
// be a nul-terminated C string
#if defined(CAT_COMPILER_MSVC)
# define CAT_STRNCPY(dest, src, size) { strncpy_s(dest, size, src, size); (dest)[(size)-1] = '\0'; }
#else
# define CAT_STRNCPY(dest, src, size) { strncpy(dest, src, size); (dest)[(size)-1] = '\0'; }
#endif
// Because memory clearing is a frequent operation
#define CAT_CLR(dest, size) memset(dest, 0, size)
// Works for arrays, also
#define CAT_OBJCLR(object) memset((void*)&(object), 0, sizeof(object))
// Stringize
#define CAT_STRINGIZE(X) DO_CAT_STRINGIZE(X)
#define DO_CAT_STRINGIZE(X) #X
// Variable-length data trailing a struct
template<typename T> CAT_INLINE u8 *GetTrailingBytes(T *t) { return reinterpret_cast<u8*>( t ) + sizeof(T); }
// Bounds
template<typename T> CAT_INLINE T BoundMin(const T &minimum, const T &x)
{
if (x < minimum) return minimum;
return x;
}
template<typename T> CAT_INLINE T BoundMax(const T &maximum, const T &x)
{
if (x > maximum) return maximum;
return x;
}
template<typename T> CAT_INLINE T Bound(const T &minimum, const T &maximum, const T &x)
{
if (x < minimum) return minimum;
if (x > maximum) return maximum;
return x;
}
//// Miscellaneous bitwise macros ////
#define CAT_BITCLRHI8(reg, count) ((u8)((u8)(reg) << (count)) >> (count)) /* sets to zero a number of high bits in a byte */
#define CAT_BITCLRLO8(reg, count) ((u8)((u8)(reg) >> (count)) << (count)) /* sets to zero a number of low bits in a byte */
#define CAT_BITCLRHI16(reg, count) ((u16)((u16)(reg) << (count)) >> (count)) /* sets to zero a number of high bits in a 16-bit word */
#define CAT_BITCLRLO16(reg, count) ((u16)((u16)(reg) >> (count)) << (count)) /* sets to zero a number of low bits in a 16-bit word */
#define CAT_BITCLRHI32(reg, count) ((u32)((u32)(reg) << (count)) >> (count)) /* sets to zero a number of high bits in a 32-bit word */
#define CAT_BITCLRLO32(reg, count) ((u32)((u32)(reg) >> (count)) << (count)) /* sets to zero a number of low bits in a 32-bit word */
//// Integer macros ////
#define CAT_AT_LEAST_2_BITS(n) ( (n) & ((n) - 1) )
#define CAT_LEAST_SIGNIFICANT_BIT(n) ( (n) & (u32)(-(s32)(n)) ) /* 0 -> 0 */
#define CAT_IS_POWER_OF_2(n) ( n && !CAT_AT_LEAST_2_BITS(n) )
// Safely take the average of two numbers without possibility of overflow
#define CAT_SAFE_AVERAGE(A, B) (((A) & (B)) + (((A) ^ (B)) >> 1))
// Bump 'n' to the next unit of 'width'
// 0=CAT_CEIL_UNIT(0, 16), 1=CAT_CEIL_UNIT(1, 16), 1=CAT_CEIL_UNIT(16, 16), 2=CAT_CEIL_UNIT(17, 16)
#define CAT_CEIL_UNIT(n, width) ( ( (n) + (width) - 1 ) / (width) )
// 0=CAT_CEIL(0, 16), 16=CAT_CEIL(1, 16), 16=CAT_CEIL(16, 16), 32=CAT_CEIL(17, 16)
#define CAT_CEIL(n, width) ( CAT_CEIL_UNIT(n, width) * (width) )
//// Rotation macros ////
#define CAT_ROL8(n, r) ( ((u8)(n) << (r)) | ((u8)(n) >> ( 8 - (r))) ) /* only works for u8 */
#define CAT_ROR8(n, r) ( ((u8)(n) >> (r)) | ((u8)(n) << ( 8 - (r))) ) /* only works for u8 */
#define CAT_ROL16(n, r) ( ((u16)(n) << (r)) | ((u16)(n) >> (16 - (r))) ) /* only works for u16 */
#define CAT_ROR16(n, r) ( ((u16)(n) >> (r)) | ((u16)(n) << (16 - (r))) ) /* only works for u16 */
#define CAT_ROL32(n, r) ( ((u32)(n) << (r)) | ((u32)(n) >> (32 - (r))) ) /* only works for u32 */
#define CAT_ROR32(n, r) ( ((u32)(n) >> (r)) | ((u32)(n) << (32 - (r))) ) /* only works for u32 */
#define CAT_ROL64(n, r) ( ((u64)(n) << (r)) | ((u64)(n) >> (64 - (r))) ) /* only works for u64 */
#define CAT_ROR64(n, r) ( ((u64)(n) >> (r)) | ((u64)(n) << (64 - (r))) ) /* only works for u64 */
//// Byte-order swapping ////
#define CAT_BOSWAP16(n) CAT_ROL16(n, 8)
#define CAT_BOSWAP32(n) ( (CAT_ROL32(n, 8) & 0x00ff00ff) | (CAT_ROL32(n, 24) & 0xff00ff00) )
#define CAT_BOSWAP64(n) ( ((u64)CAT_BOSWAP32((u32)n) << 32) | CAT_BOSWAP32((u32)(n >> 32)) )
//// Intrinsics ////
#if defined(CAT_OS_WINDOWS_CE)
#pragma intrinsic(_lrotl)
#pragma intrinsic(_lrotr)
#undef CAT_ROL32
#undef CAT_ROR32
#define CAT_ROL32(n, r) _lrotl(n, r)
#define CAT_ROR32(n, r) _lrotr(n, r)
#elif defined(CAT_COMPILER_MSVC)
#pragma intrinsic(_rotl)
#pragma intrinsic(_rotr)
#pragma intrinsic(_rotl64)
#pragma intrinsic(_rotr64)
#pragma intrinsic(_byteswap_ushort)
#pragma intrinsic(_byteswap_ulong)
#pragma intrinsic(_byteswap_uint64)
#pragma intrinsic(_BitScanForward)
#pragma intrinsic(_BitScanReverse)
#pragma intrinsic(__emulu)
#pragma intrinsic(_InterlockedExchange)
#pragma intrinsic(_interlockedbittestandset)
#pragma intrinsic(_interlockedbittestandreset)
#if defined(CAT_WORD_64)
#pragma intrinsic(__rdtsc)
#pragma intrinsic(_umul128)
#pragma intrinsic(_BitScanForward64)
#pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_InterlockedCompareExchange128)
#else
#pragma intrinsic(_InterlockedCompareExchange64)
#endif
#undef CAT_ROL32
#undef CAT_ROR32
#undef CAT_ROL64
#undef CAT_ROR64
#undef CAT_BOSWAP16
#undef CAT_BOSWAP32
#undef CAT_BOSWAP64
#define CAT_ROL32(n, r) _rotl(n, r)
#define CAT_ROR32(n, r) _rotr(n, r)
#define CAT_ROL64(n, r) _rotl64(n, r)
#define CAT_ROR64(n, r) _rotr64(n, r)
#define CAT_BOSWAP16(n) _byteswap_ushort(n)
#define CAT_BOSWAP32(n) _byteswap_ulong(n)
#define CAT_BOSWAP64(n) _byteswap_uint64(n)
#endif
} // namespace cat
#endif // CAT_PLATFORM_HPP

View File

@ -0,0 +1,80 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_SINGLETON_HPP
#define CAT_SINGLETON_HPP
#include <cat/Platform.hpp>
namespace cat {
// Derived class should define the constructor using this macro:
#define CAT_SINGLETON(subclass) \
private: \
friend class Singleton<subclass>; \
subclass()
//// Singleton
template<class T> class Singleton
{
protected:
Singleton<T>() {}
Singleton<T>(Singleton<T> &) {}
Singleton<T> &operator=(Singleton<T> &) {}
public:
static T *ii;
public:
CAT_INLINE static T *ref()
{
if (ii) return ii;
return ii = new T;
}
CAT_INLINE static void deallocate()
{
if (ii)
{
delete ii;
ii = 0;
}
}
virtual ~Singleton() {}
};
// TODO: I'm actually not 100% sure this always works
template<class T> T *Singleton<T>::ii = 0;
} // namespace cat
#endif // CAT_SINGLETON_HPP

View File

@ -0,0 +1,56 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Forward declaration for assembly routines in big_x64_*.asm
#ifndef CAT_BIG_X64_ASM_HPP
#define CAT_BIG_X64_ASM_HPP
#include <cat/math/Legs.hpp>
#if defined(CAT_WORD_64)
namespace cat {
extern "C" void bpm_add_4(Leg modulus_c, const Leg *in_a, const Leg *in_b, Leg *out);
extern "C" void bpm_sub_4(Leg modulus_c, const Leg *in_a, const Leg *in_b, Leg *out);
extern "C" void bpm_mul_4(Leg modulus_c, const Leg *in_a, const Leg *in_b, Leg *out);
extern "C" void bpm_mulx_4(Leg modulus_c, const Leg *in_a, Leg in_b, Leg *out);
extern "C" void bpm_sqr_4(Leg modulus_c, const Leg *in, Leg *out);
extern "C" Leg divide64_x(Leg legs, const Leg *in_a, const Leg in_b, Leg *out_q);
extern "C" Leg modulus64_x(Leg legs, const Leg *in_a, const Leg in_b);
extern "C" void divide64_core(Leg A_used, Leg A_overflow, const Leg *A, Leg B_used, const Leg *B, Leg *Q);
} // namespace cat
#endif // CAT_WORD_64
#endif // CAT_BIG_X64_ASM_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,219 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_RANGE_CODER_HPP
#define CAT_RANGE_CODER_HPP
#include <cat/Platform.hpp>
#include <ostream>
#include <map>
#include <string>
namespace cat {
/*
TextStatsCollector
Collects order-1 statistics of the text given one character at a time.
Order-1 statistics include the likelihood of a character given the previous one.
This is intended to be used on a large sample of text (of unlimited length)
to come up with statistics that most text should follow. When the resulting
table is used with a range coder, compression should be reliably achieved,
though a bit should be allocated for the case where the result of the coder
would be longer than encoding with uniform ranges, like if someone enters "ZZZZ".
The RangeEncoder class has a text compressor based on the output of this class.
I opted for a static table because this is to be run on a network server
where many clients are connected. The memory needed for this type of
compression does not increase with the number of clients.
*/
class TextStatsCollector
{
u32 last, total, frequencies[256][256];
u8 seen[256];
public:
TextStatsCollector();
public:
// Record a character occurance
// 0 = end of line, so next character counts towards initial character frequency
void Tally(u8 x);
#if defined(CAT_PRAGMA_PACK)
#pragma pack(push)
#pragma pack(1)
#endif
struct TableFormat
{
// MurmurHash2 of remainder, with seed = 0
u32 hash;
// Total symbols in the table <= 256
u16 total;
// Fraction of a byte represented by total, scaled from [0, 2^15]
u16 log2total;
// ASCII character code -> Table index map
u8 char2index[256];
// Table index -> ASCII character code map
u8 index2char[256];
/*
Start of frequency table
The first 32 entries are used for reverse lookup (freq->symbol):
GET_SYMBOL_LUT() will get this address:
frequencies[0..15] = array of 16 bytes creating a lookup table (LUT) given
the high 4 bits of the frequency, for the low range
frequencies[16..31] = array of 16 bytes creating a lookup table (LUT) given
the high 4 bits of the frequency, for the high range
GET_SYMBOL_BASE() will get this address:
frequencies[32] = cumulative frequency for (last=0, this=1) out of 2^16 trials
frequencies[33] = cumulative frequency for (last=0, this=2) out of 2^16 trials
frequencies[34] = ...
Note: (0, 0) is implicitly zero, and (0, TOTAL) is implicitly 2^16
So these tables don't include those implicit entries.
*/
u16 frequencies[1];
} CAT_PACKED;
#if defined(CAT_PRAGMA_PACK)
#pragma pack(pop)
#endif
// Returns code that creates a table in the above format
bool GenerateMinimalStaticTable(const char *TableName, std::ostream &osout);
// Check for errors in the in-memory version of the table that was generated
static bool VerifyTableIntegrity(const TableFormat *table);
};
/*
Range Encoder
Encodes a single message one field at a time using the minimum
number of bits, rounded up to the next highest byte.
To insure that the message does not grow in size, provide limited
space for the output buffer and check .Fail() at the end. If it
failed, this means it ran out of space during encoding.
If encoding succeeded, check .Used() to determine the number of
bytes used by the output buffer.
*/
class RangeEncoder
{
u8 *output;
int limit, remaining;
u64 low, range;
// Write out bytes as needed
CAT_INLINE void Normalize();
CAT_INLINE void GetTableSymbol(const TextStatsCollector::TableFormat *stats, u32 &last, u8 ch, u16 &symbol_low, u16 &symbol_range);
public:
// Ctors
RangeEncoder(void *output_i, int limit_i);
RangeEncoder(RangeEncoder &cp);
// Overwrite one context with another. Using context references instead
// of working on the contexts directly is probably more efficient.
RangeEncoder &operator=(RangeEncoder &cp);
// State accessors
bool Fail() { return output == 0; }
int Used() { return limit - remaining; }
public:
// Encode the given text with the given statistics
// NOTE: May be up to one byte longer than the original message
void Text(const char *msg, const TextStatsCollector::TableFormat *stats);
// Encode a biased bit given the frequency it is 0
// frequency = average times out of 2^32 trials the bit will be 0
void BiasedBit(u32 b, u32 frequency);
// Encode a field that takes on [0, total) values with equal likelihood
void Range(u32 symbol, u32 total);
// Emit the final byte(s) needed to encode the symbols
void Finish();
};
/*
Range Decoder
Interprets buffers produced by RangeEncoder
*/
class RangeDecoder
{
const u8 *input;
int remaining;
u64 code, low, range;
// Read in bytes as needed
CAT_INLINE void Normalize();
// Grab symbol low frequency and range from the table
CAT_INLINE u8 GetTableSymbol(const TextStatsCollector::TableFormat *stats, u32 &last, u16 freq, u16 &symbol_low, u16 &symbol_range);
public:
// Initializing constructor
RangeDecoder(const void *message, int bytes);
int Remaining() { return remaining; }
public:
// Decode the given text with the given statistics
int Text(char *msg, int buffer_size, const TextStatsCollector::TableFormat *stats);
// Decode a biased bit given the frequency it is 0
// frequency = average times out of 2^32 trials the bit will be 0
u32 BiasedBit(u32 frequency);
// Decode a field that takes on [0, total) values with equal likelihood
u32 Range(u32 total);
};
} // namespace cat
#endif // CAT_RANGE_CODER_HPP

View File

@ -0,0 +1,45 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_SECURE_COMPARE_HPP
#define CAT_SECURE_COMPARE_HPP
#include <cat/Platform.hpp>
namespace cat {
// Binary comparison function that is resistant to timing attack
// Note that memcmp() and strcmp() are both vulnerable
// Returns true if they are equal
bool SecureEqual(const void *A, const void *B, int bytes);
} // namespace cat
#endif // SECURE_COMPARE_HPP

View File

@ -0,0 +1,70 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_COOKIE_JAR_HPP
#define CAT_COOKIE_JAR_HPP
#include <cat/crypt/rand/Fortuna.hpp>
namespace cat {
class CookieJar
{
static const int EXPIRE_TIME = 4000; // ms
static const int BIN_COUNT = 16; // power of 2
static const int BIN_TIME = EXPIRE_TIME / BIN_COUNT;
static const int BIN_MASK = BIN_COUNT - 1;
u32 key[16];
u32 Salsa6(u32 *x);
u32 Hash(u32 ip, u16 port, u32 epoch);
u32 Hash(const void *address_info, int bytes, u32 epoch);
u32 GetEpoch();
u32 ReconstructEpoch(u32 cookie);
public:
// Initialize to a random 512-bit key on startup
void Initialize(FortunaOutput *csprng);
// Thread-safe and lock-free
u32 Generate(u32 ip, u16 port);
u32 Generate(const void *address_info, int bytes); // bytes <= 48
// Thread-safe and lock-free
bool Verify(u32 ip, u16 port, u32 cookie);
bool Verify(const void *address_info, int bytes, u32 cookie); // bytes <= 48
};
} // namespace cat
#endif // CAT_COOKIE_JAR_HPP

View File

@ -0,0 +1,87 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
HMAC-MD5 is still secure despite the ease of producing collisions in MD5.
See Mihir Bellare paper "New Proofs for NMAC and HMAC: Security without Collision-Resistance" (June 2006)
Using HMAC construction:
HMAC(x) = h(k || p1 || h(k || p2 || x))
h() = MD5 hash
p1,p2 = distinct padding to bring k up to the block size
p1 = 0x36 repeated, p2 = 0x5c repeated
Diverges from usual implementation by using little-endian rather than big-endian input
*/
#ifndef HMAC_MD5_HPP
#define HMAC_MD5_HPP
#include <cat/crypt/hash/ICryptHash.hpp>
namespace cat {
class CAT_EXPORT HMAC_MD5 : public ICryptHash
{
protected:
static const int DIGEST_BYTES = 16;
static const int WORK_BYTES = 64; // bytes in one block
static const int WORK_WORDS = WORK_BYTES / sizeof(u32);
u32 CachedInitialState[4]; // Cached state for H(K||inner padding)
u32 CachedFinalState[4]; // Cached state for H(K||outer padding)
u64 byte_counter;
u32 State[4];
u8 Work[WORK_BYTES];
int used_bytes;
void HashComputation(const void *message, int blocks, u32 *NextState);
// Unsupported modes
bool BeginKey(int /*bits*/) { return false; }
bool BeginKDF() { return false; }
bool BeginPRNG() { return false; }
public:
~HMAC_MD5();
bool SetKey(ICryptHash *parent);
void RekeyFromMD5(HMAC_MD5 *parent);
bool BeginMAC();
void Crunch(const void *message, int bytes);
void End();
// TODO: Strengthening is not supported right now
void Generate(void *out, int bytes, int strengthening_rounds = 0);
};
} // namespace cat
#endif // HMAC_MD5_HPP

View File

@ -0,0 +1,79 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// 06/15/09 began
#ifndef CAT_I_CRYPT_HASH_HPP
#define CAT_I_CRYPT_HASH_HPP
#include <cat/Platform.hpp>
#include <cstring>
namespace cat {
// Cryptographic hash functions of any size will derive from ICryptoHash and implement its public methods
class CAT_EXPORT ICryptHash
{
protected:
int digest_bytes;
public:
virtual ~ICryptHash() {}
// Returns the number of bytes in a message digest produced by this hash
CAT_INLINE int GetDigestByteCount() { return digest_bytes; }
CAT_INLINE void CrunchString(const char *s) { Crunch(s, (int)std::strlen(s) + 1); }
public:
// Begin a new key
virtual bool BeginKey(int bits) = 0;
// Start from an existing key
virtual bool SetKey(ICryptHash *parent) = 0;
// Begin hash function in MAC, KDF, or PRNG mode
virtual bool BeginMAC() = 0;
virtual bool BeginKDF() = 0;
virtual bool BeginPRNG() = 0;
// Crunch some message bytes
virtual void Crunch(const void *message, int bytes) = 0;
// Finalize the hash and prepare to generate output
virtual void End() = 0;
// Extended hash output mode
virtual void Generate(void *out, int bytes, int strengthening_rounds = 0) = 0;
};
} // namespace cat
#endif // CAT_I_CRYPT_HASH_HPP

View File

@ -0,0 +1,108 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Bruce Schneier's SHA-3 candidate Skein hash function
http://www.skein-hash.info/
*/
#ifndef CAT_SKEIN_HPP
#define CAT_SKEIN_HPP
#include <cat/crypt/hash/ICryptHash.hpp>
namespace cat {
// Base class for various versions of Skein
class CAT_EXPORT Skein : public ICryptHash
{
protected:
// Tweak word 1 bit field starting positions
static const int T1_POS_TREE_LVL = 112-64; // bits 112..118 : level in hash tree
static const int T1_POS_BIT_PAD = 119-64; // bit 119 : partial final input byte
static const int T1_POS_BLK_TYPE = 120-64; // bits 120..125 : type field
static const int T1_POS_FIRST = 126-64; // bits 126 : first block flag
static const int T1_POS_FINAL = 127-64; // bit 127 : final block flag
// Tweak word 1 bit field masks
static const u64 T1_MASK_FIRST = (u64)1 << T1_POS_FIRST;
static const u64 T1_MASK_FINAL = (u64)1 << T1_POS_FINAL;
static const u64 T1_MASK_BIT_PAD = (u64)1 << T1_POS_BIT_PAD;
static const u64 T1_MASK_TREE_LVL = (u64)0x7F << T1_POS_TREE_LVL;
static const u64 T1_MASK_BLK_TYPE = (u64)63 << T1_POS_BLK_TYPE;
static const int BLK_TYPE_KEY = 0; // key, for MAC and KDF
static const int BLK_TYPE_CFG = 4; // configuration block
static const int BLK_TYPE_PERS = 8; // personalization string
static const int BLK_TYPE_PK = 12; // public key (for digital signature hashing)
static const int BLK_TYPE_KDF = 16; // key identifier for KDF
static const int BLK_TYPE_NONCE = 20; // nonce for PRNG
static const int BLK_TYPE_MSG = 48; // message processing
static const int BLK_TYPE_OUT = 63; // output stage
static const u32 ID_STRING_LE = 0x33414853;
static const u32 SKEIN_VERSION = 1;
static const u64 SCHEMA_VER = ((u64)SKEIN_VERSION << 32) | ID_STRING_LE;
static const int MAX_BITS = 512;
static const int MAX_WORDS = MAX_BITS / 64;
static const int MAX_BYTES = MAX_BITS / 8;
u64 Tweak[2];
u64 State[MAX_WORDS];
u8 Work[MAX_BYTES];
int used_bytes, digest_words;
u64 output_block_counter;
bool output_prng_mode;
typedef void (Skein::*HashComputation)(const void *message, int blocks, u32 byte_count, u64 *NextState);
void HashComputation256(const void *message, int blocks, u32 byte_count, u64 *NextState);
void HashComputation512(const void *message, int blocks, u32 byte_count, u64 *NextState);
HashComputation hash_func;
void GenerateInitialState(int bits);
public:
~Skein();
bool BeginKey(int bits);
bool SetKey(ICryptHash *parent);
bool BeginMAC();
bool BeginKDF();
bool BeginPRNG();
void Crunch(const void *message, int bytes);
void End();
void Generate(void *out, int bytes, int strengthening_rounds = 0);
};
} // namespace cat
#endif // CAT_SKEIN_HPP

View File

@ -0,0 +1,193 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_PASSWORDS_HPP
#define CAT_PASSWORDS_HPP
#include <cat/rand/IRandom.hpp>
namespace cat {
/*
Why are passwords needed?
Passwords allow the client identity to be proved to the server. Usually
the server identity is already proven by a secure connection, but the
client identity is unproven until a password is provided.
This could be done using signatures with two-way authentication in the
secure connection establishment, however this is very slow and roughly
doubles the work a server has to do to accept a connection.
Passwords seem simple to implement at first but then you start imagining all
the "what ifs":
What if the password database is stolen?
The user passwords had better not be stored in plaintext!
So they must be hashed.
What if two users have the same password?
They would look the same hashed, so hash in the name with the password.
What if name:password for two users is "me : pass" and "m : epass" ?
They would look the same hashed, so insert a separator between the two
before hashing, as in "me\r\npass" instead of just hashing "mepass".
What if someone tries to crack the passwords?
The password hash should be strengthened to make it harder to crack,
by applying the hash function repeatedly. This does reduce the number of
bits of entropy due to non-ideal hash function collisions, but this small
effect is offset by the added difficulty to crack the password.
What if the user has a common name like "dave"?
The password hash should be salted to avoid falling to rainbow tables.
What if the attacker tries to use the stolen password hash to log into the server?
The client provides a hash pre-image during login, so the attacker would need
to reverse the hash to do this, which is harder than cracking the password.
What if an attacker has a way to actively or passively listen to login attempts?
Then they would be able to steal the hash pre-image which would offer some
amount of text password protection but would allow the attacker to log in
as the user without knowing the password.
Rainbow tables can be used to crack the pre-image to determine the password.
If the connection is secure then the client has verified the server identity
and these attacks are only possible through software bugs in the server.
Protocol Description:
H: 256-bit hash function Skein-256
c: Client
s: Server
X: Strengthening factor
Protocol 1: Creating a User Account
c: Choose a name N
c: Choose a password P
c: Calculate I = H("N\r\nP") strengthened X times
c2s CREATE_ACCOUNT || N || I (32 by)
s: Verify account is not taken, then creates an account in the database
s: Generate a 32-bit random salt S
s: Calculate J = H(S || I)
s: Store N, J and S in the account
s2c ACCOUNT_CREATE_SUCCESS
Protocol 2: Logging into a User Account
c: Choose a name N
c: Choose a password P
c: Calculate I = H("N\r\nP") strengthened X times
c2s LOGIN_REQUEST || N || I (32 by)
s: Verify user name exists in account database
s: Retrieve J, S from the account database
s: Calculate J' = H(S || I)
s: Verify J = J'
s2c LOGIN_SUCCESS
What if the user creates an account through a website?
The server-side script on the website should execute a program that runs
Protocol 1 to create the user account.
Why use this sort of password authentication + Tunnel instead of SRP?
Performance. The Tunnel key agreement takes much less CPU time than SRP
and authenticates the server, which allows this protocol to be run without
any disadvantages.
*/
class PasswordBase
{
public:
static const int HASH_BITS = 256;
static const int HASH_BYTES = HASH_BITS / 8;
static const int STRENGTHENING_FACTOR = 1000;
};
class PasswordCreator : public PasswordBase
{
public:
// Hash a password for transmission to the server during account creation or login
// NOTE: You should make the name all lowercase before passing it in
// Returns false on failure
bool HashPassword(const void *in_name, int name_bytes,
const void *in_password, int password_bytes,
void *out_hash /* 32 bytes */);
// This version accepts non-unicode C strings with nul-terminators
// It converts the name to lowercase internally
bool HashPasswordString(const char *in_name,
const char *in_password,
void *out_hash /* 32 bytes */);
};
class PasswordVerifier : public PasswordBase
{
public:
// Salt a hash for storage in the account database during account creation
// Generates a 32-bit salt and a 256-bit hash for storage
// Returns false on failure
bool SaltHash(IRandom *prng,
const void *in_hash /* 32 bytes */,
void *out_salted_hash /* 32 bytes */,
u32 *out_salt /* 4 bytes */);
// Given the stored salted hash and salt, verify the client's password hash during login
// Returns false if password is incorrect
bool VerifyHash(const void *in_hash /* 32 bytes */,
const void *in_salted_hash /* 32 bytes */,
u32 in_salt /* 4 bytes */);
};
} // namespace cat
#endif // CAT_PASSWORDS_HPP

View File

@ -0,0 +1,222 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Based on Fortuna algorithm from "Practical Cryptography" section 10.3
Published 2003 by Niels Ferguson and Bruce Schneier
Fortuna supplements the operating system (OS) pseudo-random number generator (PRNG)
by incorporating additional entropy into the seeds that the OS provides.
Modified for use with Skein in PRNG mode, sharing the strengths of both algorithms.
My implementation of Fortuna (call it Cat For Tuna) has the following components:
+ Entropy Pools
+ 32 pools numbered 0..31
+ Implemented as 32 instances of the 256-bit Skein hash
+ Entropy hashed into pools in a round-robin fashion
+ Scheme allows for recovery against attacker with knowledge of some sources
+ Entropy Sources
+ Uses best OS random number generator
+ And a variable number of OS-dependent entropy sources
+ Mainly cycle counts and other timing information
+ Output Generator
+ Implemented as a 512-bit Skein hash of some combination of the entropy pools
+ The output is produced by the PRNG mode of Skein keyed by the pools
+ Hashing all of these pools together and keying the output is called "seeding"
+ Reseeded after sufficient entropy has been collected in pool 0
+ Pool 0 is always used for reseeding
+ Reseed X uses pools numbered by the 1-bits in X (except MSB)
+ Previous seed keys the next seed
+ Diverges from normal Fortuna due to use of Skein instead of a block cipher
+ Reseeds only once every ~512 seconds
+ Does not have a limit of 2^16 output blocks
+ Skein-PRNG is guaranteed sufficient security properties anyway
The Fortuna algorithm is broken up into two objects for efficient thread-safety:
+ FortunaFactory
+ Must be initialized on startup and shut down on shutdown
+ Spawns a thread to periodically collect additional entropy
+ Can create FortunaOutput objects
+ FortunaOutput
+ Reseeds based on master seed in the FortunaFactory
+ Reseeds after master seed is updated
+ Provides a unique random stream for each thread that uses Fortuna
*/
#ifndef CAT_FOR_TUNA_HPP
#define CAT_FOR_TUNA_HPP
#include <cat/rand/IRandom.hpp>
#include <cat/crypt/hash/Skein.hpp>
#include <cat/Singleton.hpp>
#include <cat/threads/Mutex.hpp>
// Defining CAT_NO_ENTROPY_THREAD will remove dependencies on pthreads and not
// run a thread to collect more entropy. This is recommended for low-power targets
// and other systems where no thread library is available
#if defined(CAT_OS_WINDOWS_CE)
# define CAT_NO_ENTROPY_THREAD
#endif
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
# include <wincrypt.h>
#endif
#if !defined(CAT_NO_ENTROPY_THREAD)
# include <cat/threads/Thread.hpp>
# include <cat/threads/WaitableFlag.hpp>
#endif
namespace cat {
class FortunaOutput;
class FortunaFactory;
// Factory for constructing FortunaOutput objects
class FortunaFactory : public Singleton<FortunaFactory>
#if !defined(CAT_NO_ENTROPY_THREAD)
, public Thread
#endif
{
CAT_SINGLETON(FortunaFactory)
{
_initialized = false;
}
Mutex _lock;
friend class FortunaOutput;
#if defined(CAT_OS_WINDOWS) && !defined(CAT_OS_WINDOWS_CE)
typedef LONG (WINAPI *PtNtQuerySystemInformation)(
int SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
HANDLE CurrentProcess;
HMODULE NTDLL;
PtNtQuerySystemInformation NtQuerySystemInformation;
HCRYPTPROV hCryptProv;
#elif defined(CAT_OS_WINDOWS_CE)
HCRYPTPROV hCryptProv;
#elif defined(CAT_OS_LINUX)
int urandom_fd;
#endif
#if !defined(CAT_NO_ENTROPY_THREAD)
static const int ENTROPY_THREAD_KILL_TIMEOUT = 10000; // 10 seconds
WaitableFlag _kill_flag;
bool ThreadFunction(void *param);
#endif
protected:
static const int ENTROPY_POOLS = 32; // Setting this higher would break something
static const int POOL_BITS = 512;
static const int POOL_BYTES = POOL_BITS / 8;
static const int POOL_QWORDS = POOL_BYTES / sizeof(u64);
static u32 MasterSeedRevision; // Should not roll over for 13 years if incremented once every RESEED_MIN_TIME
static Skein MasterSeed;
bool _initialized;
u32 reseed_counter;
Skein Pool[ENTROPY_POOLS];
bool Reseed();
void GetNextKey(FortunaOutput *output);
bool InitializeEntropySources();
void PollInvariantSources(int pool);
void PollSlowEntropySources(int pool);
void PollFastEntropySources(int pool);
void ShutdownEntropySources();
public:
// Start the entropy generator
bool Initialize();
// Stop the entropy generator
void Shutdown();
// Create a new Fortuna object
static FortunaOutput *Create();
};
// LoopThread-safe output object for Fortuna
class FortunaOutput : public IRandom
{
friend class FortunaFactory;
static const int OUTPUT_CACHE_BYTES = FortunaFactory::POOL_BYTES * 8; // Arbitrary
u32 thread_id, SeedRevision;
Skein OutputHash;
u8 CachedRandomBytes[OUTPUT_CACHE_BYTES];
int used_bytes;
void Reseed();
FortunaOutput();
FortunaOutput(FortunaOutput&) {}
FortunaOutput &operator=(FortunaOutput &) { return *this; }
public:
~FortunaOutput();
// Generate a 32-bit random number
u32 Generate();
// Generate a variable number of random bytes
void Generate(void *buffer, int bytes);
};
} // namespace cat
#endif // CAT_FOR_TUNA_HPP

View File

@ -0,0 +1,145 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
The ChaCha cipher is a symmetric stream cipher based on Salsa20.
http://cr.yp.to/chacha.html
*/
#ifndef CAT_CHACHA_HPP
#define CAT_CHACHA_HPP
#include <cat/Platform.hpp>
namespace cat {
/*
To initialize the ChaCha cipher, you must specify a 256-bit key.
Code example:
ChaChaKey cck;
char key[32]; // fill key here
cck.Key(key, sizeof(key));
Before each encryption or decryption with the ChaCha cipher,
a 64-bit Initialization Vector (IV) must be specified. Every
time a message is encrypted, the IV must be incremented by 1.
The IV is then sent along with the encrypted message.
Encryption code example:
char message[19], ciphertext[19]; // message filled here
u64 iv = 125125;
u64 message_iv = iv;
iv = iv + 1;
ChaChaOutput cco(cck, message_iv);
cco.Crypt(message, ciphertext, sizeof(ciphertext));
Decryption code example:
char ciphertext[19], decrypted[19]; // ciphertext filled here
ChaChaOutput cco(cck, message_iv);
cco.Crypt(ciphertext, decrypted, sizeof(decrypted));
Sending all 8 bytes of the IV in every packet is not necessary.
Instead, only a few of the low bits of the IV need to be sent,
if the IV is incremented by 1 each time.
How many? It depends on how many messages can get lost.
If < 32768 messages can get lost in a row, then CAT_IV_BITS = 16 (default)
I have provided a function to handle rollover/rollunder of the IV,
which also works if the same IV is sent twice for some reason.
It needs to know how many of the low bits are sent across, so be sure
to change CAT_IV_BITS in this header if you send more or less than 16.
Code example:
u64 last_accepted_iv;
u32 new_iv_low_bits;
u64 new_iv = ChaCha::ReconstructIV(last_accepted_iv, new_iv_low_bits);
-------------------------READ THIS BEFORE USING--------------------------
Never use the same IV twice.
Otherwise: An attacker can recover the plaintext without the key.
Never use the same key twice.
Otherwise: An attacker can recover the plaintext without the key.
If you have two hosts talking to eachother securely with ChaCha encryption,
then be sure that each host is encrypting with a DIFFERENT key.
Otherwise: An attacker can recover the plaintext without the key.
Remember that an attacker can impersonate the remote computer, so be
sure not to accept the new IV until the message authentication code has
been verified if your protocol uses a message authentication code (MAC).
Otherwise: An attacker could desynchronize the IVs.
*/
//// ChaChaKey
class CAT_EXPORT ChaChaKey
{
friend class ChaChaOutput;
u32 state[16];
public:
~ChaChaKey();
// Key up to 384 bits
void Set(const void *key, int bytes);
};
//// ChaChaOutput
class CAT_EXPORT ChaChaOutput
{
u32 state[16];
void GenerateKeyStream(u32 *out);
public:
ChaChaOutput(const ChaChaKey &key, u64 iv);
~ChaChaOutput();
// Message with any number of bytes
void Crypt(const void *in, void *out, int bytes);
};
} // namespace cat
#endif // CAT_CHACHA_HPP

View File

@ -0,0 +1,148 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_AUTHENTICATED_ENCRYPTION_HPP
#define CAT_AUTHENTICATED_ENCRYPTION_HPP
#include <cat/crypt/symmetric/ChaCha.hpp>
#include <cat/crypt/hash/Skein.hpp>
#include <cat/crypt/hash/HMAC_MD5.hpp>
namespace cat {
/*
Tunnel Authenticated Encryption "Calico" protocol:
Run after the Key Agreement protocol completes.
Uses a 1024-bit anti-replay sliding window, suitable for Internet file transfer over UDP.
Cipher: 12-round ChaCha with 256-bit or 384-bit keys
KDF: Key derivation function (Skein)
MAC: 64-bit truncated HMAC-MD5
IV: Initialization vector incrementing by 1 each time
c2sMKey = KDF(k) { "upstream-MAC" }
s2cMKey = KDF(k) { "downstream-MAC" }
c2sEKey = KDF(k) { "upstream-ENC" }
s2cEKey = KDF(k) { "downstream-ENC" }
c2sIV = KDF(k) { "upstream-IV" }
s2cIV = KDF(k) { "downstream-IV" }
To transmit a message, the client calculates a MAC with the c2sMKey of the IV concatenated with
the plaintext message and then appends the 8-byte MAC and low 3 bytes of the IV to the message,
which is encrypted using the c2sEKey and the IV.
c2s Encrypt(c2sEKey) { message || MAC(c2sMKey) { full-iv-us||message } } || Obfuscated { trunc-iv-us }
encrypted { MESSAGE(X) MAC(8by) } IV(3by) = 11 bytes overhead at end of packet
To transmit a message, the server calculates a MAC with the s2cMKey of the IV concatenated with
the plaintext message and then appends the 8-byte MAC and low 3 bytes of the IV to the message,
which is encrypted using the s2cEKey and the IV.
s2c Encrypt(s2cEKey) { message || MAC(s2cMKey) { full-iv-ds||message } } || Obfuscated { trunc-iv-ds }
encrypted { MESSAGE(X) MAC(8by) } IV(3by) = 11 bytes overhead at end of packet
The full 64-bit IVs are initialized to c2sIV and s2cIV, and the first one sent is IV+1.
*/
class KeyAgreementResponder;
class KeyAgreementInitiator;
// This class is NOT THREAD-SAFE.
class CAT_EXPORT AuthenticatedEncryption
{
friend class KeyAgreementResponder;
friend class KeyAgreementInitiator;
bool _is_initiator, _accept_out_of_order;
Skein key_hash;
HMAC_MD5 local_mac_key, remote_mac_key;
ChaChaKey local_cipher_key, remote_cipher_key;
u64 local_iv, remote_iv;
// 1024-bit anti-replay sliding window
static const int BITMAP_BITS = 1024;
static const int BITMAP_WORDS = BITMAP_BITS / 64;
u64 iv_bitmap[BITMAP_WORDS];
public:
CAT_INLINE AuthenticatedEncryption() {}
CAT_INLINE ~AuthenticatedEncryption() {}
// Tunnel overhead bytes
static const int MAC_BYTES = 8;
static const int IV_BYTES = 3;
static const u32 OVERHEAD_BYTES = IV_BYTES + MAC_BYTES;
// IV constants
static const int IV_BITS = IV_BYTES * 8;
static const u32 IV_MSB = (1 << IV_BITS);
static const u32 IV_MASK = (IV_MSB - 1);
static const u32 IV_FUZZ = 0xCA7DCA7D;
protected:
bool SetKey(int KeyBytes, Skein *key, bool is_initiator, const char *key_name);
bool IsValidIV(u64 iv);
void AcceptIV(u64 iv);
public:
// Generate a proof that the local host has the key
bool GenerateProof(u8 *local_proof, int proof_bytes);
// Validate a proof that the remote host has the key
bool ValidateProof(const u8 *remote_proof, int proof_bytes);
public:
void AllowOutOfOrder(bool allowed = true) { _accept_out_of_order = allowed; }
public:
// Overhead is OVERHEAD_BYTES bytes at the end of the packet
// Returns false if the message is invalid. Invalid messages should just be ignored as if they were never received
// buf_bytes: Number of bytes in the buffer, including the overhead
// If Decrypt() returns true, buf_bytes is set to the size of the decrypted message
bool Decrypt(u8 *buffer, u32 &buf_bytes);
// Overhead is OVERHEAD_BYTES bytes at the end of the packet
// buffer_bytes: Number of bytes in the buffer; will return false if buffer size too small
// msg_bytes: Number of bytes in the message, excluding the overhead
// If Encrypt() returns true, msg_bytes is set to the size of the encrypted message
bool Encrypt(u8 *buffer, u32 buffer_bytes, u32 &msg_bytes);
};
} // namespace cat
#endif // CAT_AUTHENTICATED_ENCRYPTION_HPP

View File

@ -0,0 +1,307 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_EASY_HANDSHAKE_HPP
#define CAT_EASY_HANDSHAKE_HPP
#include <cat/crypt/tunnel/KeyAgreementInitiator.hpp>
#include <cat/crypt/tunnel/KeyAgreementResponder.hpp>
#include <cat/crypt/cookie/CookieJar.hpp>
namespace cat {
/*
The EasyHandshake classes implement a simplified version of my Tunnel protocol.
This only works for single-threaded servers and only produces a single authenticated encryption
object for each handshake. Explanations on how to use the library with a multi-threaded
server, and how to use one handshake to secure several TCP streams, are documented in the
comments of these classes.
Over the network, the handshake will look like this:
client --> server : CHALLENGE (64 random-looking bytes)
server --> client : ANSWER (128 random-looking bytes)
client --> server : PROOF (32 random-looking bytes) + first encrypted packet can be appended here
As far as coding goes, the function calls fit into the protocol like this:
server is offline:
During startup, both the client and server should initialize the library.
This is necessary also just for generating keys:
----------------------------------------------------------------
#include <cat/AllTunnel.hpp>
using namespace cat;
if (!EasyHandshake::Initialize())
{
printf("ERROR:Unable to initialize crypto subsystem\n");
}
----------------------------------------------------------------
Generate the server public and private key pairs:
----------------------------------------------------------------
u8 public_key[EasyHandshake::PUBLIC_KEY_BYTES];
u8 private_key[EasyHandshake::PRIVATE_KEY_BYTES];
EasyHandshake temp;
temp.GenerateServerKey(public_key, private_key);
----------------------------------------------------------------
(keys are stored to disk for reading on start-up)
(public key is given to the client somehow)
+ built into the client code
+ provided by a trusted server
server comes online:
----------------------------------------------------------------
ServerEasyHandshake server_handshake;
server_handshake.Initialize(public_key, private_key);
----------------------------------------------------------------
client comes online:
----------------------------------------------------------------
ClientEasyHandshake client_handshake;
client_handshake.Initialize(public_key);
u8 challenge[EasyHandshake::CHALLENGE_BYTES];
client_handshake.GenerateChallenge(challenge);
----------------------------------------------------------------
client --> server : CHALLENGE (64 random-looking bytes)
----------------------------------------------------------------
AuthenticatedEncryption server_e;
u8 answer[EasyHandshake::ANSWER_BYTES];
server_handshake.ProcessChallenge(challenge, answer, &server_e);
----------------------------------------------------------------
server --> client : ANSWER (128 random-looking bytes)
----------------------------------------------------------------
AuthenticatedEncryption client_e;
client_handshake.ProcessAnswer(answer, &client_e);
u8 proof[EasyHandshake::PROOF_BYTES];
client_e.GenerateProof(proof, EasyHandshake::PROOF_BYTES);
----------------------------------------------------------------
Encryption example:
----------------------------------------------------------------
// Example message encryption of "Hello". Note that encryption
// inflates the size of the message by OVERHEAD_BYTES.
const int PLAINTEXT_BYTES = 5;
const int BUFFER_BYTES = \
PLAINTEXT_BYTES + AuthenticatedEncryption::OVERHEAD_BYTES;
int msg_bytes = PLAINTEXT_BYTES;
// Note that it makes room for message inflation
const u8 message[CIPHERTEXT_BYTES] = {
'H', 'e', 'l', 'l', 'o'
};
// Note the second parameter is the size of the buffer, and
// the third parameter will be adjusted to the size of the
// encrypted message:
if (client_e.Encrypt(message, BUFFER_BYTES, msg_bytes))
{
// msg_bytes is now adjusted to be the size of the ciphertext
}
----------------------------------------------------------------
client --> server : PROOF (32 random-looking bytes) + first encrypted packet can be appended here
----------------------------------------------------------------
server_e.ValidateProof(proof, EasyHandshake::PROOF_BYTES);
----------------------------------------------------------------
Decryption example:
----------------------------------------------------------------
int buf_bytes = msg_bytes;
// The second parameter is the number of bytes in the encrypted message
if (server_e.Decrypt(message, buf_bytes))
{
// buf_bytes is now adjusted to be the size of the plaintext
}
----------------------------------------------------------------
During program termination, the client and server should clean up:
----------------------------------------------------------------
EasyHandshake::Shutdown();
----------------------------------------------------------------
NOTES:
Once the authenticated encryption objects are created, if the messages received are always
guaranteed to be in order, then the following flag can be set to make the object reject
packets received out of order, which would indicate tampering:
auth_enc.AllowOutOfOrder(false);
By default the messages are assumed to arrive in any order up to 1024 messages out of order.
The server similarly can encrypt messages the same way the client does in the examples.
Encrypted messages are inflated by 11 random-looking bytes for a MAC and an IV.
Modifications to the code can allow lower overhead if needed.
The EasyHandshake classes are *NOT* THREAD-SAFE.
The AuthenticatedEncryption class is *NOT* THREAD-SAFE. Simultaneously, only ONE thread
can be encrypting messages. And only ONE thread can be decrypting messages. Encryption
and decryption are separate and safe to perform simultaneously.
*/
/*
Common data needed for handshaking
*/
class CAT_EXPORT EasyHandshake
{
protected:
// Normally these would be created per-thread.
// To free memory associated with these objects just delete them.
BigTwistedEdwards *tls_math;
FortunaOutput *tls_csprng;
public:
static const int BITS = 256;
static const int BYTES = BITS / 8;
static const int PUBLIC_KEY_BYTES = BYTES * 2;
static const int PRIVATE_KEY_BYTES = BYTES;
static const int CHALLENGE_BYTES = BYTES * 2; // Packet # 1 in handshake, sent to server
static const int ANSWER_BYTES = BYTES * 4; // Packet # 2 in handshake, sent to client
static const int PROOF_BYTES = BYTES; // Packet # 3 in handshake, sent to server
static const int IDENTITY_BYTES = BYTES * 5; // [optional] Packet # 3 in handshake, sent to server, proves identity of client also
public:
// Demonstrates how to allocate and free the math and prng objects
EasyHandshake();
~EasyHandshake();
public:
static bool Initialize();
static void Shutdown();
public:
// Generate a server (public, private) key pair
// Connecting clients will need to know the public key in order to connect
bool GenerateServerKey(void *out_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */,
void *out_private_key /* EasyHandshake::PRIVATE_KEY_BYTES */);
// Fills the given buffer with a variable number of random bytes
// Returns false on failure
bool GenerateRandomNumber(void *out_num, int bytes);
};
/*
Implements the simple case of a server that performs handshakes with clients
from a single thread. Note that this implementation is not thread-safe.
*/
class CAT_EXPORT ServerEasyHandshake : public EasyHandshake
{
KeyAgreementResponder tun_server;
public:
ServerEasyHandshake();
~ServerEasyHandshake();
// Prepare a cookie jar for hungry consumers
void FillCookieJar(CookieJar *jar);
// Provide the public and private key for the server, previously generated offline
bool Initialize(const void *in_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */,
const void *in_private_key /* EasyHandshake::PRIVATE_KEY_BYTES */);
// Process a client challenge and generate a server answer
// Returns false if challenge was invalid
bool ProcessChallenge(const void *in_challenge /* EasyHandshake::CHALLENGE_BYTES */,
void *out_answer /* EasyHandshake::ANSWER_BYTES */,
AuthenticatedEncryption *auth_enc);
// Validate a client proof of identity
// Returns false if proof was invalid
bool VerifyInitiatorIdentity(const void *in_answer /* EasyHandshake::ANSWER_BYTES */,
const void *in_proof /* EasyHandshake::IDENTITY_BYTES */,
void *out_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */);
};
/*
Implements the simple case of a client that performs handshakes with servers
from a single thread. Note that this implementation is not thread-safe.
*/
class CAT_EXPORT ClientEasyHandshake : public EasyHandshake
{
KeyAgreementInitiator tun_client;
public:
ClientEasyHandshake();
~ClientEasyHandshake();
// Provide the public key for the server, acquired through some secure means
bool Initialize(const void *in_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */);
// (optional) Provide the identity for the client
bool SetIdentity(const void *in_public_key /* EasyHandshake::PUBLIC_KEY_BYTES */,
const void *in_private_key /* EasyHandshake::PRIVATE_KEY_BYTES */);
// Generate a challenge for the server to answer
bool GenerateChallenge(void *out_challenge /* EasyHandshake::CHALLENGE_BYTES */);
// Process a server answer to our challenge
// Returns false if answer was invalid
bool ProcessAnswer(const void *in_answer /* EasyHandshake::ANSWER_BYTES */,
AuthenticatedEncryption *auth_enc);
// Process a server answer to our challenge and provide a proof of client identity
// Returns false if answer was invalid
bool ProcessAnswerWithIdentity(const void *in_answer /* EasyHandshake::ANSWER_BYTES */,
void *out_identity /* EasyHandshake::IDENTITY_BYTES */,
AuthenticatedEncryption *auth_enc);
};
} // namespace cat
#endif // CAT_EASY_HANDSHAKE_HPP

View File

@ -0,0 +1,210 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_KEY_AGREEMENT_HPP
#define CAT_KEY_AGREEMENT_HPP
#include <cat/math/BigTwistedEdwards.hpp>
#include <cat/crypt/rand/Fortuna.hpp>
namespace cat {
/*
Tunnel Key Agreement "Tabby" protocol:
An unauthenticated Diffie-Hellman key agreement protocol with forward secrecy
Immune to active attacks (man-in-the-middle) if server key is known ahead of time
Using Elliptic Curve Cryptography over finite field Fp, p = 2^n - c, c small
Shape of curve: a' * x^2 + y^2 = 1 + d' * x^2 * y^2, a' = -1 (square in Fp)
d' (non square in Fp) -> order of curve = q * cofactor h, order of generator point = q
Curves satisfy MOV conditions and are not anomalous
Point operations performed with Extended Twisted Edwards group laws
See BigTwistedEdwards.hpp for more information
H: Skein-Key, either 256-bit or 512-bit based on security level
MAC: Skein-MAC, keyed from output of H()
Here the protocol initiator is the (c)lient, and the responder is the (s)erver:
s: long-term private key 1 < b < q, long-term public key B = b * G
256-bit security: B = 64 bytes for public key, b = 32 bytes for private key
384-bit security: B = 96 bytes for public key, b = 48 bytes for private key
512-bit security: B = 128 bytes for public key, b = 64 bytes for private key
c: Client already knows the server's public key B before Key Agreement
c: ephemeral private key 1 < a < q, ephemeral public key A = a * G
Initiator Challenge: c2s A
256-bit security: A = 64 bytes
384-bit security: A = 96 bytes
512-bit security: A = 128 bytes
s: validate A, ignore invalid
Invalid A(x,y) would be the additive identity x=0 or any point not on the curve
s: ephemeral private key 1 < y < q, ephemeral public key Y = y * G
Ephemeral key is re-used for several connections before being regenerated
s: hA = h * A
s: random n-bit number r
s: d = H(A,B,Y,r)
Repeat the previous two steps until d >= 1000
s: e = b + d*y (mod q)
s: T = AffineX(e * hA)
s: k = H(d,T)
Responder Answer: s2c Y || r || MAC(k) {"responder proof"}
256-bit security: Y(64by) r(32by) MAC(32by) = 128 bytes
384-bit security: Y(96by) r(48by) MAC(48by) = 192 bytes
512-bit security: Y(128by) r(64by) MAC(64by) = 256 bytes
c: validate Y, ignore invalid
Invalid Y(x,y) would be the additive identity x=0 or any point not on the curve
c: hY = h * Y
c: d = H(A,B,Y,r)
c: Verify d >= 1000
c: T = AffineX(a * hB + d*a * hY)
c: k = H(d,T)
c: validate MAC, ignore invalid
Initiator Proof: c2s MAC(k) {"initiator proof"}
This packet can also include the client's first encrypted message
256-bit security: MAC(32by) = 32 bytes
384-bit security: MAC(48by) = 48 bytes
512-bit security: MAC(64by) = 64 bytes
s: validate MAC, ignore invalid
Notes:
The strategy of this protocol is to perform two EC Diffie-Hellman exchanges,
one with the long-term server key and the second with an ephemeral key that
should be much harder to obtain by an attacker. The resulting two shared
secret points are added together into one point that is used for the key.
It is perfectly acceptable to re-use an ephemeral key for several runs of
the protocol. This means that most of the processing done by the server is
just one point multiplication.
*/
/*
Schnorr signatures:
For signing, the signer reuses its Key Agreement key pair (b,B)
H: Skein-Key, either 256-bit or 512-bit based on security level
To sign a message M, signer computes:
ephemeral secret random 1 < k < q, ephemeral point K = k * G
e = H(M || K)
s = k - b*e (mod q)
This process is repeated until e and s are non-zero
Signature: s2c e || s
256-bit security: e(32by) s(32by) = 64 bytes
384-bit security: e(48by) s(48by) = 96 bytes
512-bit security: e(64by) s(64by) = 128 bytes
To verify a signature:
Check e, s are in the range [1,q-1]
K' = s*G + e*B
e' = H(M || K')
The signature is verified if e == e'
Notes:
K ?= K'
= s*G + e*B
= (k - b*e)*G + e*(b*G)
= k*G - b*e*G + e*b*G
= K
*/
// If CAT_DETERMINISTIC_KEY_GENERATION is undefined, the time to generate a
// key is unbounded, but tends to be 1 try. I think this is a good thing
// because it randomizes the runtime and helps avoid timing attacks
//#define CAT_DETERMINISTIC_KEY_GENERATION
// If CAT_USER_ERROR_CHECKING is defined, the key agreement objects will
// check to make sure that the input parameters are all the right length
// and that the math and prng objects are not null
#define CAT_USER_ERROR_CHECKING
class CAT_EXPORT KeyAgreementCommon
{
public:
static BigTwistedEdwards *InstantiateMath(int bits);
// Math library register usage
static const int ECC_REG_OVERHEAD = 21;
// c: field prime modulus p = 2^bits - C, p = 5 mod 8 s.t. a=-1 is a square in Fp
// d: curve coefficient (yy-xx=1+Dxxyy), not a square in Fp
static const int EDWARD_C_256 = 435;
static const int EDWARD_D_256 = 31720;
static const int EDWARD_C_384 = 2147;
static const int EDWARD_D_384 = 13036;
static const int EDWARD_C_512 = 875;
static const int EDWARD_D_512 = 32;
// Limits on field prime
static const int MAX_BITS = 512;
static const int MAX_BYTES = MAX_BITS / 8;
static const int MAX_LEGS = MAX_BYTES / sizeof(Leg);
protected:
int KeyBits, KeyBytes, KeyLegs;
bool Initialize(int bits);
public:
// Generates an unbiased random key in the range 1 < key < q
void GenerateKey(BigTwistedEdwards *math, IRandom *prng, Leg *key);
};
} // namespace cat
#endif // CAT_KEY_AGREEMENT_HPP

View File

@ -0,0 +1,101 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_KEY_AGREEMENT_INITIATOR_HPP
#define CAT_KEY_AGREEMENT_INITIATOR_HPP
#include <cat/crypt/tunnel/KeyAgreement.hpp>
#include <cat/crypt/tunnel/AuthenticatedEncryption.hpp>
namespace cat {
class CAT_EXPORT KeyAgreementInitiator : public KeyAgreementCommon
{
Leg *B; // Responder's public key (pre-shared with initiator)
Leg *a; // Initiator's private key (kept secret)
Leg *A; // Initiator's public key (shared with responder in Challenge message)
Leg *hB; // h*B
Leg *G_MultPrecomp; // Precomputed table for multiplication
Leg *B_MultPrecomp; // Precomputed table for multiplication
Leg *Y_MultPrecomp; // Precomputed table for multiplication
Leg *A_neutral; // Endian-neutral A
Leg *B_neutral; // Endian-neutral B
// Identity data
Leg *I_private; // Initiator's identity private key
Leg *I_public; // Endian-neutral initiator's identity public key
bool AllocateMemory();
void FreeMemory();
public:
KeyAgreementInitiator();
~KeyAgreementInitiator();
bool Initialize(BigTwistedEdwards *math,
const u8 *responder_public_key, int public_bytes);
// Call after Initialize()
bool SetIdentity(BigTwistedEdwards *math,
const u8 *initiator_public_key, int public_bytes,
const u8 *initiator_private_key, int private_bytes);
public:
bool GenerateChallenge(BigTwistedEdwards *math, FortunaOutput *csprng,
u8 *initiator_challenge, int challenge_bytes);
bool ProcessAnswer(BigTwistedEdwards *math,
const u8 *responder_answer, int answer_bytes,
Skein *key_hash);
// Will fail if SetIdentity() has not been called
bool ProcessAnswerWithIdentity(BigTwistedEdwards *math, FortunaOutput *csprng,
const u8 *responder_answer, int answer_bytes,
Skein *key_hash,
u8 *identity_proof, int proof_bytes);
CAT_INLINE bool KeyEncryption(Skein *key_hash, AuthenticatedEncryption *auth_enc, const char *key_name)
{
return auth_enc->SetKey(KeyBytes, key_hash, true, key_name);
}
// Erase the private key after handshake completes
// Also done as this object is destroyed
void SecureErasePrivateKey();
public:
bool Verify(BigTwistedEdwards *math,
const u8 *message, int message_bytes,
const u8 *signature, int signature_bytes);
};
} // namespace cat
#endif // CAT_KEY_AGREEMENT_INITIATOR_HPP

View File

@ -0,0 +1,97 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_KEY_AGREEMENT_RESPONDER_HPP
#define CAT_KEY_AGREEMENT_RESPONDER_HPP
#include <cat/crypt/tunnel/KeyAgreement.hpp>
#include <cat/crypt/tunnel/AuthenticatedEncryption.hpp>
#include <cat/threads/Atomic.hpp>
#if defined(CAT_NO_ATOMIC_ADD) || defined(CAT_NO_ATOMIC_SET)
# include <cat/threads/Mutex.hpp>
# define CAT_NO_ATOMIC_RESPONDER
#endif
namespace cat {
class CAT_EXPORT KeyAgreementResponder : public KeyAgreementCommon
{
Leg *b; // Responder's private key (kept secret)
Leg *B; // Responder's public key (pre-shared with initiator)
Leg *B_neutral; // Endian-neutral B
Leg *G_MultPrecomp; // 8-bit table for multiplication
Leg *y[2]; // Responder's ephemeral private key (kept secret)
Leg *Y_neutral[2]; // Responder's ephemeral public key (shared online with initiator)
#if defined(CAT_NO_ATOMIC_RESPONDER)
Mutex m_thread_id_mutex;
#endif // CAT_NO_ATOMIC_RESPONDER
volatile u32 ChallengeCount;
volatile u32 ActiveY;
void Rekey(BigTwistedEdwards *math, FortunaOutput *csprng);
bool AllocateMemory();
void FreeMemory();
public:
KeyAgreementResponder();
~KeyAgreementResponder();
bool Initialize(BigTwistedEdwards *math, FortunaOutput *csprng,
const u8 *responder_public_key, int public_bytes,
const u8 *responder_private_key, int private_bytes);
public:
bool ProcessChallenge(BigTwistedEdwards *math, FortunaOutput *csprng,
const u8 *initiator_challenge, int challenge_bytes,
u8 *responder_answer, int answer_bytes, Skein *key_hash);
inline bool KeyEncryption(Skein *key_hash, AuthenticatedEncryption *auth_enc, const char *key_name)
{
return auth_enc->SetKey(KeyBytes, key_hash, false, key_name);
}
// Public key is filled if proof succeeds, and will return true
bool VerifyInitiatorIdentity(BigTwistedEdwards *math,
const u8 *responder_answer, int answer_bytes,
const u8 *proof, int proof_bytes,
u8 *public_key, int public_bytes);
public:
bool Sign(BigTwistedEdwards *math, FortunaOutput *csprng,
const u8 *message, int message_bytes,
u8 *signature, int signature_bytes);
};
} // namespace cat
#endif // CAT_KEY_AGREEMENT_RESPONDER_HPP

View File

@ -0,0 +1,47 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_KEY_MAKER_HPP
#define CAT_KEY_MAKER_HPP
#include <cat/crypt/tunnel/KeyAgreement.hpp>
#include <cat/crypt/rand/Fortuna.hpp>
namespace cat {
class KeyMaker : public KeyAgreementCommon
{
public:
bool GenerateKeyPair(BigTwistedEdwards *math, FortunaOutput *csprng, u8 *public_key, int public_bytes, u8 *private_key, int private_bytes);
};
} // namespace cat
#endif // CAT_KEY_MAKER_HPP

View File

@ -0,0 +1,171 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_BOMBAY_TABLE_HPP
#define CAT_BOMBAY_TABLE_HPP
#include <cat/threads/RWLock.hpp>
#include <cat/io/ThreadPoolFiles.hpp>
#include <cat/db/BombayTableIndex.hpp>
namespace cat {
namespace bombay {
static u64 INVALID_RECORD_OFFSET = ~(u64)0;
struct CacheNode
{
CacheNode *parent, *lower, *higher;
u64 offset;
};
class TableIndex;
class IHash;
// Query() AsyncBuffer tag must derive from AsyncQueryRead
struct AsyncQueryRead
{
ThreadRefObject *_reference;
AsyncCallback _callback;
CAT_INLINE void SetCallback(AsyncCallback callback = 0, ThreadRefObject *reference = 0)
{
if (reference)
reference->AddRef();
_callback = callback;
_reference = reference;
}
};
///// Table
class Table : public AsyncFile
{
ShutdownObserver *_shutdown_observer;
u32 _record_bytes; // Bytes per record (without CacheNode overhead)
u64 _next_record; // Next record offset
protected:
RWLock _lock;
u64 _index_database_size, _index_read_offset, _index_read_completed;
u32 _index_read_size;
static const u32 MAX_INDEX_READ_SIZE = 32768;
static const int NUM_PARALLEL_INDEX_READS = 3;
// Cache hash table of binary trees
static const u32 TARGET_TREE_SIZE = 16;
static const u32 MIN_TABLE_SIZE = 2048;
u32 _hash_table_size;
CacheNode **_cache_hash_table;
u8 *_cache; // Cache memory
u32 _cache_bytes; // Cache bytes
u32 _next_cache_slot; // Offset in cache memory to next free slot
bool _cache_full; // Cache full flag for optimization
TableIndex *_head_index, *_head_index_unique;
TableIndex *_head_index_waiting, *_head_index_update;
bool AllocateCache();
void FreeCache();
// Node versions
CacheNode *FindNode(u64 offset);
void UnlinkNode(CacheNode *node);
void InsertNode(u64 offset, u32 key, CacheNode *hint, CacheNode *node);
// Always returns with a cache node; may re-use an old cache node
u8 *SetOffset(u64 offset);
u8 *InsertOffset(u64 offset);
u8 *PeekOffset(u64 offset);
bool RemoveOffset(u64 offset);
public:
Table(const char *file_path, u32 record_bytes, u32 cache_bytes, ShutdownObserver *shutdown_observer);
virtual ~Table();
private:
TableIndex *MakeIndex(const char *index_file_path, IHash *hash_function, bool unique);
u64 UniqueIndexLookup(const void *data);
public:
// To initialize, run MakeIndex() for all of the desired indexing routines,
// and then run Initialize(), which will initialize index objects.
template<class THashFunc> CAT_INLINE TableIndex *MakeIndex(const char *index_file_path, bool unique)
{
return MakeIndex(index_file_path, new THashFunc, unique);
}
bool Initialize();
public:
CAT_INLINE u32 GetCacheBytes() { return _cache_bytes; }
CAT_INLINE u32 GetRecordBytes() { return _record_bytes; }
protected:
virtual bool OnRemoveRead(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
virtual bool OnQueryRead(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
protected:
bool StartIndexing();
bool StartIndexingRead();
void OnIndexingDone();
virtual bool OnIndexingRead(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
public:
bool RequestIndexRebuild(TableIndex *index);
public:
// Insert an AsyncBuffer data buffer
u64 Insert(void *data);
// Update with an AsyncBuffer data buffer
bool Update(void *data, u64 offset);
// Query with an AsyncBuffer
// NOTE: Query() AsyncBuffer tag must derive from AsyncQueryRead
bool Query(u64 offset, AsyncBuffer *buffer);
// Remove based on offset
bool Remove(u64 offset);
};
} // namespace bombay
} // namespace cat
#endif // CAT_BOMBAY_TABLE_HPP

View File

@ -0,0 +1,231 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_BOMBAY_TABLE_INDEX_HPP
#define CAT_BOMBAY_TABLE_INDEX_HPP
#include <cat/db/BombayTable.hpp>
namespace cat {
namespace bombay {
/*
Returning 0 from one of these hash functions will cause insertion or lookup to fail,
which is how invalid input is intended to be handled.
*/
class IHash
{
public:
virtual u64 HashField(const void *just_field) = 0;
virtual u64 HashComplete(const void *complete_record) = 0;
virtual u64 HashVarField(const void *just_field, u32 bytes) { return HashField(just_field); }
};
#define DECL_BOMBAY_SCHEMA_VAR_FIELD_HASH(T) \
class T : public bombay::IHash \
{ \
public: \
u64 HashField(const void *just_field); \
u64 HashComplete(const void *complete_record); \
u64 HashVarField(const void *just_field, u32 bytes); \
};
#define DECL_BOMBAY_SCHEMA_FIXED_FIELD_HASH(T) \
class T : public bombay::IHash \
{ \
public: \
u64 HashField(const void *just_field); \
u64 HashComplete(const void *complete_record); \
};
/*
Table index must present a complete index of the contents of a Table.
The index uses some region of bytes in each entry as a key to find
the entry given just that set of bytes. For example, mapping a user
name to a database node.
The table index should be loaded from disk on startup. If this is
not possible, then an index rebuild will need to be done on startup.
Hash table size will be at least twice as large as the number of
database entries, growing as needed.
To avoid a lot of expensive setup, each element is arranged like this:
<-- MSB LSB -->
C(1 bit) || OFFSET+1 (63 bits)
HASH(64 bits)
C: Collision flag
0 = No collision
1 = Collision, actual data may be stored at next walk location
OFFSET+1: Database file offset for this entry that contains the
full unique identifier. One(1) is added to the offset in
the memory representation of the index table element, so that
OFFSET = ~0 will be set by zeroing out the table.
0 = No data at this table element.
Other values = Valid offset+1
HASH: 64-bit full hash
Only low bits are used for table lookup, so hash does not need
to be recomputed if the table grows and lookup of something that
is not in the table does not have collisions half the time.
The whole structure fits in one cache line on an x86 server.
*/
class Table;
class TableIndex : public AsyncFile
{
friend class Table;
ShutdownObserver *_shutdown_observer;
Table *_parent;
IHash *_index_hash;
TableIndex *_next, *_next_unique, *_next_loading;
protected:
// (multiplier-1) divisible by all prime factors of table size
// (multiplier-1) is a multiple of 4 if table size is a multiple of 4
// Increment is relatively prime to the table size.
static const u32 COLLISION_MULTIPLIER = 71*7487 * 4 + 1;
static const u32 COLLISION_INCREMENTER = 1017234223;
static const u64 OFFSET_MASK = (~(u64)0) >> 1;
static const u64 COLLIDE_MASK = ~OFFSET_MASK;
static const u32 MIN_ELEMENTS = 1024;
static const u32 TABLE_FOOTER_BYTES = 16;
static const u64 TABLE_CHECK_HASH_SALT = 0x74B1301234DEADBE;
RWLock _lock;
u64 *_table;
u32 _table_raw_bytes;
u32 _table_elements; // A power of 2; just subtract 1 to make a mask
u32 _used_elements;
char _file_path[MAX_PATH+1];
bool AllocateTable();
bool DoubleTable();
void FreeTable();
protected:
void Save();
public:
TableIndex(Table *parent, const char *index_file_path,
IHash *hash_function, ShutdownObserver *shutdown_observer);
~TableIndex();
bool Initialize();
protected:
virtual bool OnRead(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
public:
CAT_INLINE const char *GetFilePath() { return _file_path; }
public:
CAT_INLINE u64 VarField(const void *data, u32 bytes)
{
return _index_hash->HashVarField(data, bytes);
}
CAT_INLINE u64 Field(const void *data)
{
return _index_hash->HashField(data);
}
CAT_INLINE u64 Complete(const void *data)
{
return _index_hash->HashComplete(data);
}
public:
// Hash value of 0 will be ignored
u64 Lookup(u64 hash);
void Insert(u64 hash, u64 offset);
void Remove(u64 hash);
public:
CAT_INLINE u64 LookupVarField(const void *data, u32 bytes)
{
return Lookup(_index_hash->HashVarField(data, bytes));
}
CAT_INLINE u64 LookupField(const void *data)
{
return Lookup(_index_hash->HashField(data));
}
CAT_INLINE u64 LookupComplete(const void *data)
{
return Lookup(_index_hash->HashComplete(data));
}
public:
CAT_INLINE void InsertVarField(const void *data, u32 bytes, u64 offset)
{
Insert(_index_hash->HashVarField(data, bytes), offset);
}
CAT_INLINE void InsertField(const void *data, u64 offset)
{
Insert(_index_hash->HashField(data), offset);
}
CAT_INLINE void InsertComplete(const void *data, u64 offset)
{
Insert(_index_hash->HashComplete(data), offset);
}
public:
CAT_INLINE void RemoveVarField(const void *data, u32 bytes)
{
Remove(_index_hash->HashVarField(data, bytes));
}
CAT_INLINE void RemoveField(const void *data)
{
Remove(_index_hash->HashField(data));
}
CAT_INLINE void RemoveComplete(const void *data)
{
Remove(_index_hash->HashComplete(data));
}
};
} // namespace bombay
} // namespace cat
#endif // CAT_BOMBAY_TABLE_INDEX_HPP

View File

@ -0,0 +1,76 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LOAD_BITMAP_HPP
#define LOAD_BITMAP_HPP
#include <cat/Platform.hpp>
namespace cat {
/*
LoadBitmap() loads a memory-mapped bitmap or a file from disk into RGBA format,
meaning the first byte of every pixel is Red, then Green, Blue, and Alpha.
The output data is useful for creating an OpenGL texture using GL_RGBA format.
The output width and height will be powers of two.
Parameters:
file, bytes : Memory-mapped file pointer and number of bytes in the file
path : Alternatively, the path to the file to load
width, height : The dimensions of the loaded file, in pixels
Returns: Zero on error, or a pointer to the rasterized RGBA pixels.
Free the allocated memory using Aligned::Delete(a);
*/
void *LoadBitmap(void *file, u32 bytes, u32 &width, u32 &height);
void *LoadBitmap(const char *path, u32 &width, u32 &height);
class BMPTokenizer
{
u8 trans_red, trans_green, trans_blue;
bool requirePOTS; // Require Power-of-Two Size
void rasterizeImage(u8 *image);
void onImage(u32 *image, u32 newWidth, u32 newHeight);
public:
BMPTokenizer();
~BMPTokenizer();
public:
bool LoadFile(const char *path);
};
} // namespace cat
#endif // LOAD_BITMAP_HPP

View File

@ -0,0 +1,162 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LOAD_PNG_HPP
#define LOAD_PNG_HPP
#include <cat/AllFramework.hpp>
#include <string>
using namespace std;
#include "zlib-1.2.4/zlib.h"
namespace cat {
#include "CRC32.hpp"
#ifdef CAT_PRAGMA_PACK
#pragma pack(push)
#pragma pack(1)
#endif
typedef struct
{
u32 length;
char type[4];
} CAT_PACKED SectionHeader;
typedef struct
{
u32 length;
char type[4];
u32 crc;
} CAT_PACKED EmptySection;
typedef struct
{
u32 width, height;
u8 bitDepth, colorType, compressionMethod, filterMethod, interlaceMethod;
} CAT_PACKED PNG_IHDR;
typedef struct
{
u8 r, g, b;
} CAT_PACKED PLTE_Entry8;
typedef struct
{
PLTE_Entry8 table[256];
} CAT_PACKED PNG_PLTE;
#ifdef CAT_PRAGMA_PACK
#pragma pack(pop)
#endif
class PNGSkeletonTokenizer
{
protected:
MMapFile mmf;
CRC32Calculator calculator;
string path;
// Split this from the ctor, so virtual overloads are in place by the time we start reading
bool read(const u8 signature[8]); // Returns false on failure
public:
PNGSkeletonTokenizer(const string &path, u32 CRC32polynomial);
virtual ~PNGSkeletonTokenizer() {}
protected:
// return true only if section is valid (no exceptions please)
virtual bool onSection(char type[4], u8 data[], u32 len) = 0;
};
class PNGTokenizer : public PNGSkeletonTokenizer
{
protected:
z_stream zstream;
u8 *obuf;
u32 olen;
int lastZlibResult;
bool requirePOTS;
PNG_IHDR header;
u16 bpp;
u32 palette[256];
u8 trans_red, trans_green, trans_blue;
void rasterizeImage(u8 *image);
public:
PNGTokenizer(const string &path, bool requirePOTS);
virtual ~PNGTokenizer();
protected:
bool onSection(char type[4], u8 data[], u32 len);
protected:
// Rasterized image in R8G8B8A8 format, new dimensions are powers of two
virtual void onImage(u32 *image, u32 newWidth, u32 newHeight);
protected:
// Important sections
void onIHDR(PNG_IHDR *infohdr);
void onPLTE(PNG_PLTE *c_palette);
void onIDAT(u8 *data, u32 len);
void onIEND();
// Transparency info
void onTRNS_Color2(u16 red, u16 green, u16 blue);
void onTRNS_Color3(u8 trans[256], u16 len);
// Color space information (all unimplemented)
void onGAMA();
void onCHRM();
void onSRGB();
void onICCP();
// Textual information (all unimplemented)
void onTEXT();
void onZTXT();
void onITXT();
// Other non-essential info (all unimplemented)
void onBKGD();
void onPHYS();
void onSBIT();
void onSPLT();
void onHIST();
void onTIME();
};
} // namespace cat
#endif // LOAD_PNG_HPP

View File

@ -0,0 +1,186 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_MATRIX_HPP
#define CAT_MATRIX_HPP
#include <cat/gfx/Vector.hpp>
namespace cat {
#define FOR_EACH_ELEMENT(index) for (int index = 0; index < ELEMENTS; ++index)
/*
4x4 matrix elements arranged column major (row, column):
m[0] m[4] m[8] m[12]
m[1] m[5] m[9] m[13]
m[2] m[6] m[10] m[14]
m[3] m[7] m[11] m[15]
Matrix element order corresponds to OpenGL matrix ordering s.t. in a
4x4 matrix the elements define the following new coordinate system:
new x-axis vector: { m[0] m[1] m[2] }
new y-axis vector: { m[4] m[5] m[6] }
new z-axis vector: { m[7] m[9] m[10] }
new origin: { m[12] m[13] m[14] }
*/
template<int ROWS, int COLS, class Scalar> class Matrix
{
protected:
static const int ELEMENTS = ROWS * COLS;
Scalar _elements[ROWS * COLS];
public:
// Short-hand for the current matrix type
typedef Matrix<ROWS, COLS, Scalar> mytype;
// Default constructor does not initialize elements
Matrix()
{
}
// Copy constructor
Matrix(const mytype &u)
{
memcpy(_elements, u._elements, sizeof(_elements));
}
// Assignment operator
mytype &operator=(const mytype &u)
{
memcpy(_elements, u._elements, sizeof(_elements));
}
// Load zero matrix
void loadZero()
{
OBJCLR(_elements);
}
// Load identity matrix
void loadIdentity()
{
OBJCLR(_elements);
// Write a 1 along the diagonal
for (int ii = 0; ii < ROWS && ii < COLS; ++ii)
{
_elements[ii * ROWS + ii] = static_cast<Scalar>( 1 );
}
}
// Addition in-place
mytype &operator+=(const mytype &u)
{
FOR_EACH_ELEMENT(ii) _elements[ii] += u._elements[ii];
}
// Subtraction in-place
mytype &operator-=(const mytype &u)
{
FOR_EACH_ELEMENT(ii) _elements[ii] -= u._elements[ii];
}
// Multiplication by scalar in-place
mytype &operator*=(Scalar u)
{
FOR_EACH_ELEMENT(ii) _elements[ii] *= u;
}
// Division by scalar in-place
mytype &operator/=(Scalar u)
{
FOR_EACH_ELEMENT(ii) _elements[ii] /= u;
}
// Matrix multiplication
template<int OTHER_COLS>
Matrix<ROWS, OTHER_COLS, Scalar> operator*(const Matrix<COLS, OTHER_COLS, Scalar> &u)
{
Matrix<ROWS, OTHER_COLS, Scalar> result;
// For each row of the matrix product,
for (int r = 0; r < ROWS; ++r)
{
// For each column of the matrix product,
for (int c = 0; c < OTHER_COLS; ++c)
{
Scalar x = static_cast<Scalar>( 0 );
// For each row of the right operand (u),
for (int ii = 0; ii < COLS; ++ii)
{
// Accumulate sum of products
x += (*this)(r, ii) * u(ii, c);
}
// Write the sum
result(r, c) = x;
}
}
return result;
}
// Accessors
inline Scalar &operator()(int ii) { return _elements[ii]; }
inline const Scalar &operator()(int ii) const { return _elements[ii]; }
inline Scalar &operator()(int row, int col) { return _elements[col * ROWS + row]; }
inline const Scalar &operator()(int row, int col) const { return _elements[col * ROWS + row]; }
};
// Short-hand for common usages:
typedef Matrix<2, 2, u32> Matrix2x2u;
typedef Matrix<3, 3, u32> Matrix3x3u;
typedef Matrix<4, 4, u32> Matrix4x4u;
typedef Matrix<2, 2, s32> Matrix2x2i;
typedef Matrix<3, 3, s32> Matrix3x3i;
typedef Matrix<4, 4, s32> Matrix4x4i;
typedef Matrix<2, 2, f32> Matrix2x2f;
typedef Matrix<3, 3, f32> Matrix3x3f;
typedef Matrix<4, 4, f32> Matrix4x4f;
typedef Matrix<2, 2, f64> Matrix2x2d;
typedef Matrix<3, 3, f64> Matrix3x3d;
typedef Matrix<4, 4, f64> Matrix4x4d;
#undef FOR_EACH_ELEMENT
} // namespace cat
#endif // CAT_MATRIX_HPP

View File

@ -0,0 +1,401 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Based on code from "Physics for Game Developers", David M. Bourg
slerp() code adapted from this website:
http://www.number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/index.html
*/
#ifndef CAT_QUATERNION_HPP
#define CAT_QUATERNION_HPP
#include <cat/gfx/Vector.hpp>
#include <cat/gfx/Matrix.hpp>
namespace cat {
// Generic quaternion class for linear algebra
template <typename Scalar, typename Double>
class Quaternion
{
protected:
// Backed by a 4D vector with elements arranged as <x,y,z,w>
Vector<4, Scalar, Double> _v;
public:
// Short-hand for the current quaternion type
typedef Quaternion<Scalar, Double> mytype;
// Short-hand for the vector type
typedef Vector<3, Scalar, Double> vectype;
// Uninitialized quaternion is not cleared
Quaternion() { }
// Copy constructor
Quaternion(const mytype &u)
: _v(u._v)
{
}
// Initialization constructor
Quaternion(const vectype &v, Scalar w)
: _v(v)
{
}
// Initialization constructor
Quaternion(Scalar x, Scalar y, Scalar z, Scalar w)
: _v(x, y, z, w)
{
}
// Assignment operator
mytype &operator=(const mytype &u)
{
_v.copy(u._v);
return *this;
}
// Convert from Euler angle representation
// Pre-condition: angles in radians (see Deg2Rad in Scalar.hpp)
void setFromEulerAngles(f32 xroll, f32 ypitch, f32 zyaw)
{
f64 croll = cos(0.5f * xroll);
f64 cpitch = cos(0.5f * ypitch);
f64 cyaw = cos(0.5f * zyaw);
f64 sroll = sin(0.5f * xroll);
f64 spitch = sin(0.5f * ypitch);
f64 syaw = sin(0.5f * zyaw);
f64 cyawcpitch = cyaw * cpitch;
f64 syawspitch = syaw * spitch;
f64 cyawspitch = cyaw * spitch;
f64 syawcpitch = syaw * cpitch;
_v(0) = static_cast<Scalar>( cyawcpitch * sroll - syawspitch * croll );
_v(1) = static_cast<Scalar>( cyawspitch * croll + syawcpitch * sroll );
_v(2) = static_cast<Scalar>( syawcpitch * croll - cyawspitch * sroll );
_v(3) = static_cast<Scalar>( cyawcpitch * croll + syawspitch * sroll );
_v.normalize();
}
// Convert from axis-angle representation
// Pre-condition: axis must be unit-length
void setFromAxisAngle(const vectype &axis, f32 angle)
{
angle *= 0.5f;
Scalar theta = static_cast<Scalar>( sin(angle) );
_v(0) = theta * axis(0);
_v(1) = theta * axis(1);
_v(2) = theta * axis(2);
_v(3) = static_cast<Scalar>( cos(angle) );
}
// Conjugate
mytype operator~() const
{
return mytype(-_v(0), -_v(1), -_v(2), _v(3));
}
// Conjugate in-place
mytype &conjugate() const
{
_v(0) = -_v(0);
_v(1) = -_v(1);
_v(2) = -_v(2);
return *this;
}
// Multiply by quaternion
mytype operator*(const mytype &u)
{
// Cache each of the elements since each is used 4 times
Double x1 = _v(0), x2 = u._v(0);
Double y1 = _v(1), y2 = u._v(1);
Double z1 = _v(2), z2 = u._v(2);
Double w1 = _v(3), w2 = u._v(3);
// Quaternion multiplication formula:
Scalar x3 = static_cast<Scalar>( w1*x2 + x1*w2 + y1*z2 - z1*y2 );
Scalar y3 = static_cast<Scalar>( w1*y2 - x1*z2 + y1*w2 + z1*x2 );
Scalar z3 = static_cast<Scalar>( w1*z2 + x1*y2 - y1*x2 + z1*w2 );
Scalar w3 = static_cast<Scalar>( w1*w2 - x1*x2 - y1*y2 - z1*z2 );
return mytype(x3, y3, z3, w3);
}
// Multiply by quaternion in-place: this = this * u
mytype &operator*=(const mytype &u)
{
// Cache each of the elements since each is used 4 times
Double x1 = _v(0), x2 = u._v(0);
Double y1 = _v(1), y2 = u._v(1);
Double z1 = _v(2), z2 = u._v(2);
Double w1 = _v(3), w2 = u._v(3);
// Quaternion multiplication formula:
_v(0) = static_cast<Scalar>( w1*x2 + x1*w2 + y1*z2 - z1*y2 );
_v(1) = static_cast<Scalar>( w1*y2 - x1*z2 + y1*w2 + z1*x2 );
_v(2) = static_cast<Scalar>( w1*z2 + x1*y2 - y1*x2 + z1*w2 );
_v(3) = static_cast<Scalar>( w1*w2 - x1*x2 - y1*y2 - z1*z2 );
return *this;
}
// Multiply by quaternion in-place: this = u * this
mytype &postMultiply(const mytype &u)
{
// Cache each of the elements since each is used 4 times
Double x2 = _v(0), x1 = u._v(0);
Double y2 = _v(1), y1 = u._v(1);
Double z2 = _v(2), z1 = u._v(2);
Double w2 = _v(3), w1 = u._v(3);
// Quaternion multiplication formula:
_v(0) = static_cast<Scalar>( w1*x2 + x1*w2 + y1*z2 - z1*y2 );
_v(1) = static_cast<Scalar>( w1*y2 - x1*z2 + y1*w2 + z1*x2 );
_v(2) = static_cast<Scalar>( w1*z2 + x1*y2 - y1*x2 + z1*w2 );
_v(3) = static_cast<Scalar>( w1*w2 - x1*x2 - y1*y2 - z1*z2 );
return *this;
}
// Rotate given vector in-place
void rotate(vectype &u)
{
// Implements the simple formula: (q1 * u2 * ~q1).getVector()
// Cache each of the elements since each is used 4 times
Double x1 = _v(0), x2 = u(0);
Double y1 = _v(1), y2 = u(1);
Double z1 = _v(2), z2 = u(2);
Double w1 = _v(3);
// Quaternion-vector multiplication formula (q3 = q1 * u2):
Double x3 = w1*x2 + y1*z2 - z1*y2;
Double y3 = w1*y2 - x1*z2 + z1*x2;
Double z3 = w1*z2 + x1*y2 - y1*x2;
Double w3 = -(x1*x2 + y1*y2 + z1*z2);
// Quaternion multiplication formula (q2' = q3 * ~q1):
u(0) = static_cast<Scalar>( w1*x3 - x1*w3 + y1*z3 - z1*y3 );
u(1) = static_cast<Scalar>( w1*y3 - x1*z3 - y1*w3 + z1*x3 );
u(2) = static_cast<Scalar>( w1*z3 + x1*y3 - y1*x3 - z1*w3 );
}
// NLERP: Very fast, non-constant velocity and torque-minimal
// Precondition: q1, q2 are unit length
friend void nlerp(const mytype &q1, const mytype &q2, Scalar t, mytype &result)
{
// Linearly interpolate and normalize result
// This formula is a little more work than "q1 + (q2 - q1) * t"
// but less likely to lose precision when it matters
// Cosine of phi, the angle between the two vectors
Double cos_phi = q1._v.dotProduct(q2._v);
// I have read this may try to rotate around the "long way" sometimes and to
// fix that we check if cos(phi) is negative and invert one of the inputs.
if (cos_phi < 0.0)
{
result._v = -q1._v;
}
else
{
result._v = q1._v;
}
// Simple linear interpolation
Scalar scale0 = static_cast<Scalar>(1) - t;
Scalar scale1 = t;
result._v *= scale0;
result._v += q2._v * scale1;
result._v.normalize();
}
// SLERP: Slower, constant velocity and torque-minimal
// Precondition: q1, q2 are unit length
friend void slerp(const mytype &q1, const mytype &q2, Scalar t, mytype &result)
{
// Cosine of phi, the angle between the two vectors
Double cos_phi = q1._v.dotProduct(q2._v);
// I have read this may try to rotate around the "long way" sometimes and to
// fix that we check if cos(phi) is negative and invert one of the inputs.
if (cos_phi < 0.0)
{
cos_phi = -cos_phi;
result._v = -q1._v;
}
else
{
result._v = q1._v;
}
// Default to simple linear interpolation
Scalar scale0 = static_cast<Scalar>(1) - t;
Scalar scale1 = t;
// If the distance is not small we need to do full slerp:
if (cos_phi < 0.9995)
{
// cos_phi is guaranteed to be within the domain of acos(), 0..1
Double phi = static_cast<Double>( acos(cos_phi) );
Double inv_sin_phi = static_cast<Double>(1) / sin(phi);
scale0 = static_cast<Scalar>( sin(scale0 * phi) * inv_sin_phi );
scale1 = static_cast<Scalar>( sin(scale1 * phi) * inv_sin_phi );
}
result._v *= scale0;
result._v += q2._v * scale1;
result._v.normalize();
}
// Get angle of rotation
Scalar getAngle()
{
return static_cast<Scalar>( 2 ) * static_cast<Scalar>( acos(_v(3)) );
}
// Get axis of rotation
vectype getAxis()
{
return vectype(_v(0), _v(1), _v(2)).normalize();
}
// Get matrix form of the rotation represented by this quaternion
void getMatrix4x4(Matrix<4, 4, Scalar> &result)
{
Double dx = _v(0);
Double dy = _v(1);
Double dz = _v(2);
Double dw = _v(3);
Double x2 = dx * dx;
Double y2 = dy * dy;
Double z2 = dz * dz;
Double xy = dx * dy;
Double yz = dy * dz;
Double zx = dz * dx;
Double xw = dx * dw;
Double yw = dy * dw;
Double zw = dz * dw;
const Double ONE = static_cast<Double>( 1 );
const Double TWO = static_cast<Double>( 2 );
// Result is written in OpenGL column-major matrix order:
result( 0) = static_cast<Scalar>( ONE - TWO * (y2 + z2) );
result( 1) = static_cast<Scalar>( TWO * (xy - zw) );
result( 2) = static_cast<Scalar>( TWO * (zx + yw) );
result( 3) = static_cast<Scalar>( 0 );
result( 4) = static_cast<Scalar>( TWO * (xy + zw) );
result( 5) = static_cast<Scalar>( ONE - TWO * (x2 + z2) );
result( 6) = static_cast<Scalar>( TWO * (yz - xw) );
result( 7) = static_cast<Scalar>( 0 );
result( 8) = static_cast<Scalar>( TWO * (zx - yw) );
result( 9) = static_cast<Scalar>( TWO * (yz + xw) );
result(10) = static_cast<Scalar>( ONE - TWO * (x2 + y2) );
result(11) = static_cast<Scalar>( 0 );
result(12) = static_cast<Scalar>( 0 );
result(13) = static_cast<Scalar>( 0 );
result(14) = static_cast<Scalar>( 0 );
result(15) = static_cast<Scalar>( ONE );
}
// Get Euler angles
vectype Quaternion::getEulerAngles()
{
Double dx = _v(0);
Double dy = _v(1);
Double dz = _v(2);
Double dw = _v(3);
Double x2 = dx * dx;
Double y2 = dy * dy;
Double z2 = dz * dz;
Double w2 = dw * dw;
Double xy = dx * dy;
Double yz = dy * dz;
Double xw = dx * dw;
Double yw = dy * dw;
Double zw = dz * dw;
const Double TWO = static_cast<Double>( 2 );
Double r11 = w2 + x2 - y2 - z2;
Double r21 = TWO * (xy + zw);
Double r31 = TWO * (xy - yw);
Double r32 = TWO * (yz + xw);
Double r33 = w2 - x2 - y2 + z2;
Double tmp = fabs(r31);
const Double LIMIT = static_cast<Double>( 0.999999 );
if (tmp > LIMIT)
{
Double xz = dx * dz;
Double r12 = TWO * (yz - zw);
Double r13 = TWO * (xz + yw);
return vectype(static_cast<Scalar>( 0 ),
static_cast<Scalar>( -CAT_HALF_PI_64 * r31 / tmp ),
static_cast<Scalar>( atan2(-r12, -r31 * r13) ));
}
return vectype(static_cast<Scalar>( atan2(r32, r33) ),
static_cast<Scalar>( asin(-r31) ),
static_cast<Scalar>( atan2(r21, r11) ));
}
};
// Short-hand for common usages:
typedef Quaternion<f32, f64> Quaternion4f;
typedef Quaternion<f64, f64> Quaternion4d;
} // namespace cat
#endif // CAT_QUATERNION_HPP

View File

@ -0,0 +1,85 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_SCALAR_HPP
#define CAT_SCALAR_HPP
#include <cat/Platform.hpp>
#include <cmath>
namespace cat {
// PI
#define CAT_TWO_PI_64 6.283185307179586476925286766559
#define CAT_TWO_PI_32 6.28318531f
#define CAT_PI_64 3.1415926535897932384626433832795
#define CAT_PI_32 3.14159265f
#define CAT_HALF_PI_64 1.5707963267948966192313216916398
#define CAT_HALF_PI_32 1.5707963268f
#define CAT_QUARTER_PI_64 0.78539816339744830961566084581988
#define CAT_QUARTER_PI_32 0.7853981634f
#define CAT_INV_PI_64 0.31830988618379067153776752674503
#define CAT_INV_PI_32 0.3183098862f
// Angle conversion
inline f64 Deg2Rad(f64 angle)
{
return angle * CAT_TWO_PI_64 / 360.0;
}
inline f32 Deg2Rad(f32 angle)
{
return angle * CAT_TWO_PI_32 / 360.0f;
}
inline f64 Rad2Deg(f64 angle)
{
return angle * 360.0 / CAT_TWO_PI_64;
}
inline f32 Rad2Deg(f32 angle)
{
return angle * 360.0f / CAT_TWO_PI_32;
}
// Generic clamp() function
template<class Scalar>
void Clamp(Scalar &x, Scalar low, Scalar high)
{
if (x < low) x = low;
else if (x > high) x = high;
}
// Fast inverse square root
f32 InvSqrt(f32 x);
} // namespace cat
#endif // CAT_SCALAR_HPP

View File

@ -0,0 +1,389 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_VECTOR_HPP
#define CAT_VECTOR_HPP
#include <cat/gfx/Scalar.hpp>
namespace cat {
#define FOR_EACH_DIMENSION(index) for (int index = 0; index < DIM; ++index)
// Generic vector class for linear algebra
template<int DIM, typename Scalar, typename Double> class Vector
{
protected:
// Protected internal storage of vector components
Scalar _elements[DIM];
public:
// Short-hand for the current vector type
typedef Vector<DIM, Scalar, Double> mytype;
// Uninitialized vector is not cleared
Vector() {}
// Component-wise initializing constructors
Vector(Scalar x, Scalar y)
{
_elements[0] = x;
_elements[1] = y;
}
Vector(Scalar x, Scalar y, Scalar z)
{
_elements[0] = x;
_elements[1] = y;
_elements[2] = z;
}
Vector(Scalar x, Scalar y, Scalar z, Scalar w)
{
_elements[0] = x;
_elements[1] = y;
_elements[2] = z;
_elements[3] = w;
}
// Make the vector a copy of a given vector
mytype &copy(const mytype &u)
{
memcpy(_elements, u._elements, sizeof(_elements));
return *this;
}
// Copy constructor
Vector(const mytype &u)
{
copy(u);
}
// Assignment operator
mytype &operator=(const mytype &u)
{
return copy(u);
}
// Magnitude calculation
Double magnitude() const
{
Double element, sum = 0;
FOR_EACH_DIMENSION(ii)
{
element = _elements[ii];
sum += element * element;
}
return static_cast<Double>( sqrt(sum) );
}
// Fast normalization for 32-bit floating point elements in-place
mytype &normalize_fast_f32()
{
f32 element = _elements[0];
f32 sum = element * element;
for (int ii = 1; ii < DIM; ++ii)
{
element = _elements[ii];
sum += element * element;
}
// If sum is not close to 1, then perform normalization:
if (sum > 1.005f || sum < 0.995f)
{
f32 inv = InvSqrt(sum);
FOR_EACH_DIMENSION(ii) _elements[ii] *= inv;
}
return *this;
}
// Normalization in-place
mytype &normalize()
{
Double m = magnitude();
Double inv = static_cast<Double>( 1 ) / m;
FOR_EACH_DIMENSION(ii) _elements[ii] *= inv;
return *this;
}
// Zero elements
void zero()
{
OBJCLR(_elements);
}
// Is zero?
bool isZero()
{
FOR_EACH_DIMENSION(ii)
if (_elements[ii] != static_cast<Scalar>( 0 ))
return false;
return true;
}
// For consistency with Matrix class, use the () operator instead of [] to index it
inline Scalar &operator()(int ii) { return _elements[ii]; }
inline Scalar &x() { return _elements[0]; }
inline Scalar &y() { return _elements[1]; }
inline Scalar &z() { return _elements[2]; }
inline Scalar &w() { return _elements[3]; }
// Const version for accessors
inline const Scalar &operator()(int ii) const { return _elements[ii]; }
inline const Scalar &x() const { return _elements[0]; }
inline const Scalar &y() const { return _elements[1]; }
inline const Scalar &z() const { return _elements[2]; }
inline const Scalar &w() const { return _elements[3]; }
// Negation
mytype operator-() const
{
mytype x;
FOR_EACH_DIMENSION(ii) x._elements[ii] = -_elements[ii];
return x;
}
// Negation in-place
mytype &negate()
{
FOR_EACH_DIMENSION(ii) _elements[ii] = -_elements[ii];
return *this;
}
// Addition
mytype operator+(const mytype &u) const
{
mytype x;
FOR_EACH_DIMENSION(ii) x._elements[ii] = _elements[ii] + u._elements[ii];
return x;
}
// Addition in-place
mytype &operator+=(const mytype &u)
{
FOR_EACH_DIMENSION(ii) _elements[ii] += u._elements[ii];
return *this;
}
// Add a scalar to each element in-place
mytype &addToEachElement(Scalar u)
{
FOR_EACH_DIMENSION(ii) _elements[ii] += u;
return *this;
}
// Subtraction
mytype operator-(const mytype &u) const
{
mytype x;
FOR_EACH_DIMENSION(ii) x._elements[ii] = _elements[ii] - u._elements[ii];
return x;
}
// Subtraction in-place
mytype &operator-=(const mytype &u)
{
FOR_EACH_DIMENSION(ii) _elements[ii] -= u._elements[ii];
return *this;
}
// Subtract a scalar from each element in-place
mytype &subtractFromEachElement(Scalar u)
{
FOR_EACH_DIMENSION(ii) _elements[ii] -= u;
return *this;
}
// Scalar multiplication
mytype operator*(Scalar u) const
{
mytype x;
FOR_EACH_DIMENSION(ii) x._elements[ii] = u * _elements[ii];
return x;
}
// Scalar multiplication in-place
mytype &operator*=(Scalar u)
{
FOR_EACH_DIMENSION(ii) _elements[ii] *= u;
return *this;
}
// Component-wise multiply in-place
mytype &componentMultiply(const mytype &u)
{
FOR_EACH_DIMENSION(ii) _elements[ii] *= u._elements[ii];
return *this;
}
// Scalar division
mytype operator/(Scalar u) const
{
mytype x;
Scalar inv_u = static_cast<Scalar>( 1 ) / static_cast<Scalar>( u );
FOR_EACH_DIMENSION(ii) x._elements[ii] = _elements[ii] * inv_u;
return x;
}
// Scalar division in-place
mytype &operator/=(Scalar u)
{
Scalar inv_u = static_cast<Scalar>( 1 ) / static_cast<Scalar>( u );
FOR_EACH_DIMENSION(ii) _elements[ii] *= inv_u;
return *this;
}
// Component-wise divide in-place
mytype &componentDivide(const mytype &u)
{
FOR_EACH_DIMENSION(ii) _elements[ii] /= u._elements[ii];
return *this;
}
// Dot product
Double dotProduct(const mytype &u) const
{
Double sum = 0;
FOR_EACH_DIMENSION(ii)
sum += static_cast<Double>( _elements[ii] )
* static_cast<Double>( u._elements[ii] );
return sum;
}
public:
// Only for 2-element vectors:
// Generate a 2D rotation vector in-place
void generateRotation2D(f32 angle)
{
x() = cos(angle);
y() = sin(angle);
}
// Add rotation vector in-place
mytype &addRotation2D(const mytype &r)
{
Double ax = x(), ay = y();
Double rx = r.x(), ry = r.y();
x() = static_cast<Scalar>( ax*rx - ay*ry ); // cos(a+r) = cos(a)*cos(r) - sin(a)*sin(r)
y() = static_cast<Scalar>( ay*rx + ax*ry ); // sin(a+r) = sin(a)*cos(r) + cos(a)*sin(r)
return *this;
}
// Subtract rotation vector in-place
mytype &subtractRotation2D(const mytype &r)
{
Double ax = x(), ay = y();
Double rx = r.x(), ry = r.y();
x() = static_cast<Scalar>( ax*rx + ay*ry ); // cos(a-r) = cos(a)*cos(r) + sin(a)*sin(r)
y() = static_cast<Scalar>( ay*rx - ax*ry ); // sin(a-r) = sin(a)*cos(r) - cos(a)*sin(r)
return *this;
}
// Cross product: Result is a scalar
f32 crossProduct2D(const mytype &u)
{
return x() * u.y() - y() * u.x();
}
public:
// Only for 3-element vectors:
// Cross product: Result is a 3D vector
mytype crossProduct3D(const mytype &u)
{
mytype result;
result.x() = y() * u.z() - z() * u.y();
result.y() = z() * u.x() - x() * u.z();
result.z() = x() * u.y() - y() * u.x();
return result;
}
};
// Short-hand for common usages:
typedef Vector<2, u32, u32> Vector2u;
typedef Vector<3, u32, u32> Vector3u;
typedef Vector<4, u32, u32> Vector4u;
typedef Vector<2, s32, s32> Vector2s;
typedef Vector<3, s32, s32> Vector3s;
typedef Vector<4, s32, s32> Vector4s;
typedef Vector<2, f32, f64> Vector2f;
typedef Vector<3, f32, f64> Vector3f;
typedef Vector<4, f32, f64> Vector4f;
typedef Vector<2, f64, f64> Vector2d;
typedef Vector<3, f64, f64> Vector3d;
typedef Vector<4, f64, f64> Vector4d;
#undef FOR_EACH_DIMENSION
} // namespace cat
#endif // CAT_VECTOR_HPP

View File

@ -0,0 +1,80 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
MurmurHash2 is a very fast noncryptographic 32/64-bit hash
Algorithm by Austin Appleby <aappleby@gmail.com>
http://murmurhash.googlepages.com/
*/
#ifndef CAT_MURMUR_HASH_2_HPP
#define CAT_MURMUR_HASH_2_HPP
#include <cat/Platform.hpp>
namespace cat {
// NOTE: Result is NOT endian-neutral. Use getLE().
u32 MurmurHash32(const void *key, int bytes, u32 seed);
u64 MurmurHash64(const void *key, int bytes, u64 seed);
class IncrementalMurmurHash32
{
u32 _hash, _tail, _count, _size;
static const u32 M = 0x5bd1e995;
static const u32 R = 24;
public:
void Begin(u32 seed = 0);
void Add(const void *data, int bytes);
u32 End();
};
class IncrementalMurmurHash64
{
u32 _count;
u64 _hash, _tail, _size;
static const u64 M = 0xc6a4a7935bd1e995ULL;
static const u64 R = 47;
public:
void Begin(u64 seed = 0);
void Add(const void *data, int bytes);
u64 End();
};
} // namespace cat
#endif // CAT_MURMUR_HASH_2_HPP

View File

@ -0,0 +1,261 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_ASYNC_BUFFER_HPP
#define CAT_ASYNC_BUFFER_HPP
#include <cat/Platform.hpp>
#include <cat/port/FastDelegate.h>
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
#endif
namespace cat {
class ThreadPoolLocalStorage;
class AsyncBuffer;
typedef fastdelegate::FastDelegate4<ThreadPoolLocalStorage *, int, AsyncBuffer *, u32, bool> AsyncCallback;
// Overlapped base object
#if defined(CAT_OS_WINDOWS)
typedef OVERLAPPED AsyncOv;
#else
#error "TODO"
#endif
/*
AsyncBuffer: Utility object representing the buffers for a single I/O operation.
This is flexible enough to represent network and file IO buffers.
*/
class AsyncBuffer
{
private:
AsyncOv _ov;
AsyncCallback _callback;
u8 *_data;
u32 _data_bytes, _tag_bytes;
u8 _tag[1];
public:
// Reset AsyncOv and set offset and callback
CAT_INLINE void Reset(const AsyncCallback &callback, u64 offset = 0)
{
#if defined(CAT_OS_WINDOWS)
_ov.hEvent = 0;
_ov.Internal = 0;
_ov.InternalHigh = 0;
_ov.OffsetHigh = (u32)(offset >> 32);
_ov.Offset = (u32)offset;
#else
#error "TODO"
#endif
_callback = callback;
}
public:
static CAT_INLINE u32 OVERHEAD() { return (u32)(offsetof(AsyncBuffer, _tag)); }
CAT_INLINE AsyncOv *GetOv() { return &_ov; }
CAT_INLINE u64 GetOffset() { return ((u64)_ov.OffsetHigh << 32) | _ov.Offset; }
CAT_INLINE bool Call(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes)
{
if (!_callback) return true;
return _callback(tls, error, buffer, bytes);
}
CAT_INLINE void Zero()
{
CAT_CLR(_data, _data_bytes);
}
public:
CAT_INLINE u32 GetDataBytes() { return _data_bytes; }
CAT_INLINE u8 *GetData() { return reinterpret_cast<u8*>( _data ); }
template<class T>
CAT_INLINE T *GetData() { return reinterpret_cast<T*>( _data ); }
template<class T>
CAT_INLINE T *GetData(T * &ptr) { return (ptr = reinterpret_cast<T*>( _data )); }
public:
CAT_INLINE u32 GetTagBytes() { return _tag_bytes; }
CAT_INLINE u8 *GetTagData() { return _tag; }
template<class T>
CAT_INLINE T *GetTag() { return reinterpret_cast<T*>( _tag ); }
template<class T>
CAT_INLINE T *GetTag(T * &ptr) { return (ptr = reinterpret_cast<T*>( _tag )); }
public:
// Acquire with built-in data pointer
static CAT_INLINE AsyncBuffer *Acquire(AsyncBuffer * &ptr, u32 data_bytes = 0, u32 tag_bytes = 0)
{
const u32 OVERHEAD_BYTES = (u32)(offsetof(AsyncBuffer, _tag));
AsyncBuffer *buffer = reinterpret_cast<AsyncBuffer*>(
RegionAllocator::ii->Acquire(OVERHEAD_BYTES + data_bytes + tag_bytes) );
if (!buffer) return 0;
buffer->_data_bytes = data_bytes;
buffer->_tag_bytes = tag_bytes;
buffer->_data = buffer->_tag + tag_bytes;
return (ptr = buffer);
}
// Change number of data bytes allocated to the buffer
// Returns a new data pointer that may be different from the old data pointer
CAT_INLINE AsyncBuffer *Resize(u32 data_bytes)
{
const u32 OVERHEAD_BYTES = (u32)(offsetof(AsyncBuffer, _tag));
AsyncBuffer *buffer = reinterpret_cast<AsyncBuffer*>(
RegionAllocator::ii->Resize( this,
OVERHEAD_BYTES + _tag_bytes + data_bytes) );
if (!buffer) return 0;
buffer->_data_bytes = data_bytes;
buffer->_data = buffer->_tag + buffer->_tag_bytes;
return buffer;
}
public:
// Acquire with built-in data pointer
static CAT_INLINE u8 *Acquire(u32 data_bytes = 0, u32 tag_bytes = 0)
{
AsyncBuffer *buffer;
if (!Acquire(buffer, data_bytes, tag_bytes)) return 0;
return buffer->_data;
}
// Acquire with built-in data pointer
template<class T>
static CAT_INLINE T *Acquire(T * &data, u32 tag_bytes = 0)
{
AsyncBuffer *buffer;
if (!Acquire(buffer, sizeof(T), tag_bytes)) return 0;
return (data = reinterpret_cast<T*>( buffer->_data ));
}
// Change number of data bytes allocated to the buffer
// Returns a new data pointer that may be different from the old data pointer
static CAT_INLINE u8 *Resize(void *vdata, u32 data_bytes)
{
u8 *data = reinterpret_cast<u8*>( vdata );
const u32 OVERHEAD_BYTES = (u32)(offsetof(AsyncBuffer, _tag));
if (!data) return Acquire(data_bytes);
AsyncBuffer *buffer = reinterpret_cast<AsyncBuffer*>( data - OVERHEAD_BYTES );
buffer = reinterpret_cast<AsyncBuffer*>(
RegionAllocator::ii->Resize(buffer,
OVERHEAD_BYTES + buffer->_tag_bytes + data_bytes) );
if (!buffer) return 0;
buffer->_data_bytes = data_bytes;
return (buffer->_data = buffer->_tag + buffer->_tag_bytes);
}
public:
// Wrap external data pointer
static CAT_INLINE AsyncBuffer *Wrap(void *vdata, u32 data_bytes, u32 tag_bytes = 0)
{
u8 *data = reinterpret_cast<u8*>( vdata );
const u32 OVERHEAD_BYTES = (u32)(offsetof(AsyncBuffer, _tag));
AsyncBuffer *buffer = reinterpret_cast<AsyncBuffer*>(
RegionAllocator::ii->Acquire(OVERHEAD_BYTES + tag_bytes) );
if (!buffer) return 0;
buffer->_data_bytes = data_bytes;
buffer->_tag_bytes = tag_bytes;
buffer->_data = data;
return buffer;
}
public:
// Only works on Acquired() buffers, not Wrap()ed buffers
static CAT_INLINE AsyncBuffer *Promote(void *vdata)
{
u8 *data = reinterpret_cast<u8*>( vdata );
const u32 OVERHEAD_BYTES = (u32)(offsetof(AsyncBuffer, _tag));
if (!data) return 0;
return reinterpret_cast<AsyncBuffer*>( data - OVERHEAD_BYTES );
}
public:
// Release memory
CAT_INLINE void Release()
{
RegionAllocator::ii->Release(this);
}
static CAT_INLINE void Release(AsyncBuffer *buffer)
{
RegionAllocator::ii->Release(buffer);
}
static CAT_INLINE void Release(void *vdata)
{
u8 *data = reinterpret_cast<u8*>( vdata );
const u32 OVERHEAD_BYTES = (u32)(offsetof(AsyncBuffer, _tag));
if (!data) return;
AsyncBuffer *buffer = reinterpret_cast<AsyncBuffer*>( data - OVERHEAD_BYTES );
RegionAllocator::ii->Release(buffer);
}
};
} // namespace cat
#endif // CAT_ASYNC_BUFFER_HPP

View File

@ -0,0 +1,56 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_BASE64_HPP
#define CAT_BASE64_HPP
#include <cat/Platform.hpp>
#include <ostream>
namespace cat {
// Write buffer to output stream in Base64 encoding
int GetBase64LengthFromBinaryLength(int bytes);
// Returns number of bytes written, or 0 for error
int WriteBase64(const void *buffer, int bytes, char *encoded_buffer, int encoded_bytes);
int WriteBase64Str(const void *buffer, int bytes, char *encoded_buffer, int encoded_bytes); // This version writes a null-terminator
int WriteBase64(const void *buffer, int bytes, std::ostream &output);
// Read buffer in Base64 encoding
int GetBinaryLengthFromBase64Length(const char *encoded_buffer, int bytes);
// Returns number of bytes read, or 0 for error
int ReadBase64(const char *encoded_buffer, int encoded_bytes, void *decoded_buffer, int decoded_bytes);
int ReadBase64(const char *encoded_buffer, int encoded_bytes, std::ostream &output);
} // namespace cat
#endif // CAT_BASE64_HPP

View File

@ -0,0 +1,194 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_LOGGING_HPP
#define CAT_LOGGING_HPP
#include <cat/threads/RegionAllocator.hpp>
#if defined(CAT_OS_WINDOWS)
#include <cat/port/WindowsInclude.hpp>
#endif
namespace cat {
//// Enumerations
enum EventSeverity
{
LVL_INANE,
LVL_INFO,
LVL_WARN,
LVL_OOPS,
LVL_FATAL,
LVL_SILENT, // invalid for an actual event's level, valid value for a threshold
};
//// Utility
region_string HexDumpString(const void *vdata, u32 bytes);
// Write to console (and debug log in windows) then trigger a breakpoint and exit
void FatalStop(const char *message);
void DefaultLogCallback(EventSeverity severity, const char *source, region_ostringstream &msg);
//// Logging
typedef void (*LogCallback)(EventSeverity severity, const char *source, region_ostringstream &msg);
class Logging : public Singleton<Logging>
{
CAT_SINGLETON(Logging);
LogCallback _callback;
friend class Recorder;
void LogEvent(Recorder *recorder);
public:
int _log_threshold;
public:
void Initialize(EventSeverity min_severity = LVL_INANE);
CAT_INLINE void SetThreshold(EventSeverity min_severity) { _log_threshold = min_severity; }
void ReadSettings();
void Shutdown();
protected:
bool _service;
#if defined(CAT_OS_WINDOWS)
HANDLE _event_source;
#endif
public:
CAT_INLINE bool IsService() { return _service; }
void EnableServiceMode(const char *service_name);
void WriteServiceLog(EventSeverity severity, const char *line);
public:
// Not thread-safe
CAT_INLINE void SetLogCallback(LogCallback cb) { _callback = cb; }
};
//// Recorder
class Recorder
{
friend class Logging;
EventSeverity _severity;
const char *_subsystem;
region_ostringstream _msg;
public:
Recorder(const char *subsystem, EventSeverity severity);
~Recorder();
public:
template<class T> inline Recorder &operator<<(const T &t)
{
_msg << t;
return *this;
}
};
// Because there is an IF statement in the macro, you cannot use the
// braceless if-else construction:
// if (XYZ) WARN("SS") << "ERROR!"; else INFO("SS") << "OK!"; <-- bad
// Instead use:
// if (XYZ) { WARN("SS") << "ERROR!"; } else INFO("SS") << "OK!"; <-- good
#define RECORD(subsystem, severity) \
if (severity >= Logging::ii->_log_threshold) Recorder(subsystem, severity)
#define INANE(subsystem) RECORD(subsystem, LVL_INANE)
#define INFO(subsystem) RECORD(subsystem, LVL_INFO)
#define WARN(subsystem) RECORD(subsystem, LVL_WARN)
#define OOPS(subsystem) RECORD(subsystem, LVL_OOPS)
#define FATAL(subsystem) RECORD(subsystem, LVL_FATAL)
//// Enforcer
class Enforcer
{
protected:
std::ostringstream oss;
public:
Enforcer(const char *locus);
~Enforcer();
public:
template<class T> inline Enforcer &operator<<(const T &t)
{
oss << t;
return *this;
}
};
#define USE_ENFORCE_EXPRESSION_STRING
#define USE_ENFORCE_FILE_LINE_STRING
#if defined(USE_ENFORCE_EXPRESSION_STRING)
# define ENFORCE_EXPRESSION_STRING(exp) "Failed assertion (" #exp ")"
#else
# define ENFORCE_EXPRESSION_STRING(exp) "Failed assertion"
#endif
#if defined(USE_ENFORCE_FILE_LINE_STRING)
# define ENFORCE_FILE_LINE_STRING " at " __FILE__ ":" CAT_STRINGIZE(__LINE__)
#else
# define ENFORCE_FILE_LINE_STRING ""
#endif
// Because there is an IF statement in the macro, you cannot use the
// braceless if-else construction:
// if (XYZ) ENFORCE(A == B) << "ERROR"; else INFO("SS") << "OK"; <-- bad!
// Instead use:
// if (XYZ) { ENFORCE(A == B) << "ERROR"; } else INFO("SS") << "OK"; <-- good!
#define ENFORCE(exp) if ( (exp) == 0 ) Enforcer(ENFORCE_EXPRESSION_STRING(exp) ENFORCE_FILE_LINE_STRING "\n")
#define EXCEPTION() Enforcer("Exception" ENFORCE_FILE_LINE_STRING "\n")
#if defined(CAT_DEBUG)
# define DEBUG_ENFORCE(exp) ENFORCE(exp)
#else
# define DEBUG_ENFORCE(exp) if (0) ENFORCE(exp) /* hopefully will be optimized out of existence */
#endif
} // namespace cat
#endif // CAT_LOGGING_HPP

View File

@ -0,0 +1,75 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_MMAPFILE_HPP
#define CAT_MMAPFILE_HPP
#include <cat/Platform.hpp>
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
#endif
namespace cat {
class MMapFile
{
char *data;
u32 len;
s32 offset;
#if defined(CAT_OS_LINUX)
int fd;
#elif defined(CAT_OS_WINDOWS)
HANDLE hFile, hMapping;
#endif
public:
MMapFile(const char *path);
~MMapFile();
inline bool good() { return data != 0; }
inline bool inside() { return offset >= 0 && offset < (s32)len; }
inline u32 size() { return len; }
inline void seek(s32 poffset) { offset = poffset; }
inline bool underrun(s32 requested) { return (u32)(offset + requested) > len; }
inline char *look() { return data + offset; }
inline char *look(s32 offset) { return data + offset; }
inline char *read(s32 requested) { offset += requested; return data + (offset - requested); }
inline void skip(s32 requested) { offset += requested; }
inline u32 remaining() { return len - offset; }
inline u32 getOffset() { return offset; }
};
} // namespace cat
#endif // CAT_MMAPFILE_HPP

View File

@ -0,0 +1,107 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_PACKAGE_MANAGER_HPP
#define CAT_PACKAGE_MANAGER_HPP
#include <cat/Platform.hpp>
#include <cat/port/FastDelegate.h>
namespace cat {
// Package resource identifier macro
#define CAT_UNCAGE(packagePath, offset, size) offset, size
/*
All file resources are packed into one large file and each is
assigned a unique identifying number, starting from 0.
The client source code is preprocessed by a tool that replaces the
arguments of the CAT_UNPACK() macro with the correct ID number based
on the string given as the first argument.
CAT_UNPACK("world1/lightmap3.png")
-> CAT_UNPACK("world1/lightmap3.png", 15241, 256, 0xdecryptionkey)
At runtime the client application will not be aware of the string
name of a resource in the package, only where to go to get it.
Resources that are used together during tuning will have identifiers
that are close together so that disk seek time is minimized.
*/
/*
Kennel files are simple concatenations of all of the game resources.
The goal is to reduce access time to data by cutting the operating
system's file-system out completely. Furthermore, data that are
accessed together are stored together on disk and in the same order
that they are accessed.
Textures are compressed with modified JPEG-LS, providing the fastest
possible access time.
Sounds compression hasn't been investigated yet.
Each resource (sound/texture) is obfuscated with a 64-bit key, making
it necessary to reverse-engineer the game client to decode in-game
resources outside of the game.
The KennelFile object implements optimized algorithms for performing
in-place modification to a large datafile (>4 GB).
*/
class KennelPatchFile : AsyncFile
{
public:
KennelPatchFile();
~KennelPatchFile();
public:
void Insert
};
// Kennel Patch Callback (param=bool: true on successful patch, false on error)
typedef fastdelegate::FastDelegate1<bool, void> KennelPatchCallback;
class KennelFile : AsyncFile
{
public:
KennelFile();
virtual ~KennelFile();
public:
bool Move(u64 dest, u32 region_size, u64 src, KennelPatchCallback OnComplete);
};
} // namespace cat
#endif // CAT_PACKAGE_MANAGER_HPP

View File

@ -0,0 +1,117 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_SETTINGS_HPP
#define CAT_SETTINGS_HPP
#include <cat/Singleton.hpp>
#include <cat/threads/Mutex.hpp>
#include <fstream>
namespace cat {
enum SettingsValueFlags
{
CAT_SETTINGS_FILLED = 1, // s[] array has been set
CAT_SETTINGS_INT = 2, // value has been promoted to int 'i'
};
struct SettingsValue
{
u8 flags; // sum of SettingsValueFlags
char s[256]; // always nul-terminated
int i;
};
class SettingsKey
{
public:
SettingsKey(SettingsKey *lnode, SettingsKey *gnode, const char *name);
~SettingsKey();
public:
SettingsKey *lnode, *gnode;
char name[64]; // not necessarily nul-terminated
SettingsValue value;
public:
void write(std::ofstream &file);
};
// User settings manager
class Settings : public Singleton<Settings>
{
CAT_SINGLETON(Settings);
Mutex _lock;
protected:
static const u32 KEY_HASH_SALT = 0xbaddecaf;
static const int SETTINGS_HASH_BINS = 256;
SettingsKey *hbtrees[SETTINGS_HASH_BINS]; // hash table of binary trees
bool readSettings; // Flag set when settings have been read from disk
bool modified; // Flag set when settings have been modified since last write
std::string _settings_file;
protected:
SettingsKey *addKey(const char *name);
SettingsKey *getKey(const char *name);
SettingsKey *initInt(const char *name, int n, bool overwrite);
SettingsKey *initStr(const char *name, const char *value, bool overwrite);
void clear();
public:
void readSettingsFromFile(const char *file_path = "settings.txt", const char *override_file = "override.txt");
void readSettingsFromBuffer(const char *data, int len);
void write();
public:
int getInt(const char *name);
const char *getStr(const char *name);
int getInt(const char *name, int init);
const char *getStr(const char *name, const char *init);
void setInt(const char *name, int n);
void setStr(const char *name, const char *value);
};
} // namespace cat
#endif // CAT_SETTINGS_HPP

View File

@ -0,0 +1,82 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_FILES_HPP
#define CAT_THREAD_POOL_FILES_HPP
#include <cat/threads/ThreadPool.hpp>
#include <cat/port/FastDelegate.h>
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
#endif
namespace cat {
enum AsyncFileModes
{
ASYNCFILE_READ = 1,
ASYNCFILE_WRITE = 2,
ASYNCFILE_RANDOM = 4
};
class AsyncFile : public ThreadRefObject
{
HANDLE _file;
protected:
char _file_path[MAX_PATH+1];
public:
AsyncFile(int priorityLevel);
virtual ~AsyncFile();
public:
bool Valid();
const char *GetFilePath();
public:
/*
In read mode, Open() will fail if the file does not exist.
In write mode, Open() will create the file if it does not exist.
*/
bool Open(const char *file_path, u32 async_file_modes);
void Close();
bool SetSize(u64 bytes);
u64 GetSize();
bool Read(AsyncBuffer *buffer, u64 offset, const AsyncCallback &callback);
bool Write(AsyncBuffer *buffer, u64 offset, const AsyncCallback &callback = 0);
};
} // namespace cat
#endif // CAT_THREAD_POOL_FILES_HPP

View File

@ -0,0 +1,106 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_STRINGS_HPP
#define CAT_STRINGS_HPP
/*
These are ANSI C String function that do not work with UNICODE, UTF-8, etc.
*/
#include <cat/Platform.hpp>
#if defined(CAT_COMPILER_MSVC)
#include <string.h> // _stricmp
#elif defined(CAT_COMPILER_GCC)
#include <strings.h> // strcasecmp
#endif
namespace cat {
// Convert from signed 32-bit number to string (up to 12 bytes including '\0')
int DecToString(s32 x, char *outs);
// iStrEqual(): Returns true if strings match. Case-insensitive
#if defined(CAT_COMPILER_MSVC)
CAT_INLINE bool iStrEqual(const char *A, const char *B)
{
return _stricmp(A, B) == 0;
}
#elif defined(CAT_COMPILER_GCC)
CAT_INLINE bool iStrEqual(const char *A, const char *B)
{
return strcasecmp(A, B) == 0;
}
#else
# define CAT_UNKNOWN_BUILTIN_ISTRCMP
bool iStrEqual(const char *A, const char *B);
#endif
// Get length of string that has a maximum length (potentially no trailing nul)
u32 GetFixedStrLen(const char *str, u32 max_len);
// Set a fixed string buffer (zero-padded) from a variable-length string,
// both either zero or length-terminated. Returns length of copied string
u32 SetFixedStr(char *dest, u32 dest_len, const char *src, u32 src_max_len);
// Returns true if buffer contains any non-zero bytes
bool IsZeroFixedBuffer(const void *buffer, u32 bytes);
// Replaces all similar-looking glyphs with a common character
char DesimilarizeCharacter(char ch);
// Replaces all similar-looking glyphs with common characters while copying a string
void CopyDesimilarizeString(const char *from, char *to);
// Replaces all similar-looking glyphs with common characters in a fixed string
u32 DesimilarizeFixedString(char *str, u32 max_len);
// Copies the input string to an output string replacing lowercase letters with their uppercase equivalents
void CopyToUppercaseString(const char *from, char *to);
// Copies the input string to an output string replacing uppercase letters with their lowercase equivalents
void CopyToLowercaseString(const char *from, char *to);
} // namespace cat
#endif // CAT_STRINGS_HPP

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,101 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Several algorithms based on ideas from the "Handbook of Applied Cryptography"
http://www.cacr.math.uwaterloo.ca/hac/
*/
#ifndef CAT_BIG_MONTGOMERY_HPP
#define CAT_BIG_MONTGOMERY_HPP
#include <cat/math/BigRTL.hpp>
#include <cat/rand/IRandom.hpp>
namespace cat {
// Performs fast modular arithmetic in the Montgomery Residue Number System
class BigMontgomery : public BigRTL
{
static const int MON_OVERHEAD = 3 + 4;
int mon_regs;
protected:
Leg *TempProduct;
Leg *TempProductHi;
Leg *CachedModulus;
Leg mod_inv;
public:
BigMontgomery(int regs, int bits);
// Must call SetModulus() before using this object
void SetModulus(const Leg *mod);
public:
const Leg *GetModulus() { return CachedModulus; }
void CopyModulus(Leg *out);
public:
// Convert value in register into RNS, stored in out
void MonInput(const Leg *in, Leg *out);
// Convert value in register from RNS, stored in out
void MonOutput(const Leg *in, Leg *out);
// Note: This will clobber the input product!
// Reduce a double-register product to a single register in the RNS
void MonReduceProduct(Leg *inout_product, Leg *out);
public:
// Inputs and outputs must be in the Montgomery RNS
void MonAdd(const Leg *in_a, const Leg *in_b, Leg *out);
void MonSubtract(const Leg *in_a, const Leg *in_b, Leg *out);
void MonNegate(const Leg *in, Leg *out);
void MonDouble(const Leg *in, Leg *out);
public:
// Inputs and outputs must be in the Montgomery RNS
void MonMultiply(const Leg *in_a, const Leg *in_b, Leg *out);
void MonSquare(const Leg *in, Leg *out);
public:
// Base must be in the Montgomery RNS. in_base != out
void MonExpMod(const Leg *in_base, const Leg *in_exp, Leg *out);
public:
// Input is NOT in the RNS (don't call MonInput)
// Probably a prime, certainty = 4^-trials. 20: %99.9999999999 certainty
bool IsRabinMillerPrime(IRandom *prng, const Leg *n, int trials = 20);
};
} // namespace cat
#endif // CAT_BIG_MONTGOMERY_HPP

View File

@ -0,0 +1,95 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Several algorithms based on ideas from the "Handbook of Applied Cryptography"
http://www.cacr.math.uwaterloo.ca/hac/
Several algorithms based on ideas from the
"Handbook of Elliptic and Hyperelliptic Curve Cryptography"
http://www.hyperelliptic.org/HEHCC/
*/
#ifndef CAT_BIG_PSEUDO_MERSENNE_HPP
#define CAT_BIG_PSEUDO_MERSENNE_HPP
#include <cat/math/BigRTL.hpp>
namespace cat {
// Performs fast arithmetic modulo 2^bits-C, C = 1 (mod 4) or 3 (mod 8), C < 16384
class BigPseudoMersenne : public BigRTL
{
static const int PM_OVERHEAD = 6; // overhead for MrSquareRoot()
int pm_regs;
protected:
Leg *CachedModulus;
Leg modulus_c;
void CAT_FASTCALL MrReduceProductX(Leg overflow, Leg *inout);
void CAT_FASTCALL MrReduceProduct(const Leg *in_hi, const Leg *in_lo, Leg *out);
public:
BigPseudoMersenne(int regs, int bits, int C);
public:
const Leg *GetModulus() { return CachedModulus; }
void CAT_FASTCALL CopyModulus(Leg *out);
public:
// Result may be one modulus too large, so efficiently correct that
void CAT_FASTCALL MrReduce(Leg *inout);
public:
void CAT_FASTCALL MrAdd(const Leg *in_a, const Leg *in_b, Leg *out);
void CAT_FASTCALL MrAddX(Leg *inout, Leg x);
void CAT_FASTCALL MrSubtract(const Leg *in_a, const Leg *in_b, Leg *out);
void CAT_FASTCALL MrSubtractX(Leg *inout, Leg x);
void CAT_FASTCALL MrNegate(const Leg *in, Leg *out);
public:
void CAT_FASTCALL MrDouble(const Leg *in, Leg *out);
public:
void CAT_FASTCALL MrMultiply(const Leg *in_a, const Leg *in_b, Leg *out);
void CAT_FASTCALL MrMultiplyX(const Leg *in_a, Leg in_b, Leg *out);
void CAT_FASTCALL MrSquare(const Leg *in, Leg *out);
public:
void CAT_FASTCALL MrInvert(const Leg *in, Leg *out);
public:
void CAT_FASTCALL MrSquareRoot(const Leg *in, Leg *out);
};
} // namespace cat
#endif // CAT_BIG_PSEUDO_MERSENNE_HPP

View File

@ -0,0 +1,164 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Several algorithms based on ideas from the "Handbook of Applied Cryptography"
http://www.cacr.math.uwaterloo.ca/hac/
Several algorithms based on ideas from the
"Handbook of Elliptic and Hyperelliptic Curve Cryptography"
http://www.hyperelliptic.org/HEHCC/
*/
#ifndef CAT_BIG_RTL_HPP
#define CAT_BIG_RTL_HPP
#include <cat/math/Legs.hpp>
namespace cat {
// Implements a register transfer language (RTL) for big integer arithmetic
class BigRTL
{
static const int BIG_OVERHEAD = 7; // overhead for ModularInverse()
int library_regs;
protected:
int library_legs;
Leg *library_memory;
protected:
static Leg CAT_FASTCALL ShiftRight(int legs, const Leg *in, int shift, Leg *out);
static Leg CAT_FASTCALL ShiftLeft(int legs, const Leg *in, int shift, Leg *out);
protected:
static u8 CAT_FASTCALL Add(int legs, const Leg *in_a, const Leg *in_b, Leg *out);
static u8 CAT_FASTCALL Add(int legs_a, const Leg *in_a, int legs_b, const Leg *in_b, Leg *out); // legs_b <= legs_a
static u8 CAT_FASTCALL Subtract(int legs, const Leg *in_a, const Leg *in_b, Leg *out);
protected:
static Leg CAT_FASTCALL MultiplyX(int legs, const Leg *in_a, Leg in_b, Leg *out);
static Leg CAT_FASTCALL MultiplyXAdd(int legs, const Leg *in_a, Leg in_b, const Leg *in_c, Leg *out);
static Leg CAT_FASTCALL DoubleAdd(int legs, const Leg *in_a, const Leg *in_b, Leg *out);
protected:
static void CAT_FASTCALL DivideCore(int A_used, Leg A_overflow, Leg *A, int B_used, Leg *B, Leg *Q); // A = remainder
public:
BigRTL(int regs, int bits);
~BigRTL();
public:
Leg * CAT_FASTCALL Get(int reg_index);
CAT_INLINE int Legs() { return library_legs; }
CAT_INLINE int RegBytes() { return library_legs * sizeof(Leg); }
public:
// Save one single register to an endian-neutral byte array
void CAT_FASTCALL Save(const Leg *in, void *out, int bytes);
// Load one single register from an endian-neutral byte array
void CAT_FASTCALL Load(const void *in, int bytes, Leg *out);
bool CAT_FASTCALL LoadFromString(const char *in, int base, Leg *out);
public:
void CAT_FASTCALL Copy(const Leg *in, Leg *out);
void CAT_FASTCALL CopyX(Leg in, Leg *out);
public:
int CAT_FASTCALL LegsUsed(const Leg *in);
public:
bool CAT_FASTCALL Greater(const Leg *in_a, const Leg *in_b);
bool CAT_FASTCALL GreaterX(const Leg *in, Leg x);
bool CAT_FASTCALL Less(const Leg *in_a, const Leg *in_b);
bool CAT_FASTCALL LessX(const Leg *in, Leg x);
bool CAT_FASTCALL Equal(const Leg *in_a, const Leg *in_b);
bool CAT_FASTCALL EqualX(const Leg *in, Leg x);
bool CAT_FASTCALL IsZero(const Leg *in);
public:
Leg CAT_FASTCALL ShiftLeft(const Leg *in, int shift, Leg *out);
void CAT_FASTCALL MoveLegsRight(const Leg *in, int legs, Leg *out);
public:
u8 CAT_FASTCALL Add(const Leg *in_a, const Leg *in_b, Leg *out);
u8 CAT_FASTCALL AddX(Leg *inout, Leg x);
u8 CAT_FASTCALL Subtract(const Leg *in_a, const Leg *in_b, Leg *out);
u8 CAT_FASTCALL SubtractX(Leg *inout, Leg x);
void CAT_FASTCALL Negate(const Leg *in, Leg *out);
public:
u8 CAT_FASTCALL Double(const Leg *in, Leg *out);
public:
// Eat all trailing least significant zeroes from the argument and return the number eatten
int CAT_FASTCALL EatTrailingZeroes(Leg *inout);
public:
Leg CAT_FASTCALL MultiplyX(const Leg *in_a, Leg in_b, Leg *out); // out = a[] * b
Leg CAT_FASTCALL MultiplyXAdd(const Leg *in_a, Leg in_b, const Leg *in_c, Leg *out); // out = a[] * b + c[]
Leg CAT_FASTCALL DoubleAdd(const Leg *in_a, const Leg *in_b, Leg *out); // out = a[] * 2 + b[]
public:
void CAT_FASTCALL MultiplyLow(const Leg *in_a, const Leg *in_b, Leg *out); // out = a[] * b[], low half
public:
// out[] gets the low part of the product, next reg gets high part
// note: in_a != out, in_b != out
void CAT_FASTCALL Multiply(const Leg *in_a, const Leg *in_b, Leg *out); // out+1:out = a[] * b[]
void CAT_FASTCALL Square(const Leg *in, Leg *out); // out+1:out = in[] * in[]
public:
Leg CAT_FASTCALL DivideX(const Leg *in_a, Leg in_b, Leg *out); // out = a[] / b, returns modulus
Leg CAT_FASTCALL ModulusX(const Leg *in_a, Leg in_b); // returns a[] % b
public:
bool CAT_FASTCALL Divide(const Leg *in_a, const Leg *in_b, Leg *out_q, Leg *out_r);
// Divide the product of two registers (a+1:a) by single register (b)
// Resulting quotient is two registers (q+1:q) and remainder is one register (r)
bool CAT_FASTCALL DivideProduct(const Leg *in_a, const Leg *in_b, Leg *out_q, Leg *out_r);
public:
// r = a * b (mod m)
void CAT_FASTCALL MulMod(const Leg *in_a, const Leg *in_b, const Leg *in_m, Leg *r);
public:
void CAT_FASTCALL ModularInverse(const Leg *x, const Leg *modulus, Leg *inverse);
public:
Leg CAT_FASTCALL MultiplicativeInverseX(Leg x);
};
} // namespace cat
#endif // CAT_BIG_RTL_HPP

View File

@ -0,0 +1,195 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Addition and doubling formulas using Extended Twisted Edwards coordinates from
Hisil<69>Wong<6E>Carter<65>Dawson paper "Twisted Edwards Curves Revisited" (Asiacrypt 2008)
w-MOF scalar multiplication from http://www.sdl.hitachi.co.jp/crypto/mof/index-e.html
Scalar multiplication precomputation with "conjugate addition" inspired by
Longa-Gebotys paper "Novel Precomputation Schemes for Elliptic Curve Cryptosystems" (2008)
*/
/*
Twisted Edwards E(p) Curve: a * x^2 + y^2 = 1 + d * x^2 * y^2, a = -1, p = 2^256 - c, c small
Edwards coordinates: (X : Y : Z)
Extended Edwards coordinates: (X : Y : T : Z), T = XY
Edwards to Extended Edwards: (X : Y : Z) -> (XZ : YZ : XY : ZZ)
Extended Edwards to Edwards: (X : Y : T : Z) -> (X : Y : Z)
-(X : Y : T : Z) = (-X : Y : -T : Z)
Additive Identity element: X = 0
When Z = 1, a multiplication can be omitted
Mixing operations for more speed:
doubling, doubling -> E = 2E
doubling, add -> Ee = 2E, E = Ee + Ee
*/
#ifndef CAT_BIG_TWISTED_EDWARDS_HPP
#define CAT_BIG_TWISTED_EDWARDS_HPP
#include <cat/math/BigPseudoMersenne.hpp>
#include <cat/rand/IRandom.hpp>
namespace cat {
class BigTwistedEdwards : public BigPseudoMersenne
{
static const int POINT_REGS = 4;
static const int XOFF = 0;
int YOFF, TOFF, ZOFF, POINT_STRIDE;
// Point multiplication default window
static const int WINDOW_BITS = 6;
static const int PRECOMP_POINTS = 1 << (WINDOW_BITS-1);
static const int PRECOMP_NEG_OFFSET = PRECOMP_POINTS / 2;
static const int TE_OVERHEAD = (1 + PRECOMP_POINTS) * POINT_REGS + 9 + POINT_REGS * 2;
int te_regs;
// Local workspace
Leg *A, *B, *C, *D, *E, *F, *G, *H, *CurveQ, *Generator;
Leg *TempPt;
protected:
Leg curve_d;
// Simultaneous Add and Subtract for efficient precomputation (A +/- B) in 14M 1D 11a (versus 16M 2D 16a)
void PtPrecompAddSub(const Leg *in_a, const Leg *in_b, Leg *sum, Leg *diff, int neg_offset);
public:
BigTwistedEdwards(int regs, int bits, int C, int D, const u8 *Q, const u8 *GenPt);
int PtLegs() { return Legs() * POINT_REGS; }
Leg GetCurveD() { return curve_d; }
const Leg *GetCurveQ() { return CurveQ; }
const Leg *GetGenerator() { return Generator; }
public:
// Unpack an Extended Projective point (X,Y,T,Z) from affine point (x,y)
void PtUnpack(Leg *inout);
// Set a point to the identity
void PtIdentity(Leg *inout);
// Check if the affine point (x,y) is the additive identity x=0
bool IsAffineIdentity(const Leg *in);
public:
void PtCopy(const Leg *in, Leg *out);
// Fill the X coordinate of the point with a random value
void PtFillRandomX(IRandom *prng, Leg *out);
// Generate a random point on the curve that is not part of a small subgroup
void PtGenerate(IRandom *prng, Leg *out);
public:
// Solve for Y given the X point on a curve
void PtSolveAffineY(Leg *inout);
// Verify that the point (x,y) exists on the given curve
bool PtValidAffine(const Leg *in);
public:
// out(x) = X/Z
void SaveAffineX(const Leg *in, void *out_x);
// out(x,y) = (X/Z,Y/Z)
void SaveAffineXY(const Leg *in, void *out_x, void *out_y);
// out(X,Y) = (X,Y) without attempting to convert to affine from projective
void SaveProjectiveXY(const Leg *in, void *out_x, void *out_y);
// out(X,Y,Z,T) = (in_x,in_y), returns false if the coordinates are invalid
bool LoadVerifyAffineXY(const void *in_x, const void *in_y, Leg *out);
// Compute affine coordinates for (X,Y), set Z=1, and compute T = xy
void PtNormalize(const Leg *in, Leg *out);
public:
// Extended Twisted Edwards Negation Formula
void PtNegate(const Leg *in, Leg *out);
// Extended Twisted Edwards Unified Addition Formula (works when both inputs are the same) in 8M 1D 9a
void PtEAdd(const Leg *in_a, const Leg *in_b, Leg *out);
void PtAdd(const Leg *in_a, const Leg *in_b, Leg *out); // -1M, cannot be followed by PtAdd
// Extended Twisted Edwards Unified Subtraction Formula (works when both inputs are the same) in 8M 1D 9a
void PtESubtract(const Leg *in_a, const Leg *in_b, Leg *out);
void PtSubtract(const Leg *in_a, const Leg *in_b, Leg *out); // -1M, cannot be followed by PtAdd
// Extended Twisted Edwards Dedicated Doubling Formula in 4M 4S 5a
void PtEDouble(const Leg *in, Leg *out);
void PtDouble(const Leg *in, Leg *out); // -1M, cannot be followed by PtAdd
// Extended Twisted Edwards Dedicated Doubling Formula Assuming Z=1, in 4M 3S 4a
void PtEDoubleZ1(const Leg *in, Leg *out);
void PtDoubleZ1(const Leg *in, Leg *out); // -1M, cannot be followed by PtAdd
public:
// Allocate a table for use with PtMultiplyPrecomp()
// Free the table with Aligned::Delete()
Leg *PtMultiplyPrecompAlloc(int w);
// Precompute odd multiples of input point
void PtMultiplyPrecomp(const Leg *in, int w, Leg *table);
public:
// Extended Twisted Edwards Scalar Multiplication k*p
// Requires precomputation with PtMultiplyPrecomp()
// CAN *NOT* BE followed by a Pt[E]Add()
void PtMultiply(const Leg *in_precomp, int w, const Leg *in_k, u8 msb_k, Leg *out);
// Extended Twisted Edwards Scalar Multiplication k*p
// Uses default precomputation
// CAN *NOT* BE followed by a Pt[E]Add()
void PtMultiply(const Leg *in_p, const Leg *in_k, u8 msb_k, Leg *out);
// A reference multiplier to verify that PtMultiply() is functionally the same
void RefMul(const Leg *in_p, const Leg *in_k, u8 msb_k, Leg *out);
public:
// Extended Twisted Edwards Simultaneous Scalar Multiplication k*P + l*Q
// Requires precomputation with PtMultiplyPrecomp()
// CAN *NOT* BE followed by a Pt[E]Add()
void PtSiMultiply(const Leg *precomp_p, const Leg *precomp_q, int w,
const Leg *in_k, u8 msb_k, const Leg *in_l, u8 msb_l, Leg *out);
};
} // namespace cat
#endif // CAT_BIG_TWISTED_EDWARDS_HPP

View File

@ -0,0 +1,246 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_BITMATH_HPP
#define CAT_BITMATH_HPP
#include <cat/Platform.hpp>
#if defined(CAT_OS_WINDOWS)
# include <cat/port/WindowsInclude.hpp>
#endif
namespace cat {
// Next highest power of two (e.g. 13 -> 16)
CAT_INLINE u32 NextHighestPow2(u32 n)
{
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n + 1;
}
CAT_INLINE u64 NextHighestPow2(u64 n)
{
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
return n + 1;
}
// Bit Scan Forward (BSF)
// Scans from bit 0 to MSB
// Undefined when input is zero
CAT_INLINE u32 BSF32(u32 x);
CAT_INLINE u32 BSF64(u64 x);
// Bit Scan Reverse (BSR)
// Scans from MSB to bit 0
// Undefined when input is zero
CAT_INLINE u32 BSR32(u32 x);
CAT_INLINE u32 BSR64(u64 x);
// Returns the count of bits set in the input for types up to 128 bits
template<typename T> CAT_INLINE T BitCount(T v)
{
// From Stanford Bit Twiddling Hacks collection
// http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
v = v - ((v >> 1) & (T)~(T)0/3);
v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);
v = (v + (v >> 4)) & (T)~(T)0/255*15;
return (T)(v * ((T)~(T)0/255)) >> ((sizeof(v) - 1) * 8);
}
// Reconstruct a 32-bit or 64-bit counter that increments by one each time,
// given a truncated sample of its low bits, and the last accepted value of the counter.
template<int BITS, typename T> CAT_INLINE T ReconstructCounter(T last_accepted_count, u32 partial_low_bits)
{
const u32 IV_MSB = (1 << BITS); // BITS < 32
const u32 IV_MASK = (IV_MSB - 1);
s32 diff = partial_low_bits - (u32)(last_accepted_count & IV_MASK);
return ((last_accepted_count & ~(T)IV_MASK) | partial_low_bits)
- (((IV_MSB >> 1) - (diff & IV_MASK)) & IV_MSB)
+ (diff & IV_MSB);
}
u32 BSF32(u32 x)
{
#if defined(CAT_COMPILER_MSVC) && defined(CAT_WORD_64) && !defined(CAT_DEBUG)
u32 index;
_BitScanForward((unsigned long*)&index, x);
return index;
#elif defined(CAT_ASM_INTEL) && defined(CAT_ISA_X86)
CAT_ASM_BEGIN
BSF eax, [x]
CAT_ASM_END
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
u32 retval;
CAT_ASM_BEGIN
"BSFl %1, %%eax"
: "=a" (retval)
: "r" (x)
: "cc"
CAT_ASM_END
return retval;
#else
return BSR32(x ^ (x - 1));
#endif
}
u32 BSR32(u32 x)
{
#if defined(CAT_COMPILER_MSVC) && defined(CAT_WORD_64) && !defined(CAT_DEBUG)
u32 index;
_BitScanReverse((unsigned long*)&index, x);
return index;
#elif defined(CAT_ASM_INTEL) && defined(CAT_ISA_X86)
CAT_ASM_BEGIN
BSR eax, [x]
CAT_ASM_END
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
u32 retval;
CAT_ASM_BEGIN
"BSRl %1, %%eax"
: "=a" (retval)
: "r" (x)
: "cc"
CAT_ASM_END
return retval;
#else
// Adapted from the Stanford Bit Twiddling Hacks collection
register u32 shift, r;
r = (x > 0xFFFF) << 4; x >>= r;
shift = (x > 0xFF) << 3; x >>= shift; r |= shift;
shift = (x > 0xF) << 2; x >>= shift; r |= shift;
shift = (x > 0x3) << 1; x >>= shift; r |= shift;
r |= (x >> 1);
return r;
#endif
}
u32 BSF64(u64 x)
{
#if defined(CAT_COMPILER_MSVC) && !defined(CAT_DEBUG) && defined(CAT_WORD_64)
u32 index;
_BitScanForward64((unsigned long*)&index, x);
return index;
#elif defined(CAT_ASM_ATT) && defined(CAT_WORD_64) && defined(CAT_ISA_X86)
u32 retval;
CAT_ASM_BEGIN
"BSFq %1, %%rax"
: "=a" (retval)
: "r" (x)
: "cc"
CAT_ASM_END
return retval;
#else
return BSR64(x ^ (x - 1));
#endif
}
u32 BSR64(u64 x)
{
#if defined(CAT_COMPILER_MSVC) && !defined(CAT_DEBUG) && defined(CAT_WORD_64)
u32 index;
_BitScanReverse64((unsigned long*)&index, x);
return index;
#elif defined(CAT_ASM_ATT) && defined(CAT_WORD_64) && defined(CAT_ISA_X86)
u32 retval;
CAT_ASM_BEGIN
"BSRq %1, %%rax"
: "=a" (retval)
: "r" (x)
: "cc"
CAT_ASM_END
return retval;
#else
// Adapted from the Stanford Bit Twiddling Hacks collection
register u32 shift, r;
r = (x > 0xFFFFFFFF) << 5; x >>= r;
shift = (x > 0xFFFF) << 4; x >>= shift; r |= shift;
shift = (x > 0xFF) << 3; x >>= shift; r |= shift;
shift = (x > 0xF) << 2; x >>= shift; r |= shift;
shift = (x > 0x3) << 1; x >>= shift; r |= shift;
r |= (u32)(x >> 1);
return r;
#endif
}
} // namespace cat
#endif // CAT_BITMATH_HPP

View File

@ -0,0 +1,196 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_LEGS_HPP
#define CAT_LEGS_HPP
#include <cat/Platform.hpp>
namespace cat {
#if defined(CAT_WORD_64)
#define CAT_LEG_BITS 64
#define CAT_USED_BITS(x) BSR64(x) /* does not work if x = 0 */
#define CAT_TRAILING_ZEROES(x) BSF64(x) /* does not work if x = 0 */
typedef u64 Leg;
typedef s64 LegSigned;
#if !defined(CAT_COMPILER_MSVC)
typedef u128 LegPair;
typedef s128 LegPairSigned;
# define CAT_LEG_PAIRMUL(A, B) ((LegPair)A * B)
#else
# define CAT_NO_LEGPAIR
#endif
// If x86-64 and MSVC
#if defined(CAT_ISA_X86) && defined(CAT_COMPILER_MSVC)
#define CAT_USE_LEGS_ASM64 /* use 64-bit assembly code inner loops */
#endif
#elif defined(CAT_WORD_32)
#define CAT_LEG_BITS 32
#define CAT_USED_BITS(x) BSR32(x) /* does not work if x = 0 */
#define CAT_TRAILING_ZEROES(x) BSF32(x) /* does not work if x = 0 */
typedef u32 Leg;
typedef s32 LegSigned;
typedef u64 LegPair;
typedef s64 LegPairSigned;
#if defined(CAT_COMPILER_MSVC)
# define CAT_LEG_PAIRMUL(A, B) __emulu(A, B) /* slightly faster in ICC */
#else
# define CAT_LEG_PAIRMUL(A, B) ((LegPair)A * B)
#endif
#endif // CAT_WORD_32
// Largest value that can be taken on by a Leg
const Leg CAT_LEG_LARGEST = ~(Leg)0;
// MSB of a leg
const Leg CAT_LEG_MSB = (Leg)1 << (CAT_LEG_BITS - 1);
#if defined(CAT_NO_LEGPAIR)
////
// Platforms that do not have LegPair (assumes 64-bit MSVC)
////
// p(hi:lo) = A * B
#define CAT_LEG_MUL(A, B, p_hi, p_lo) \
{ \
p_lo = _umul128(A, B, &p_hi); \
}
// p(hi:lo) = A * B + C
#define CAT_LEG_MULADD(A, B, C, p_hi, p_lo) \
{ \
u64 _C0 = C; \
p_lo = _umul128(A, B, &p_hi); \
p_hi += ((p_lo += _C0) < _C0); \
}
// p(hi:lo) = A * B + C + D
#define CAT_LEG_MULADD2(A, B, C, D, p_hi, p_lo) \
{ \
u64 _C0 = C, _D0 = D; \
p_lo = _umul128(A, B, &p_hi); \
p_hi += ((p_lo += _C0) < _C0); \
p_hi += ((p_lo += _D0) < _D0); \
}
// p(C2:C1:C0) = A * B + (C1:C0)
#define CAT_LEG_COMBA2(A, B, C0, C1, C2) \
{ \
u64 _p_hi, _p_lo; \
_p_lo = _umul128(A, B, &_p_hi); \
_p_hi += ((C0 += _p_lo) < _p_lo); \
C2 = ((C1 += _p_hi) < _p_hi); \
}
// p(C2:C1:C0) = A * B + (C2:C1:C0)
#define CAT_LEG_COMBA3(A, B, C0, C1, C2) \
{ \
u64 _p_hi, _p_lo; \
_p_lo = _umul128(A, B, &_p_hi); \
_p_hi += ((C0 += _p_lo) < _p_lo); \
C2 += ((C1 += _p_hi) < _p_hi); \
}
#else // has LegPair
////
// Platforms that have LegPair (assumes 32-bit MSVC or any-bit GCC)
////
// p(hi:lo) = A * B
#define CAT_LEG_MUL(A, B, p_hi, p_lo) \
{ \
LegPair _mt = CAT_LEG_PAIRMUL(A, B); \
(p_lo) = (Leg)_mt; \
(p_hi) = (Leg)(_mt >> CAT_LEG_BITS); \
}
// p(hi:lo) = A * B + C
#define CAT_LEG_MULADD(A, B, C, p_hi, p_lo) \
{ \
LegPair _mt = CAT_LEG_PAIRMUL(A, B) + (Leg)(C); \
(p_lo) = (Leg)_mt; \
(p_hi) = (Leg)(_mt >> CAT_LEG_BITS); \
}
// p(hi:lo) = A * B + C + D
#define CAT_LEG_MULADD2(A, B, C, D, p_hi, p_lo) \
{ \
LegPair _mt = CAT_LEG_PAIRMUL(A, B) + (Leg)(C) + (Leg)(D); \
(p_lo) = (Leg)_mt; \
(p_hi) = (Leg)(_mt >> CAT_LEG_BITS); \
}
// p(C2:C1:C0) = A * B + (C1:C0)
#define CAT_LEG_COMBA2(A, B, C0, C1, C2) \
{ \
LegPair _cp = CAT_LEG_PAIRMUL(A, B) + (C0); \
(C0) = (Leg)_cp; \
_cp = (_cp >> CAT_LEG_BITS) + (C1); \
(C1) = (Leg)_cp; \
(C2) = (Leg)(_cp >> CAT_LEG_BITS); \
}
// p(C2:C1:C0) = A * B + (C2:C1:C0)
#define CAT_LEG_COMBA3(A, B, C0, C1, C2) \
{ \
LegPair _cp = CAT_LEG_PAIRMUL(A, B) + (C0); \
(C0) = (Leg)_cp; \
_cp = (_cp >> CAT_LEG_BITS) + (C1); \
(C1) = (Leg)_cp; \
(C2) += (Leg)(_cp >> CAT_LEG_BITS); \
}
// Q(hi:lo) = A(hi:lo) / B
#define CAT_LEG_DIV(A_hi, A_lo, B, Q_hi, Q_lo) \
{ \
LegPair _Ax = ((LegPair)(A_hi) << CAT_LEG_BITS) | (Leg)(A_lo); \
LegPair _qt = (LegPair)(_Ax / (B)); \
(Q_hi) = (Leg)(_qt >> CAT_LEG_BITS); \
(Q_lo) = (Leg)_qt; \
}
#endif // CAT_NO_LEGPAIR
} // namespace cat
#endif // CAT_LEGS_HPP

View File

@ -0,0 +1,191 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// TODO: React to timeouts from DNS server by switching to a backup
// TODO: Use TTL from DNS record instead of fixed constant
// TODO: If the DNS resolution load is high, it would make sense to put
// multiple requests in the same DNS packet
// TODO: Retransmissions could also be grouped into the same DNS packets
// TODO: The locks held in DNSClient are fairly coarse and could be broken up
#ifndef CAT_DNS_CLIENT_HPP
#define CAT_DNS_CLIENT_HPP
#include <cat/net/ThreadPoolSockets.hpp>
#include <cat/threads/Thread.hpp>
#include <cat/threads/WaitableFlag.hpp>
#include <cat/crypt/rand/Fortuna.hpp>
#include <cat/port/FastDelegate.h>
namespace cat {
static const int HOSTNAME_MAXLEN = 63; // Max characters in a hostname request
static const int DNSREQ_TIMEOUT = 3000; // DNS request timeout interval
static const int DNSREQ_REPOST_TIME = 300; // Number of milliseconds between retries
static const int DNSREQ_MAX_SIMUL = 2048; // Maximum number of simultaneous DNS requests
static const int DNSCACHE_MAX_REQS = 8; // Maximum number of requests to cache
static const int DNSCACHE_MAX_RESP = 8; // Maximum number of responses to cache
static const int DNSCACHE_TIMEOUT = 60000; // Time until a cached response is dropped
// Prototype: bool MyResultCallback(const char *, const NetAddr*, int);
typedef fastdelegate::FastDelegate3<const char *, const NetAddr*, int, bool> DNSResultCallback;
//// DNSRequest
struct DNSCallback
{
DNSCallback *next;
DNSResultCallback cb;
ThreadRefObject *ref;
};
struct DNSRequest
{
DNSRequest *last, *next;
u32 first_post_time; // Timestamp for first post, for timeout
u32 last_post_time; // Timestamp for last post, for retries and cache
// Our copy of the hostname string
char hostname[HOSTNAME_MAXLEN+1];
u16 id; // Random request ID
DNSCallback callback_head;
// For caching purposes
NetAddr responses[DNSCACHE_MAX_RESP];
int num_responses;
};
//// DNSClient
class DNSClient : Thread, public UDPEndpoint, public Singleton<DNSClient>
{
static const int TICK_RATE = 200; // milliseconds
static const int DNS_THREAD_KILL_TIMEOUT = 10000; // 10 seconds
CAT_SINGLETON(DNSClient)
: UDPEndpoint(REFOBJ_PRIO_0+5)
{
_server_addr.Invalidate();
_dns_unavailable = true;
_cache_head = _cache_tail = 0;
_cache_size = 0;
_request_head = _request_tail = 0;
_request_queue_size = 0;
}
public:
virtual ~DNSClient();
/*
In your startup code, call Initialize() and check the return value.
In your shutdown code, call Shutdown(). This will delete the DNSClient object.
*/
bool Initialize();
void Shutdown();
/*
If hostname is numeric or in the cache, the callback function will be invoked
immediately from the requesting thread, rather than from another thread.
First attempts numerical resolve of hostname, then queries the DNS server.
Hostname string length limited to HOSTNAME_MAXLEN characters.
Caches the most recent DNSCACHE_MAX_REQS requests.
Returns up to DNSCACHE_MAX_RESP addresses per resolve request.
Performs DNS lookup on a cached request after DNSCACHE_TIMEOUT.
Gives up on DNS lookup after DNSREQ_TIMEOUT.
If holdRef is valid, the reference will be held until the callback completes.
If no results were found, array_length == 0.
If the callback returns false, the result will not be entered into the cache.
The resolved addresses may need to be promoted to IPv6.
If Resolve() returns false, no callback will be generated.
*/
bool Resolve(const char *hostname, DNSResultCallback, ThreadRefObject *holdRef = 0);
private:
NetAddr _server_addr;
volatile bool _dns_unavailable;
FortunaOutput *_csprng;
private:
Mutex _request_lock;
DNSRequest *_request_head;
DNSRequest *_request_tail;
int _request_queue_size;
bool GetUnusedID(u16 &id); // not thread-safe, caller must lock
bool IsValidHostname(const char *hostname);
DNSRequest *PullRequest(u16 id); // not thread-safe, caller must lock
private:
Mutex _cache_lock;
DNSRequest *_cache_head;
DNSRequest *_cache_tail;
int _cache_size;
// These functions do not lock, caller must lock:
void CacheAdd(DNSRequest *req); // Assumes not already in cache
DNSRequest *CacheGet(const char *hostname); // Case-insensitive
void CacheKill(DNSRequest *req); // Assumes already in cache
private:
bool GetServerAddr();
bool BindToRandomPort(bool ignoreUnreachable);
bool PostDNSPacket(DNSRequest *req, u32 now);
bool PerformLookup(DNSRequest *req); // not thread-safe, caller must lock
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &src, u8 *data, u32 bytes);
virtual void OnClose();
virtual void OnUnreachable(const NetAddr &src);
protected:
void ProcessDNSResponse(DNSRequest *req, int qdcount, int ancount, u8 *data, u32 bytes);
void NotifyRequesters(DNSRequest *req);
private:
WaitableFlag _kill_flag;
bool ThreadFunction(void *param);
};
} // namespace cat
#endif // CAT_DNS_CLIENT_HPP

View File

@ -0,0 +1,188 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_SOCKETS_HPP
#define CAT_SOCKETS_HPP
#include <cat/Platform.hpp>
#include <string>
#if defined(CAT_OS_WINDOWS)
# include <WS2tcpip.h>
#else
# include <unistd.h>
#endif
#define CAT_IP4_LOOPBACK "127.0.0.1"
#define CAT_IP6_LOOPBACK "::1"
namespace cat {
//// Data Types
#if defined(CAT_OS_WINDOWS)
typedef SOCKET Socket;
CAT_INLINE bool CloseSocket(Socket s) { return !closesocket(s); }
#else
typedef int Socket;
static const Socket INVALID_SOCKET = -1;
static const int SOCKET_ERROR = -1;
CAT_INLINE bool CloseSocket(Socket s) { return !close(s); }
#endif
typedef u16 Port;
#pragma pack(push)
#pragma pack(1)
// Wrapper for IPv4 and IPv6 addresses
class NetAddr
{
union
{
u8 v6_bytes[16];
u16 v6_words[8];
u64 v6[2];
struct {
u32 v4;
u32 v4_padding[3];
};
} _ip; // Network order
union
{
u32 _valid;
struct {
Port _port; // Host order
u16 _family; // Host order
};
};
public:
static const int IP4_BYTES = 4;
static const int IP6_BYTES = 16;
typedef sockaddr_in6 SockAddr;
public:
CAT_INLINE NetAddr() {}
NetAddr(const char *ip_str, Port port = 0);
NetAddr(const sockaddr_in6 &addr);
NetAddr(const sockaddr_in &addr);
NetAddr(const sockaddr *addr);
NetAddr(int a, int b, int c, int d, Port port = 0);
public:
NetAddr(const NetAddr &addr);
NetAddr &operator=(const NetAddr &addr);
public:
bool Wrap(const sockaddr_in6 &addr);
bool Wrap(const sockaddr_in &addr);
bool Wrap(const sockaddr *addr);
public:
// Promote an IPv4 address to an IPv6 address if needed
bool PromoteTo6();
// Demote an IPv6 address to an IPv4 address if possible,
// otherwise marks address as invalid and returns false
bool DemoteTo4();
CAT_INLINE bool Convert(bool To6) { if (To6) return PromoteTo6(); else return DemoteTo4(); }
public:
CAT_INLINE bool Valid() const { return _valid != 0; }
CAT_INLINE bool Is6() const { return _family == AF_INET6; }
CAT_INLINE const u32 GetIP4() const { return _ip.v4; }
CAT_INLINE const u64 *GetIP6() const { return _ip.v6; }
CAT_INLINE Port GetPort() const { return _port; }
CAT_INLINE void SetPort(Port port) { _port = port; }
// Mark the address as invalid
CAT_INLINE void Invalidate() { _valid = 0; }
public:
bool EqualsIPOnly(const NetAddr &addr) const;
bool operator==(const NetAddr &addr) const;
bool operator!=(const NetAddr &addr) const;
public:
// To validate external input; don't want clients connecting
// to their local network instead of the actual game server.
bool IsInternetRoutable();
// Returns true if the address is routable on local network or Internet.
// Returns false if the address is IPv4 multicast, loopback, or weird.
bool IsRoutable();
public:
bool SetFromString(const char *ip_str, Port port = 0);
std::string IPToString() const;
bool SetFromRawIP(const u8 *ip_binary, int bytes);
bool SetFromDotDecimals(int a, int b, int c, int d, Port port = 0);
public:
bool Unwrap(SockAddr &addr, int &addr_len, bool PromoteToIP6 = false) const;
};
#pragma pack(pop)
//// Helper Functions
// Run startup and cleanup functions needed under some OS
bool StartupSockets(); // returns false on error
void CleanupSockets();
// inout_OnlyIPv4: Indicates that only IPv4 is requested by caller
// Sets OnlyIPv4 if IPv6 will be unsupported
// Returns true on success
bool CreateSocket(int type, int protocol, bool SupportIPv4, Socket &out_s, bool &inout_OnlyIPv4);
// Returns true on success
bool NetBind(Socket s, Port port, bool OnlyIPv4);
// Returns 0 on failure
Port GetBoundPort(Socket s);
//// Error Codes
// Returns a string describing the last error from Winsock2 API
std::string SocketGetLastErrorString();
std::string SocketGetErrorString(int code);
} // namespace cat
#endif // CAT_SOCKETS_HPP

View File

@ -0,0 +1,116 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_SPHYNX_CLIENT_HPP
#define CAT_SPHYNX_CLIENT_HPP
#include <cat/net/SphynxTransport.hpp>
#include <cat/crypt/tunnel/KeyAgreementInitiator.hpp>
#include <cat/threads/Thread.hpp>
#include <cat/threads/WaitableFlag.hpp>
namespace cat {
namespace sphynx {
//// sphynx::Client
class Client : Thread, public UDPEndpoint, public Transport
{
static const int HANDSHAKE_TICK_RATE = 100; // milliseconds
static const int INITIAL_HELLO_POST_INTERVAL = 200; // milliseconds
static const int CONNECT_TIMEOUT = 6000; // milliseconds
static const u32 MTU_PROBE_INTERVAL = 8000; // 8 seconds
static const int CLIENT_THREAD_KILL_TIMEOUT = 10000; // 10 seconds
static const int SESSION_KEY_BYTES = 32;
char _session_key[SESSION_KEY_BYTES];
KeyAgreementInitiator _key_agreement_initiator;
u8 _server_public_key[PUBLIC_KEY_BYTES];
u8 _cached_challenge[CHALLENGE_BYTES];
WaitableFlag _kill_flag;
protected:
u32 _last_send_mstsc;
NetAddr _server_addr;
bool _connected;
AuthenticatedEncryption _auth_enc;
// Last time a packet was received from the server -- for disconnect timeouts
u32 _last_recv_tsc;
public:
Client();
virtual ~Client();
bool SetServerKey(ThreadPoolLocalStorage *tls, const void *server_key, int key_bytes, const char *session_key);
bool Connect(const char *hostname, Port port);
bool Connect(const NetAddr &addr);
void Disconnect();
protected:
bool IsConnected() { return _connected; }
virtual void OnClose() = 0;
virtual void OnConnectFail() = 0;
virtual void OnConnect(ThreadPoolLocalStorage *tls) = 0;
virtual void OnTimestampDeltaUpdate(u32 rtt, s32 delta) {}
virtual void OnMessage(ThreadPoolLocalStorage *tls, BufferStream msg, u32 bytes) = 0;
virtual void OnDisconnect() = 0;
virtual void OnTick(ThreadPoolLocalStorage *tls, u32 now) = 0;
private:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &src, u8 *data, u32 bytes);
virtual void OnWrite(u32 bytes);
private:
bool PostHello();
void OnUnreachable(const NetAddr &src);
// Return false to remove resolve from cache
bool OnResolve(const char *hostname, const NetAddr *array, int array_length);
virtual bool PostPacket(u8 *buffer, u32 buf_bytes, u32 msg_bytes, u32 skip_bytes);
private:
bool ThreadFunction(void *param);
};
} // namespace sphynx
} // namespace cat
#endif // CAT_SPHYNX_CLIENT_HPP

View File

@ -0,0 +1,706 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_SPHYNX_COLLEXION_HPP
#define CAT_SPHYNX_COLLEXION_HPP
#include <cat/threads/Mutex.hpp>
#include <cat/threads/RegionAllocator.hpp>
#include <cat/net/SphynxTransport.hpp>
namespace cat {
namespace sphynx {
/*
The purpose of sphynx::Collexion and sphynx::CollexionIterator is to
store lists of Connexion object references and iterate through them.
Since the number of clients may be in the thousands, I feel it is
important to scale effectively. So in the Collexion data structure,
insertion and removal are O(1) operations. Also locks should be held
for the smallest amount of time possible, so I have taken care to make
locks short and reduce the amount of locking. For example, the iterator
caches large blocks of data instead of locking for each iteration.
The design is optimized for cache usage, re-using common code to benefit
from code cache and allocating and accessing table entries on cache line
boundaries to double memory performance over a naive approach.
*/
//// sphynx::Collexion
template<class T>
class CollexionIterator;
template<class T>
struct CollexionElement
{
// Number of active enumerators using this element
// If references are held it cannot be deleted
// so the KILL flag is set on the 'next' member and
// the final enumerator to reduce the reference count
// to zero is responsible for removal.
u32 refcnt;
// Bitfield:
// 1 bit: COLLISION FLAG
// 1 bit: KILL FLAG
// 30 bits: Table index to next element in list + 1
u32 next;
// Data at this table element
T *conn;
};
struct CollexionElement2
{
// Previous table element in list + 1
u32 last;
// Hash of data pointer from main entry (so it doesn't need to be recalculated during growth)
u32 hash;
};
template<class T>
class Collexion
{
static const u32 COLLIDE_MASK = 0x80000000;
static const u32 KILL_MASK = 0x40000000;
static const u32 NEXT_MASK = 0x3fffffff;
static const u32 MIN_ALLOCATED = 32;
private:
// Number of used table elements
u32 _used;
// Number of allocated table elements
u32 _allocated;
// First table index in list of active elements
u32 _first;
// Primary table
CollexionElement<T> *_table;
// Secondary table, split off so that primary table elements will
// fit on a cache line. Contains data that is only accessed rarely.
CollexionElement2 *_table2;
// Table lock
Mutex _lock;
protected:
// Attempt to double size of hash table (does not hold lock)
bool DoubleTable();
// Hash a pointer to a 32-bit table key
static CAT_INLINE u32 HashPtr(T *ptr)
{
u64 key = 0xBADdecafDEADbeef;
#if defined(CAT_WORD_64)
key ^= *(u64*)&ptr;
#else
key ^= *(u32*)&ptr;
#endif
key = (~key) + (key << 18);
key = key ^ (key >> 31);
key = key * 21;
key = key ^ (key >> 11);
key = key + (key << 6);
key = key ^ (key >> 22);
return (u32)key;
}
// Common functions shared by interface for good code cache usage:
// Unlink a table key
void Unlink(u32 key);
// Fill an iterator with the next set of data
// Returns false if no data remains to fill
void Fill(CollexionIterator<T> &iter, u32 first);
// Find a hash table key based on data
u32 Find(T *conn);
public:
// Ctor zeros everything
Collexion()
{
_first = 0;
_used = 0;
_allocated = 0;
_table = 0;
_table2 = 0;
}
// Dtor releases dangling memory
~Collexion();
// Returns true if table is empty
CAT_INLINE bool IsEmpty() { return _used == 0; }
// Insert Connexion object, return false if already present or out of memory
bool Insert(T *conn);
// Remove Connexion object from list if it exists
bool Remove(T *conn);
// Begin iterating through list
void Begin(CollexionIterator<T> &iter);
// Iterate
void Next(CollexionIterator<T> &iter, bool refill = true);
};
//// sphynx::CollexionIterator
template<class T>
class CollexionIterator
{
friend class Collexion<T>;
static const u32 MAX_CACHE = 256;
// Parent Collexion object
Collexion<T> *_parent;
// First and last hash table indices in parent
u32 _first, _last;
// Stores the size of the parent when snapshot was taken,
// will invalidate _first and _last if table changed size
u32 _prev_allocated;
// Connexion object cache, to avoid locking and unlocking a lot
T *_cache[MAX_CACHE];
// Offset into cache and total elements in cache
// Will grab another cache once offset reaches total
u32 _offset, _total;
public:
// Smart pointer -style accessors
CAT_INLINE T *Get() throw() { return _cache[_offset]; }
CAT_INLINE T *operator->() throw() { return _cache[_offset]; }
CAT_INLINE T &operator*() throw() { return *_cache[_offset]; }
CAT_INLINE operator T*() { return _cache[_offset]; }
public:
// Ctor: Grabs first cache of Connexions
CollexionIterator(Collexion<T> &begin);
// Dtor: Calls Release()
~CollexionIterator();
// Iterate to next Connexion object in list
CollexionIterator &operator++();
// Releases reference to any outstanding Connexions
void Release();
};
//// sphynx::Collexion
template<class T>
bool Collexion<T>::DoubleTable()
{
u32 new_allocated = _allocated << 1;
if (new_allocated < MIN_ALLOCATED) new_allocated = MIN_ALLOCATED;
// Allocate secondary table
u32 new_bytes2 = sizeof(CollexionElement2) * new_allocated;
CollexionElement2 *new_table2 = reinterpret_cast<CollexionElement2*>(
RegionAllocator::ii->Acquire(new_bytes2) );
if (!new_table2) return false;
// Allocate primary table
u32 new_bytes = sizeof(CollexionElement<T>) * new_allocated;
CollexionElement<T> *new_table = reinterpret_cast<CollexionElement<T> *>(
RegionAllocator::ii->Acquire(new_bytes) );
if (!new_table)
{
RegionAllocator::ii->Release(new_table2);
return false;
}
CAT_CLR(new_table, new_bytes);
u32 new_first = 0;
if (_table && _table2)
{
// For each entry in the old table,
u32 ii = _first, mask = _allocated - 1;
while (ii)
{
--ii;
CollexionElement<T> *oe = &_table[ii];
u32 hash = _table2[ii].hash;
u32 key = hash & mask;
// While collisions occur,
while (new_table[key].conn)
{
// Mark collision
new_table[key].next |= COLLIDE_MASK;
// Walk collision list
key = (key * COLLISION_MULTIPLIER + COLLISION_INCREMENTER) & mask;
}
// Fill new table element
new_table[key].conn = oe->conn;
new_table2[key].hash = hash;
// new_table[key].refcnt is already zero
// Link new element to new list
if (new_first)
{
new_table[key].next |= new_first;
new_table2[new_first - 1].last = key;
}
// new_table[key].next is already zero so no need to zero it here
new_first = key + 1;
// Get next old table entry
ii = oe->next & NEXT_MASK;
}
// Zero head->last
new_table2[new_first - 1].last = 0;
}
// Resulting linked list starting with _first-1 will extend until e->next == 0
if (_table2) RegionAllocator::ii->Release(_table2);
if (_table) RegionAllocator::ii->Release(_table);
_table = new_table;
_table2 = new_table2;
_allocated = new_allocated;
_first = new_first;
return true;
}
template<class T>
Collexion<T>::~Collexion()
{
if (_table2)
{
RegionAllocator::ii->Release(_table2);
}
// If table doesn't exist, return
if (!_table) return;
// For each allocated table entry,
for (u32 ii = 0; ii < _allocated; ++ii)
{
// Get Connexion object
T *conn = _table[ii].conn;
// If object is valid, release it
if (conn) conn->ReleaseRef();
}
// Release table memory
RegionAllocator::ii->Release(_table);
}
template<class T>
bool Collexion<T>::Insert(T *conn)
{
u32 hash = HashPtr(conn);
conn->AddRef();
AutoMutex lock(_lock);
// If more than half of the table will be used,
if (_used >= (_allocated >> 1))
{
// Double the size of the table (O(1) allocation pattern)
// Growing pains are softened by careful design
if (!DoubleTable())
{
// On growth failure, return false
lock.Release();
conn->ReleaseRef();
return false;
}
}
// Mask off high bits to make table key from hash
u32 mask = _allocated - 1;
u32 key = hash & mask;
// While empty table entry not found,
while (_table[key].conn)
{
// If Connexion object is already in the table,
if (_table[key].conn == conn)
{
// Return false on duplicate
lock.Release();
conn->ReleaseRef();
return false;
}
// Mark as a collision
_table[key].next |= COLLIDE_MASK;
// Walk collision list
key = (key * COLLISION_MULTIPLIER + COLLISION_INCREMENTER) & mask;
}
// Fill new element
_table[key].conn = conn;
_table[key].refcnt = 0;
_table2[key].hash = hash;
_table2[key].last = 0;
// Link new element to front of list
if (_first) _table2[_first - 1].last = key + 1;
_table[key].next = (_table[key].next & COLLIDE_MASK) | _first;
_first = key + 1;
++_used;
return true;
}
template<class T>
void Collexion<T>::Unlink(u32 key)
{
// Clear reference
_table[key].conn = 0;
// Unlink from active list
u32 next = _table[key].next & NEXT_MASK;
u32 last = _table2[key].last;
if (last) _table[last-1].next = (_table[last-1].next & ~NEXT_MASK) | next;
else _first = next;
if (next) _table2[next-1].last = last;
// If this key was a leaf on a collision wind,
if (!(_table[key].next & COLLIDE_MASK))
{
u32 mask = _allocated - 1;
do
{
// Go backwards through the collision list one step
key = ((key + COLLISION_INCRINVERSE) * COLLISION_MULTINVERSE) & mask;
// Stop where collision list stops
if (!(_table[key].next & COLLIDE_MASK))
break;
// Turn off collision key for previous entry
_table[key].next &= ~COLLIDE_MASK;
} while (!_table[key].conn);
}
// Update number of used elements
--_used;
}
template<class T>
bool Collexion<T>::Remove(T *conn)
{
u32 hash = HashPtr(conn);
AutoMutex lock(_lock);
// If table doesn't exist,
if (!_allocated) return false;
// Mask off high bits to make table key from hash
u32 mask = _allocated - 1;
u32 key = hash & mask;
// While target table entry not found,
for (;;)
{
// If target was found,
if (_table[key].conn == conn)
{
if (_table[key].refcnt)
{
// Mark it killed so iterator can clean it up when it's finished
_table[key].next |= KILL_MASK;
}
else
{
Unlink(key);
lock.Release();
conn->ReleaseRef();
}
// Return success
return true;
}
if (!(_table[key].next & COLLIDE_MASK))
{
break; // End of collision list
}
// Walk collision list
key = (key * COLLISION_MULTIPLIER + COLLISION_INCREMENTER) & mask;
}
// Return failure: not found
return false;
}
template<class T>
void Collexion<T>::Fill(CollexionIterator<T> &iter, u32 first)
{
u32 key = first;
// Find first list element that does not want to die
while (key && (_table[key-1].next & KILL_MASK))
{
// Go to next
key = _table[key-1].next & NEXT_MASK;
}
iter._offset = 0;
// If no elements in table,
if (!key)
{
// Return empty set
iter._cache[0] = 0;
iter._total = 0;
iter._first = 0;
iter._last = 0;
return;
}
// Remember size of hash table in case it grows before iterator is done
iter._prev_allocated = _allocated;
// Remember first key for next iteration
iter._first = key;
// For each of the first MAX_CACHE elements in the table, copy the data pointer to cache
u32 ii = 0, final = 0;
do
{
// If element does not want to die,
if (!(_table[key-1].next & KILL_MASK))
{
// Copy data pointer
iter._cache[ii] = _table[key-1].conn;
// Increment reference count for element
_table[key-1].refcnt++;
// Remember key as the next iteration starting point
final = key;
// Check if copy is complete
if (++ii >= CollexionIterator<T>::MAX_CACHE) break;
}
// Go to next key
key = _table[key-1].next & NEXT_MASK;
} while (key);
// Record number of elements written
iter._total = ii;
// Remember next key for next iteration
iter._last = final;
}
template<class T>
void Collexion<T>::Begin(CollexionIterator<T> &iter)
{
iter._parent = this;
AutoMutex lock(_lock);
Fill(iter, _first);
}
// Find a hash table key based on data
template<class T>
u32 Collexion<T>::Find(T *conn)
{
u32 mask = _allocated - 1;
u32 key = HashPtr(conn) & mask;
// Find the object in the collision list starting at the expected location
while (_table[key].conn != conn)
{
// If at the end of the collision list,
if (!(_table[key].next & COLLIDE_MASK))
break; // Should never happen
// Walk collision list
key = (key * COLLISION_MULTIPLIER + COLLISION_INCREMENTER) & mask;
}
return key;
}
template<class T>
void Collexion<T>::Next(CollexionIterator<T> &iter, bool refill)
{
T *release_list[CollexionIterator<T>::MAX_CACHE];
u32 release_ii = 0;
u32 key = iter._first;
u32 last = iter._last;
// If iteration is done,
if (!key) return;
AutoMutex lock(_lock);
// If hash table changed size (rare),
if (iter._prev_allocated != _allocated)
{
// iter._first and iter._last are invalid
// ...but we can find them again based on the cached pointers!
key = Find(iter._cache[0]) + 1;
last = Find(iter._cache[iter._total - 1]) + 1;
}
last = _table[last-1].next & NEXT_MASK;
// Release any table elements that want to die now
do
{
u32 flags = _table[key-1].next;
// If reference count is now zero for this element,
if (0 == --_table[key-1].refcnt)
{
// If element wants to die,
if (flags & KILL_MASK)
{
// Prepare to release data after lock is released
release_list[release_ii++] = _table[key-1].conn;
Unlink(key-1);
}
}
key = flags & NEXT_MASK;
} while (key != last);
// Fill iterator starting with next key
if (refill) Fill(iter, key);
lock.Release();
if (!refill)
{
// Return empty set
iter._cache[0] = 0;
iter._total = 0;
iter._offset = 0;
iter._first = 0;
iter._last = 0;
}
// Release data awaiting destruction
for (u32 ii = 0; ii < release_ii; ++ii)
{
release_list[ii]->ReleaseRef();
}
}
//// sphynx::CollexionIterator
template<class T>
CollexionIterator<T>::CollexionIterator(Collexion<T> &begin)
{
begin.Begin(*this);
}
template<class T>
CollexionIterator<T>::~CollexionIterator()
{
Release();
}
template<class T>
CollexionIterator<T> &CollexionIterator<T>::operator++()
{
if (++_offset >= _total)
{
_parent->Next(*this, true);
}
return *this;
}
template<class T>
void CollexionIterator<T>::Release()
{
if (_parent)
{
_parent->Next(*this, false);
_parent = 0;
}
}
} // namespace sphynx
} // namespace cat
#endif // CAT_SPHYNX_COLLEXION_HPP

View File

@ -0,0 +1,300 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_SPHYNX_SERVER_HPP
#define CAT_SPHYNX_SERVER_HPP
#include <cat/net/SphynxTransport.hpp>
#include <cat/threads/RWLock.hpp>
#include <cat/threads/Thread.hpp>
#include <cat/threads/WaitableFlag.hpp>
#include <cat/net/SphynxCollexion.hpp>
#include <cat/crypt/cookie/CookieJar.hpp>
#include <cat/crypt/tunnel/KeyAgreementResponder.hpp>
namespace cat {
namespace sphynx {
/*
Designed for server hardware with many processors.
In order to handle many users, the Sphynx server opens up a single UDP port
to accept new connections, and several other UDP data ports for data.
For retransmissions and detecting link loss due to timeout, the server runs
several additional threads that wake up periodically to perform timed tasks.
Server uses thread pool to receive packets on connect and worker ports,
meaning that packets are processed by any free CPU as soon as they arrive.
Sphynx Server
UDP Hello Port [1]
+ In case this thread spins constantly, only use one CPU for new
connections since in-game experience is more important than login
+ Assigns users to a data port after handshake completes
UDP Data Ports [4 * (CPU Count)]
+ Spread users evenly across several ports since
only one packet can be processed from a single port at a time
+ Any free CPU will process incoming packets as fast as possible
ServerTimer threads [(CPU Count) / 2]
+ In case these threads spin constantly, they only consume
half of the CPU resources available
+ Wake up every X milliseconds according to Transport::TICK_RATE
+ Detect link loss due to silence timeout
+ Update transport layer
+ Retransmit lost messages
+ Re-evaluate bandwidth and transmit queued messages
*/
//// sphynx::Connexion
// Derive from sphynx::Connexion and sphynx::Server to define server behavior
class Connexion : public Transport, public ThreadRefObject
{
friend class Server;
friend class Map;
friend class ServerWorker;
friend class ServerTimer;
public:
Connexion();
virtual ~Connexion() {}
private:
volatile u32 _destroyed;
u32 _key; // Map hash table index, unique for each active connection
Connexion *_next_delete;
ServerWorker *_server_worker;
u8 _first_challenge[64]; // First challenge seen from this client address
u8 _cached_answer[128]; // Cached answer to this first challenge, to avoid eating server CPU time
private:
// Return false to destroy this object
bool Tick(ThreadPoolLocalStorage *tls, u32 now);
void OnRawData(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes);
virtual bool PostPacket(u8 *buffer, u32 buf_bytes, u32 msg_bytes, u32 skip_bytes);
public:
CAT_INLINE bool IsValid() { return _destroyed == 0; }
CAT_INLINE u32 GetKey() { return _key; }
void Destroy();
protected:
NetAddr _client_addr;
// Last time a packet was received from this user -- for disconnect timeouts
u32 _last_recv_tsc;
bool _seen_encrypted;
AuthenticatedEncryption _auth_enc;
protected:
virtual void OnConnect(ThreadPoolLocalStorage *tls) = 0;
virtual void OnDestroy() = 0;
virtual void OnTick(ThreadPoolLocalStorage *tls, u32 now) = 0;
};
//// sphynx::Map
class Map
{
protected:
CAT_INLINE u32 hash_addr(const NetAddr &addr, u32 salt);
public:
struct Slot
{
Connexion *connection;
bool collision;
Slot *next;
};
protected:
u32 _hash_salt;
CAT_ALIGNED(16) Slot _table[HASH_TABLE_SIZE];
RWLock _table_lock;
public:
Map();
virtual ~Map();
// Lookup client by address
Connexion *Lookup(const NetAddr &addr);
// Lookup client by key
Connexion *Lookup(u32 key);
// May return false if network address in Connexion is already in the map.
// This averts a potential race condition but should never happen during
// normal operation, so the Connexion allocation by caller won't be wasted.
bool Insert(Connexion *conn);
// Destroy a list described by the 'next' member of Slot
void DestroyList(Map::Slot *kill_list);
void Tick(ThreadPoolLocalStorage *tls);
};
//// sphynx::ServerWorker
class ServerWorker : public UDPEndpoint
{
friend class Map;
protected:
Map *_conn_map;
ServerTimer *_server_timer;
protected:
volatile u32 _session_count;
public:
ServerWorker(Map *conn_map, ServerTimer *server_timer);
virtual ~ServerWorker();
void IncrementPopulation();
void DecrementPopulation();
u32 GetPopulation() { return _session_count; }
protected:
void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &src, u8 *data, u32 bytes);
void OnWrite(u32 bytes) {}
void OnClose();
};
//// sphynx::ServerTimer
class ServerTimer : Thread
{
protected:
Map *_conn_map;
protected:
ServerWorker **_workers;
int _worker_count;
protected:
Map::Slot *_insert_head;
Mutex _insert_lock;
protected:
Map::Slot *_active_head;
public:
ServerTimer(Map *conn_map, ServerWorker **workers, int worker_count);
virtual ~ServerTimer();
CAT_INLINE bool Valid() { return _worker_count > 0; }
public:
void InsertSlot(Map::Slot *slot);
protected:
CAT_INLINE void Tick(ThreadPoolLocalStorage *tls);
bool ThreadFunction(void *param);
protected:
static const int TIMER_THREAD_KILL_TIMEOUT = 10000;
WaitableFlag _kill_flag;
};
//// sphynx::Server
class Server : public UDPEndpoint
{
public:
Server();
virtual ~Server();
bool StartServer(ThreadPoolLocalStorage *tls, Port port, u8 *public_key, int public_bytes, u8 *private_key, int private_bytes, const char *session_key);
u32 GetTotalPopulation();
static bool GenerateKeyPair(ThreadPoolLocalStorage *tls, const char *public_key_file,
const char *private_key_file, u8 *public_key,
int public_bytes, u8 *private_key, int private_bytes);
private:
static const int SESSION_KEY_BYTES = 32;
char _session_key[SESSION_KEY_BYTES];
Port _server_port;
Map _conn_map;
CookieJar _cookie_jar;
KeyAgreementResponder _key_agreement_responder;
u8 _public_key[PUBLIC_KEY_BYTES];
static const int WORKER_LIMIT = 32; // Maximum number of workers
ServerWorker **_workers;
int _worker_count;
ServerTimer **_timers;
int _timer_count;
private:
ServerWorker *FindLeastPopulatedPort();
void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &src, u8 *data, u32 bytes);
void OnWrite(u32 bytes);
void OnClose();
protected:
// Must return a new instance of your Connexion derivation
virtual Connexion *NewConnexion() = 0;
// IP address filter: Return true to allow the connection to be made
virtual bool AcceptNewConnexion(const NetAddr &src) = 0;
// Lookup client by key
Connexion *Lookup(u32 key);
};
} // namespace sphynx
} // namespace cat
#endif // CAT_SPHYNX_SERVER_HPP

View File

@ -0,0 +1,455 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_SPHYNX_TRANSPORT_HPP
#define CAT_SPHYNX_TRANSPORT_HPP
#include <cat/net/ThreadPoolSockets.hpp>
#include <cat/threads/Mutex.hpp>
#include <cat/crypt/tunnel/AuthenticatedEncryption.hpp>
#include <cat/parse/BufferStream.hpp>
namespace cat {
namespace sphynx {
/*
Based on what I have envisioned needing for my game, the following protocol is being
used after spending weeks looking at alternatives and false-starts. It provides signaled
disconnects, fragmentation, MTU discovery, time synchronization, three reliable ordered
streams, one unordered reliable stream, and unreliable delivery.
The Transport object that implements a sender/receiver in the protocol requires 276 bytes
of memory per server connection, plus 32 bytes per message fragment in flight, plus buffers
for queued send/recv packets, and it keeps two mutexes for thread-safety. A lockless memory
allocator is used to allocate all buffers except the fragmented message reassembly buffer.
Packet format on top of UDP header:
E { HDR(2 bytes)|ACK-ID(3 bytes)|DATA || ... || MAC(8 bytes) } || IV(3 bytes)
E: ChaCha-12 stream cipher.
IV: Initialization vector used by security layer (Randomly initialized).
MAC: Message authentication code used by security layer (HMAC-MD5).
HDR|ACK-ID|DATA: A message block inside the datagram. The HDR and ACK-ID
fields employ compression to use as little as 1 byte together.
Each message follows the same format. A two-byte header followed by data:
--- Message Header (16 bits) ---
0 1 2 3 4 5 6 7 8 9 a b c d e f
<-- LSB ----------------- MSB -->
| BHI |I|R| SOP | BLO |
---------------------------------
DATA_BYTES: BHI | BLO = Number of bytes in data part of message.
If BHI = "111"b, the BLO byte is omitted and the receiver can
assume that the rest of the packet contains just one message.
I: 1=Followed by ACK-ID field. 0=ACK-ID is one higher than the last.
R: 1=Reliable. 0=Unreliable.
SOP: Super opcodes:
0=Data (reliable or unreliable)
1=Fragment (reliable)
2=ACK (unreliable)
3=MTU Probe (unreliable)
4=MTU Set (unordered reliable)
5=Time Ping (unreliable)
6=Time Pong (unreliable)
7=Disconnect (unreliable)
When the I bit is set, the data part is preceded by an ACK-ID,
which is then applied to all following reliable messages.
This additional size is NOT accounted for in the DATA_BYTES field.
When the FRAG opcode used for the first time in an ordered stream,
the data part begins with a 16-bit Fragment Header.
This additional size IS accounted for in the DATA_BYTES field.
Often times there is just one message in a datagram. To compress
the header in this case, when BHI = 7 the receiver assumes that
only one message is in the packet and uses the payload length to
determine the length of the single message. BLO byte is omitted.
This *could* also be used on the final message in a cluster,
but it cannot be done without a memcpy to cover up the extra
header byte, which I don't consider worthwhile...
------------- ACK-ID Field (24 bits) ------------
0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7
<-- LSB --------------------------------- MSB -->
| S | IDA (5) |C| IDB (7) |C| IDC (8) |
-------------------------------------------------
C: 1=Continues to next byte.
S: 0=Unordered stream, 1-3: Ordered streams.
ID: IDC | IDB | IDA (20 bits)
On retransmission, the ACK-ID field uses no compression
since the receiver state cannot be determined.
--- Fragment Header (16 bits) ---
0 1 2 3 4 5 6 7 8 9 a b c d e f
<-- LSB ----------------- MSB -->
| TOTAL_BYTES(16) |
---------------------------------
TOTAL_BYTES: Total bytes in data part of fragmented message,
not including this header.
*/
/*
ACK message format:
Header: I=0, R=0, SOP=SOP_ACK
Data: ROLLUP(3) || RANGE1 || RANGE2 || ... ROLLUP(3) || RANGE1 || RANGE2 || ...
ROLLUP = Next expected ACK-ID. Acknowledges every ID before this one.
RANGE1:
START || END
START = First inclusive ACK-ID in a range to acknowledge.
END = Final inclusive ACK-ID in a range to acknowledge.
Negative acknowledgment can be inferred from the holes in the RANGEs.
------------ ROLLUP Field (24 bits) -------------
0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7
<-- LSB --------------------------------- MSB -->
|1| S | IDA (5) | IDB (8) | IDC (8) |
-------------------------------------------------
1: Indicates start of ROLLUP field.
S: 0=Unordered stream, 1-3: Ordered streams.
ID: IDC | IDB | IDA (21 bits)
ROLLUP is always 3 bytes since we cannot tell how far ahead the remote host is now.
--------- RANGE START Field (24 bits) -----------
0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7
<-- LSB --------------------------------- MSB -->
|0|E| IDA (5) |C| IDB (7) |C| IDC (8) |
-------------------------------------------------
0: Indicates start of RANGE field.
C: 1=Continues to next byte.
E: 1=Has end field. 0=One ID in range.
ID: IDC | IDB | IDA (20 bits) + last ack id in message
---------- RANGE END Field (24 bits) ------------
0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7
<-- LSB --------------------------------- MSB -->
| IDA (7) |C| IDB (7) |C| IDC (8) |
-------------------------------------------------
C: 1=Continues to next byte.
ID: IDC | IDB | IDA (22 bits) + START.ID
*/
class Connexion;
class Map;
class Server;
class ServerWorker;
class ServerTimer;
class Client;
class Transport;
#if defined(CAT_WORD_32)
#define CAT_PACK_TRANSPORT_STATE_STRUCTURES /* For 32-bit version, this allows fragments to fit in 32 bytes */
#else // 64-bit version:
//#define CAT_PACK_TRANSPORT_STATE_STRUCTURES /* No advantage for 64-bit version */
#endif
//#define CAT_TRANSPORT_DEBUG_LOGGING /* Enables info messages on console */
#define CAT_VERBOSE_VALIDATION /* Enables input error messages on console */
// Protocol constants
static const u32 PROTOCOL_MAGIC = 0xC47D0001;
static const int PUBLIC_KEY_BYTES = 64;
static const int PRIVATE_KEY_BYTES = 32;
static const int CHALLENGE_BYTES = PUBLIC_KEY_BYTES;
static const int ANSWER_BYTES = PUBLIC_KEY_BYTES*2;
static const int HASH_TABLE_SIZE = 32768; // Power-of-2
static const int HASH_TABLE_MASK = HASH_TABLE_SIZE - 1;
static const int MAX_POPULATION = HASH_TABLE_SIZE / 2;
// (multiplier-1) divisible by all prime factors of table size
// (multiplier-1) is a multiple of 4 if table size is a multiple of 4
// These constants are from Press, Teukolsky, Vetterling and Flannery's
// "Numerical Recipes in FORTRAN: The Art of Scientific Computing"
static const u32 COLLISION_MULTIPLIER = 71*5861 * 4 + 1;
static const u32 COLLISION_INCREMENTER = 1013904223;
// If multiplier changes, this needs to be recalculated (multiplicative inverse of above)
static const u32 COLLISION_MULTINVERSE = 4276115653;
static const u32 COLLISION_INCRINVERSE = 0 - COLLISION_INCREMENTER;
// Handshake types
enum HandshakeType
{
C2S_HELLO,
S2C_COOKIE,
C2S_CHALLENGE,
S2C_ANSWER,
S2C_ERROR
};
// Handshake errors
enum HandshakeError
{
ERR_SERVER_FULL
};
// Stream modes
enum StreamMode
{
STREAM_UNORDERED = 0, // Reliable, unordered stream 0
STREAM_1 = 1, // Reliable, ordered stream 1
STREAM_2 = 2, // Reliable, ordered stream 2
STREAM_3 = 3 // Reliable, ordered stream 3
};
// Super Opcodes
enum SuperOpcode
{
SOP_DATA, // 0=Data (reliable or unreliable)
SOP_FRAG, // 1=Fragment (reliable)
SOP_ACK, // 2=ACK (unreliable)
SOP_MTU_PROBE, // 3=MTU Probe (unreliable)
SOP_MTU_SET, // 4=MTU Set (unordered reliable)
SOP_TIME_PING, // 5=Time Ping (unreliable)
SOP_TIME_PONG, // 6=Time Pong (unreliable)
SOP_DISCO, // 7=Disconnect (unreliable)
};
//// sphynx::Transport
#if defined(CAT_PACK_TRANSPORT_STATE_STRUCTURES)
#pragma pack(push)
#pragma pack(1)
#endif // CAT_PACK_TRANSPORT_STATE_STRUCTURES
// Receive state: Receive queue
struct RecvQueue
{
static const u32 FRAG_FLAG = 0x80000000;
static const u32 BYTE_MASK = 0x7fffffff;
RecvQueue *next; // Next in queue
RecvQueue *prev; // Previous in queue
u32 id; // Acknowledgment id
u32 bytes; // High bit: Fragment?
// Message contents follow
};
// Send state: Send queue
struct SendQueue
{
SendQueue *next; // Next in queue
SendQueue *prev; // Previous in queue
u32 ts_firstsend; // Millisecond-resolution timestamp when it was first sent
u32 ts_lastsend; // Millisecond-resolution timestamp when it was last sent
union
{
u32 sent_bytes; // In send queue: Number of sent bytes while fragmenting a large message
u32 id; // In sent list: Acknowledgment id
};
u16 bytes; // Data bytes
u16 frag_count; // Number of fragments remaining to be delivered
u16 sop; // Super opcode of message
// Message contents follow
};
struct SendFrag : public SendQueue
{
SendQueue *full_data; // Object containing message data
u16 offset; // Fragment data offset
};
// Temporary send node structure, nestled in the encryption overhead of outgoing packets
struct TempSendNode // Size <= 11 bytes = AuthenticatedEncryption::OVERHEAD_BYTES
{
static const u32 SINGLE_FLAG = 0x8000;
static const u32 BYTE_MASK = 0x7fff;
TempSendNode *next;
u16 negative_offset; // Number of bytes before this structure, and single flag
};
#if defined(CAT_PACK_TRANSPORT_STATE_STRUCTURES)
#pragma pack(pop)
#endif // CAT_PACK_TRANSPORT_STATE_STRUCTURES
class Transport
{
protected:
static const u8 BHI_MASK = 7;
static const u8 BHI_SINGLE_MESSAGE = 7;
static const u8 I_MASK = 1 << 3;
static const u8 R_MASK = 1 << 4;
static const u32 SOP_SHIFT = 5;
static const u32 NUM_STREAMS = 4; // Number of reliable streams
static const u32 MIN_RTT = 50; // Minimum milliseconds for RTT
static const int TIMEOUT_DISCONNECT = 15000; // 15 seconds
static const int SILENCE_LIMIT = 9333; // 9.333 seconds: Time silent before sending a keep-alive (0-length unordered reliable message)
static const int TICK_RATE = 20; // 20 milliseconds
static const u32 MINIMUM_MTU = 576; // Dialup
static const u32 MEDIUM_MTU = 1400; // Highspeed with unexpected overhead, maybe VPN
static const u32 MAXIMUM_MTU = 1500; // Highspeed
static const u32 IPV6_OPTIONS_BYTES = 40; // TODO: Not sure about this
static const u32 IPV6_HEADER_BYTES = 40 + IPV6_OPTIONS_BYTES;
static const u32 IPV4_OPTIONS_BYTES = 40;
static const u32 IPV4_HEADER_BYTES = 20 + IPV4_OPTIONS_BYTES;
static const u32 UDP_HEADER_BYTES = 8;
static const u32 FRAG_THRESHOLD = 32; // Fragment if FRAG_THRESHOLD bytes would be in each fragment
static const u32 MAX_MESSAGE_DATALEN = 65535-1; // Maximum number of bytes in the data part of a message (-1 for the opcode)
protected:
// Maximum transfer unit (MTU) in UDP payload bytes, excluding the IP and UDP headers and encryption overhead
u32 _max_payload_bytes;
public:
void InitializePayloadBytes(bool ip6);
protected:
// Receive state: Next expected ack id to receive
u32 _next_recv_expected_id[NUM_STREAMS];
// Receive state: Synchronization objects
volatile bool _got_reliable[NUM_STREAMS];
Mutex _recv_lock; // Just needs to protect writes OnDatagram() from messing up reads on tick
// Receive state: Fragmentation
u8 *_fragment_buffer[NUM_STREAMS]; // Buffer for accumulating fragment
u32 _fragment_length[NUM_STREAMS]; // Number of bytes in fragment buffer
u32 _fragment_offset[NUM_STREAMS]; // Current write offset in buffer
static const u32 FRAG_MIN = 0; // Min bytes for a fragmented message
static const u32 FRAG_MAX = 65535; // Max bytes for a fragmented message
// Receive state: Receive queue head
RecvQueue *_recv_queue_head[NUM_STREAMS], *_recv_queue_tail[NUM_STREAMS];
private:
void RunQueue(ThreadPoolLocalStorage *tls, u32 ack_id, u32 stream);
void QueueRecv(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes, u32 ack_id, u32 stream, u32 super_opcode);
protected:
// Send state: Synchronization objects
Mutex _send_lock;
// Send state: Next ack id to use
u32 _next_send_id[NUM_STREAMS];
// Send state: Estimated round-trip time
u32 _rtt; // milliseconds
// Send state: Last rollup ack id from remote receiver
u32 _send_next_remote_expected[NUM_STREAMS];
// Send state: Combined writes
u8 *_send_buffer;
u32 _send_buffer_bytes;
u32 _send_buffer_stream, _send_buffer_ack_id; // Used to compress ACK-ID by setting I=0 after the first reliable message
u32 _send_buffer_msg_count; // Used to compress datagrams with a single message by omitting the header's BLO field
// Queue of messages that are waiting to be sent
SendQueue *_send_queue_head[NUM_STREAMS], *_send_queue_tail[NUM_STREAMS];
// List of messages that are waiting to be acknowledged
SendQueue *_sent_list_head[NUM_STREAMS], *_sent_list_tail[NUM_STREAMS];
bool _disconnected;
private:
void TransmitQueued();
void Retransmit(u32 stream, SendQueue *node, u32 now); // Does not hold the send lock!
void WriteACK();
void OnACK(u8 *data, u32 data_bytes);
void OnMTUSet(u8 *data, u32 data_bytes);
public:
Transport();
virtual ~Transport();
public:
// ata_bytes: Length of msg_data
bool WriteUnreliable(u8 msg_opcode, const void *msg_data = 0, u32 data_bytes = 0);
bool WriteReliable(StreamMode, u8 msg_opcode, const void *msg_data = 0, u32 data_bytes = 0, SuperOpcode super_opcode = SOP_DATA);
void FlushWrite();
protected:
// Notify transport layer of disconnect to halt message processing
CAT_INLINE void TransportDisconnected() { _disconnected = true; }
CAT_INLINE bool IsDisconnected() { return _disconnected; }
void TickTransport(ThreadPoolLocalStorage *tls, u32 now);
void OnDatagram(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes);
private:
void OnFragment(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes, u32 stream);
void CombineNextWrite();
protected:
// skip_bytes: Number of bytes to skip at the start of the buffer
// buf_bytes and msg_bytes contain the skipped bytes
virtual bool PostPacket(u8 *data, u32 buf_bytes, u32 msg_bytes, u32 skip_bytes) = 0;
virtual void OnTimestampDeltaUpdate(u32 rtt, s32 delta) {}
virtual void OnMessage(ThreadPoolLocalStorage *tls, BufferStream msg, u32 bytes) = 0;
virtual void OnDisconnect() = 0;
protected:
bool PostMTUProbe(ThreadPoolLocalStorage *tls, u16 payload_bytes);
bool PostTimePing();
bool PostTimePong(u32 client_ts);
bool PostDisconnect();
};
} // namespace sphynx
} // namespace cat
#endif // CAT_SPHYNX_TRANSPORT_HPP

View File

@ -0,0 +1,95 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// TODO: Half-open connections can easily DoS the TCP server right now.
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
#define CAT_THREAD_POOL_SOCKETS_HPP
#include <cat/threads/ThreadPool.hpp>
#include <cat/net/Sockets.hpp>
namespace cat {
/*
Thread Pool Sockets library
Provides a framework for rapidly developing TCP/UDP server and client objects
that make use of high performance APIs under various server and desktop
operating systems.
All network events are processed by a thread pool managed by ThreadPool.
*/
class TCPServer;
class TCPConnexion;
class TCPClient;
class UDPEndpoint;
void ReportUnexpectedSocketError(int error);
} // namespace cat
#if defined (CAT_OS_WINDOWS) // Windows-style IOCP
#include <MSWSock.h>
#include <cat/port/WindowsInclude.hpp>
#include <cat/net/win/TCPServer.hpp>
#include <cat/net/win/TCPConnexion.hpp>
#include <cat/net/win/TCPClient.hpp>
#include <cat/net/win/UDPEndpoint.hpp>
#elif defined(CAT_OS_LINUX) // Linux-style eventfd
#include <cat/net/linux/TCPServer.hpp>
#include <cat/net/linux/TCPConnexion.hpp>
#include <cat/net/linux/TCPClient.hpp>
#include <cat/net/linux/UDPEndpoint.hpp>
#elif defined(CAT_OS_OSX) || defined(CAT_OS_BSD) // BSD-style kevent
#include <cat/net/bsd/TCPServer.hpp>
#include <cat/net/bsd/TCPConnexion.hpp>
#include <cat/net/bsd/TCPClient.hpp>
#include <cat/net/bsd/UDPEndpoint.hpp>
#else // Fall-back
#include <cat/net/generic/TCPServer.hpp>
#include <cat/net/generic/TCPConnexion.hpp>
#include <cat/net/generic/TCPClient.hpp>
#include <cat/net/generic/UDPEndpoint.hpp>
#endif
#endif // CAT_THREAD_POOL_SOCKETS_HPP

View File

@ -0,0 +1,348 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// TODO: Half-open connections can easily DoS the TCP server right now.
// TODO: Port to Linux(eventfd) and BSD/MacOSX(kevent)
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
#define CAT_THREAD_POOL_SOCKETS_HPP
#include <cat/threads/ThreadPool.hpp>
#include <cat/net/Sockets.hpp>
#if defined(CAT_MS_SOCKET_API)
# include <MSWSock.h>
# include <cat/port/WindowsInclude.hpp>
#endif
namespace cat {
/*
Thread Pool Sockets library
Provides a framework for rapidly developing TCP/UDP server and client objects
that make use of high performance APIs under various server and desktop
operating systems.
All network events are processed by a thread pool managed by ThreadPool.
*/
class TCPServer;
class TCPConnection;
class TCPClient;
class UDPEndpoint;
//// Buffer Management
// Generate a buffer to pass to Post()
u8 *GetPostBuffer(u32 bytes);
void *ResizePostBuffer(void *buffer, u32 newBytes);
// Release a buffer provided by GetPostBuffer()
// Note: Once the buffer is submitted to Post() this is unnecessary
void ReleasePostBuffer(void *buffer);
//// Overlapped Sockets
// AcceptEx() OVERLAPPED structure
struct AcceptExOverlapped
{
TypedOverlapped tov;
Socket acceptSocket;
// Space pre-allocated to receive addresses
// NOTE: This is not necessarily how the addresses are organized in memory
struct
{
// Not necessarily an IPv6 address either!
sockaddr_in6 addr[2];
u8 padding[2*16];
} addresses;
void Set(Socket s);
};
// WSARecvFrom() OVERLAPPED structure
struct RecvFromOverlapped
{
TypedOverlapped tov;
// Not necessarily and IPv6 address,
// but we allocate enough space for one
int addrLen;
sockaddr_in6 addr;
// data follows...
void Reset();
};
/*
class TCPServer
Object that represents a TCP server bound to a single port
Overload InstantiateServerConnection() to subclass connections with the server
*/
class TCPServer : public ThreadRefObject
{
friend class TCPConnection;
friend class ThreadPool;
public:
TCPServer();
virtual ~TCPServer();
bool ValidServer();
Port GetPort();
bool Bind(Port port = 0);
void Close();
protected:
virtual TCPConnection *InstantiateServerConnection() = 0;
private:
Socket _socket;
LPFN_ACCEPTEX _lpfnAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
Port _port;
private:
bool QueueAcceptEx();
bool QueueAccepts();
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
};
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_SOCKETS_HPP

View File

@ -0,0 +1,242 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
#define CAT_THREAD_POOL_SOCKETS_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
#include <MSWSock.h>
#include <cat/port/WindowsInclude.hpp>
namespace cat {
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_SOCKETS_HPP

View File

@ -0,0 +1,347 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
#define CAT_THREAD_POOL_SOCKETS_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
#include <MSWSock.h>
#include <cat/port/WindowsInclude.hpp>
namespace cat {
/*
Thread Pool Sockets library
Provides a framework for rapidly developing TCP/UDP server and client objects
that make use of high performance APIs under various server and desktop
operating systems.
All network events are processed by a thread pool managed by ThreadPool.
*/
class TCPServer;
class TCPConnection;
class TCPClient;
class UDPEndpoint;
//// Buffer Management
// Generate a buffer to pass to Post()
u8 *GetPostBuffer(u32 bytes);
void *ResizePostBuffer(void *buffer, u32 newBytes);
// Release a buffer provided by GetPostBuffer()
// Note: Once the buffer is submitted to Post() this is unnecessary
void ReleasePostBuffer(void *buffer);
//// Overlapped Sockets
// AcceptEx() OVERLAPPED structure
struct AcceptExOverlapped
{
TypedOverlapped tov;
Socket acceptSocket;
// Space pre-allocated to receive addresses
// NOTE: This is not necessarily how the addresses are organized in memory
struct
{
// Not necessarily an IPv6 address either!
sockaddr_in6 addr[2];
u8 padding[2*16];
} addresses;
void Set(Socket s);
};
// WSARecvFrom() OVERLAPPED structure
struct RecvFromOverlapped
{
TypedOverlapped tov;
// Not necessarily and IPv6 address,
// but we allocate enough space for one
int addrLen;
sockaddr_in6 addr;
// data follows...
void Reset();
};
/*
class TCPServer
Object that represents a TCP server bound to a single port
Overload InstantiateServerConnection() to subclass connections with the server
*/
class TCPServer : public ThreadRefObject
{
friend class TCPConnection;
friend class ThreadPool;
public:
TCPServer();
virtual ~TCPServer();
bool ValidServer();
Port GetPort();
bool Bind(Port port = 0);
void Close();
protected:
virtual TCPConnection *InstantiateServerConnection() = 0;
private:
Socket _socket;
LPFN_ACCEPTEX _lpfnAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
Port _port;
private:
bool QueueAcceptEx();
bool QueueAccepts();
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
};
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_SOCKETS_HPP

View File

@ -0,0 +1,319 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_UDP_ENDPOINT_HPP
#define CAT_THREAD_POOL_UDP_ENDPOINT_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
#include <MSWSock.h>
#include <cat/port/WindowsInclude.hpp>
namespace cat {
//// Overlapped Sockets
// AcceptEx() OVERLAPPED structure
struct AcceptExOverlapped
{
TypedOverlapped tov;
Socket acceptSocket;
// Space pre-allocated to receive addresses
// NOTE: This is not necessarily how the addresses are organized in memory
struct
{
// Not necessarily an IPv6 address either!
sockaddr_in6 addr[2];
u8 padding[2*16];
} addresses;
void Set(Socket s);
};
// WSARecvFrom() OVERLAPPED structure
struct RecvFromOverlapped
{
TypedOverlapped tov;
// Not necessarily and IPv6 address,
// but we allocate enough space for one
int addrLen;
sockaddr_in6 addr;
// data follows...
void Reset();
};
/*
class TCPServer
Object that represents a TCP server bound to a single port
Overload InstantiateServerConnection() to subclass connections with the server
*/
class TCPServer : public ThreadRefObject
{
friend class TCPConnection;
friend class ThreadPool;
public:
TCPServer();
virtual ~TCPServer();
bool ValidServer();
Port GetPort();
bool Bind(Port port = 0);
void Close();
protected:
virtual TCPConnection *InstantiateServerConnection() = 0;
private:
Socket _socket;
LPFN_ACCEPTEX _lpfnAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
Port _port;
private:
bool QueueAcceptEx();
bool QueueAccepts();
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
};
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_UDP_ENDPOINT_HPP

View File

@ -0,0 +1,348 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// TODO: Half-open connections can easily DoS the TCP server right now.
// TODO: Port to Linux(eventfd) and BSD/MacOSX(kevent)
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
#define CAT_THREAD_POOL_SOCKETS_HPP
#include <cat/threads/ThreadPool.hpp>
#include <cat/net/Sockets.hpp>
#if defined(CAT_MS_SOCKET_API)
# include <MSWSock.h>
# include <cat/port/WindowsInclude.hpp>
#endif
namespace cat {
/*
Thread Pool Sockets library
Provides a framework for rapidly developing TCP/UDP server and client objects
that make use of high performance APIs under various server and desktop
operating systems.
All network events are processed by a thread pool managed by ThreadPool.
*/
class TCPServer;
class TCPConnection;
class TCPClient;
class UDPEndpoint;
//// Buffer Management
// Generate a buffer to pass to Post()
u8 *GetPostBuffer(u32 bytes);
void *ResizePostBuffer(void *buffer, u32 newBytes);
// Release a buffer provided by GetPostBuffer()
// Note: Once the buffer is submitted to Post() this is unnecessary
void ReleasePostBuffer(void *buffer);
//// Overlapped Sockets
// AcceptEx() OVERLAPPED structure
struct AcceptExOverlapped
{
TypedOverlapped tov;
Socket acceptSocket;
// Space pre-allocated to receive addresses
// NOTE: This is not necessarily how the addresses are organized in memory
struct
{
// Not necessarily an IPv6 address either!
sockaddr_in6 addr[2];
u8 padding[2*16];
} addresses;
void Set(Socket s);
};
// WSARecvFrom() OVERLAPPED structure
struct RecvFromOverlapped
{
TypedOverlapped tov;
// Not necessarily and IPv6 address,
// but we allocate enough space for one
int addrLen;
sockaddr_in6 addr;
// data follows...
void Reset();
};
/*
class TCPServer
Object that represents a TCP server bound to a single port
Overload InstantiateServerConnection() to subclass connections with the server
*/
class TCPServer : public ThreadRefObject
{
friend class TCPConnection;
friend class ThreadPool;
public:
TCPServer();
virtual ~TCPServer();
bool ValidServer();
Port GetPort();
bool Bind(Port port = 0);
void Close();
protected:
virtual TCPConnection *InstantiateServerConnection() = 0;
private:
Socket _socket;
LPFN_ACCEPTEX _lpfnAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
Port _port;
private:
bool QueueAcceptEx();
bool QueueAccepts();
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
};
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_SOCKETS_HPP

View File

@ -0,0 +1,242 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
#define CAT_THREAD_POOL_SOCKETS_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
#include <MSWSock.h>
#include <cat/port/WindowsInclude.hpp>
namespace cat {
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_SOCKETS_HPP

View File

@ -0,0 +1,347 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
#define CAT_THREAD_POOL_SOCKETS_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
#include <MSWSock.h>
#include <cat/port/WindowsInclude.hpp>
namespace cat {
/*
Thread Pool Sockets library
Provides a framework for rapidly developing TCP/UDP server and client objects
that make use of high performance APIs under various server and desktop
operating systems.
All network events are processed by a thread pool managed by ThreadPool.
*/
class TCPServer;
class TCPConnection;
class TCPClient;
class UDPEndpoint;
//// Buffer Management
// Generate a buffer to pass to Post()
u8 *GetPostBuffer(u32 bytes);
void *ResizePostBuffer(void *buffer, u32 newBytes);
// Release a buffer provided by GetPostBuffer()
// Note: Once the buffer is submitted to Post() this is unnecessary
void ReleasePostBuffer(void *buffer);
//// Overlapped Sockets
// AcceptEx() OVERLAPPED structure
struct AcceptExOverlapped
{
TypedOverlapped tov;
Socket acceptSocket;
// Space pre-allocated to receive addresses
// NOTE: This is not necessarily how the addresses are organized in memory
struct
{
// Not necessarily an IPv6 address either!
sockaddr_in6 addr[2];
u8 padding[2*16];
} addresses;
void Set(Socket s);
};
// WSARecvFrom() OVERLAPPED structure
struct RecvFromOverlapped
{
TypedOverlapped tov;
// Not necessarily and IPv6 address,
// but we allocate enough space for one
int addrLen;
sockaddr_in6 addr;
// data follows...
void Reset();
};
/*
class TCPServer
Object that represents a TCP server bound to a single port
Overload InstantiateServerConnection() to subclass connections with the server
*/
class TCPServer : public ThreadRefObject
{
friend class TCPConnection;
friend class ThreadPool;
public:
TCPServer();
virtual ~TCPServer();
bool ValidServer();
Port GetPort();
bool Bind(Port port = 0);
void Close();
protected:
virtual TCPConnection *InstantiateServerConnection() = 0;
private:
Socket _socket;
LPFN_ACCEPTEX _lpfnAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
Port _port;
private:
bool QueueAcceptEx();
bool QueueAccepts();
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
};
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_SOCKETS_HPP

View File

@ -0,0 +1,319 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_UDP_ENDPOINT_HPP
#define CAT_THREAD_POOL_UDP_ENDPOINT_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
#include <MSWSock.h>
#include <cat/port/WindowsInclude.hpp>
namespace cat {
//// Overlapped Sockets
// AcceptEx() OVERLAPPED structure
struct AcceptExOverlapped
{
TypedOverlapped tov;
Socket acceptSocket;
// Space pre-allocated to receive addresses
// NOTE: This is not necessarily how the addresses are organized in memory
struct
{
// Not necessarily an IPv6 address either!
sockaddr_in6 addr[2];
u8 padding[2*16];
} addresses;
void Set(Socket s);
};
// WSARecvFrom() OVERLAPPED structure
struct RecvFromOverlapped
{
TypedOverlapped tov;
// Not necessarily and IPv6 address,
// but we allocate enough space for one
int addrLen;
sockaddr_in6 addr;
// data follows...
void Reset();
};
/*
class TCPServer
Object that represents a TCP server bound to a single port
Overload InstantiateServerConnection() to subclass connections with the server
*/
class TCPServer : public ThreadRefObject
{
friend class TCPConnection;
friend class ThreadPool;
public:
TCPServer();
virtual ~TCPServer();
bool ValidServer();
Port GetPort();
bool Bind(Port port = 0);
void Close();
protected:
virtual TCPConnection *InstantiateServerConnection() = 0;
private:
Socket _socket;
LPFN_ACCEPTEX _lpfnAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
Port _port;
private:
bool QueueAcceptEx();
bool QueueAccepts();
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
};
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_UDP_ENDPOINT_HPP

View File

@ -0,0 +1,348 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// TODO: Half-open connections can easily DoS the TCP server right now.
// TODO: Port to Linux(eventfd) and BSD/MacOSX(kevent)
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
#define CAT_THREAD_POOL_SOCKETS_HPP
#include <cat/threads/ThreadPool.hpp>
#include <cat/net/Sockets.hpp>
#if defined(CAT_MS_SOCKET_API)
# include <MSWSock.h>
# include <cat/port/WindowsInclude.hpp>
#endif
namespace cat {
/*
Thread Pool Sockets library
Provides a framework for rapidly developing TCP/UDP server and client objects
that make use of high performance APIs under various server and desktop
operating systems.
All network events are processed by a thread pool managed by ThreadPool.
*/
class TCPServer;
class TCPConnection;
class TCPClient;
class UDPEndpoint;
//// Buffer Management
// Generate a buffer to pass to Post()
u8 *GetPostBuffer(u32 bytes);
void *ResizePostBuffer(void *buffer, u32 newBytes);
// Release a buffer provided by GetPostBuffer()
// Note: Once the buffer is submitted to Post() this is unnecessary
void ReleasePostBuffer(void *buffer);
//// Overlapped Sockets
// AcceptEx() OVERLAPPED structure
struct AcceptExOverlapped
{
TypedOverlapped tov;
Socket acceptSocket;
// Space pre-allocated to receive addresses
// NOTE: This is not necessarily how the addresses are organized in memory
struct
{
// Not necessarily an IPv6 address either!
sockaddr_in6 addr[2];
u8 padding[2*16];
} addresses;
void Set(Socket s);
};
// WSARecvFrom() OVERLAPPED structure
struct RecvFromOverlapped
{
TypedOverlapped tov;
// Not necessarily and IPv6 address,
// but we allocate enough space for one
int addrLen;
sockaddr_in6 addr;
// data follows...
void Reset();
};
/*
class TCPServer
Object that represents a TCP server bound to a single port
Overload InstantiateServerConnection() to subclass connections with the server
*/
class TCPServer : public ThreadRefObject
{
friend class TCPConnection;
friend class ThreadPool;
public:
TCPServer();
virtual ~TCPServer();
bool ValidServer();
Port GetPort();
bool Bind(Port port = 0);
void Close();
protected:
virtual TCPConnection *InstantiateServerConnection() = 0;
private:
Socket _socket;
LPFN_ACCEPTEX _lpfnAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
Port _port;
private:
bool QueueAcceptEx();
bool QueueAccepts();
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
};
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_SOCKETS_HPP

View File

@ -0,0 +1,242 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
#define CAT_THREAD_POOL_SOCKETS_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
#include <MSWSock.h>
#include <cat/port/WindowsInclude.hpp>
namespace cat {
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_SOCKETS_HPP

View File

@ -0,0 +1,347 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_SOCKETS_HPP
#define CAT_THREAD_POOL_SOCKETS_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
#include <MSWSock.h>
#include <cat/port/WindowsInclude.hpp>
namespace cat {
/*
Thread Pool Sockets library
Provides a framework for rapidly developing TCP/UDP server and client objects
that make use of high performance APIs under various server and desktop
operating systems.
All network events are processed by a thread pool managed by ThreadPool.
*/
class TCPServer;
class TCPConnection;
class TCPClient;
class UDPEndpoint;
//// Buffer Management
// Generate a buffer to pass to Post()
u8 *GetPostBuffer(u32 bytes);
void *ResizePostBuffer(void *buffer, u32 newBytes);
// Release a buffer provided by GetPostBuffer()
// Note: Once the buffer is submitted to Post() this is unnecessary
void ReleasePostBuffer(void *buffer);
//// Overlapped Sockets
// AcceptEx() OVERLAPPED structure
struct AcceptExOverlapped
{
TypedOverlapped tov;
Socket acceptSocket;
// Space pre-allocated to receive addresses
// NOTE: This is not necessarily how the addresses are organized in memory
struct
{
// Not necessarily an IPv6 address either!
sockaddr_in6 addr[2];
u8 padding[2*16];
} addresses;
void Set(Socket s);
};
// WSARecvFrom() OVERLAPPED structure
struct RecvFromOverlapped
{
TypedOverlapped tov;
// Not necessarily and IPv6 address,
// but we allocate enough space for one
int addrLen;
sockaddr_in6 addr;
// data follows...
void Reset();
};
/*
class TCPServer
Object that represents a TCP server bound to a single port
Overload InstantiateServerConnection() to subclass connections with the server
*/
class TCPServer : public ThreadRefObject
{
friend class TCPConnection;
friend class ThreadPool;
public:
TCPServer();
virtual ~TCPServer();
bool ValidServer();
Port GetPort();
bool Bind(Port port = 0);
void Close();
protected:
virtual TCPConnection *InstantiateServerConnection() = 0;
private:
Socket _socket;
LPFN_ACCEPTEX _lpfnAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
Port _port;
private:
bool QueueAcceptEx();
bool QueueAccepts();
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
};
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_SOCKETS_HPP

View File

@ -0,0 +1,319 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_THREAD_POOL_UDP_ENDPOINT_HPP
#define CAT_THREAD_POOL_UDP_ENDPOINT_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
#include <MSWSock.h>
#include <cat/port/WindowsInclude.hpp>
namespace cat {
//// Overlapped Sockets
// AcceptEx() OVERLAPPED structure
struct AcceptExOverlapped
{
TypedOverlapped tov;
Socket acceptSocket;
// Space pre-allocated to receive addresses
// NOTE: This is not necessarily how the addresses are organized in memory
struct
{
// Not necessarily an IPv6 address either!
sockaddr_in6 addr[2];
u8 padding[2*16];
} addresses;
void Set(Socket s);
};
// WSARecvFrom() OVERLAPPED structure
struct RecvFromOverlapped
{
TypedOverlapped tov;
// Not necessarily and IPv6 address,
// but we allocate enough space for one
int addrLen;
sockaddr_in6 addr;
// data follows...
void Reset();
};
/*
class TCPServer
Object that represents a TCP server bound to a single port
Overload InstantiateServerConnection() to subclass connections with the server
*/
class TCPServer : public ThreadRefObject
{
friend class TCPConnection;
friend class ThreadPool;
public:
TCPServer();
virtual ~TCPServer();
bool ValidServer();
Port GetPort();
bool Bind(Port port = 0);
void Close();
protected:
virtual TCPConnection *InstantiateServerConnection() = 0;
private:
Socket _socket;
LPFN_ACCEPTEX _lpfnAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
Port _port;
private:
bool QueueAcceptEx();
bool QueueAccepts();
void OnAcceptExComplete(int error, AcceptExOverlapped *overlapped);
};
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection();
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true iff the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
friend class ThreadPool;
public:
TCPClient();
virtual ~TCPClient();
bool ValidClient();
bool Connect(const NetAddr &remoteServerAddress);
void DisconnectServer();
bool PostToServer(void *buffer, u32 bytes);
protected:
virtual void OnConnectToServer() = 0;
virtual bool OnReadFromServer(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToServer(u32 bytes) = 0;
virtual void OnDisconnectFromServer() = 0;
private:
Socket _socket;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
bool _ipv6;
private:
bool QueueConnectEx(const NetAddr &remoteServerAddress);
void OnConnectExComplete(int error);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
void *_queueBuffer;
u32 _queueBytes;
protected:
void PostQueuedToServer();
public:
TCPClientQueued();
virtual ~TCPClientQueued();
bool PostToServer(void *buffer, u32 bytes);
};
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
friend class ThreadPool;
public:
UDPEndpoint();
virtual ~UDPEndpoint();
bool Valid();
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
void Close(); // Invalidates this object
bool Bind(Port port = 0, bool ignoreUnreachable = true);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling Post() with addr.PromoteTo6()
bool Post(const NetAddr &addr, void *data, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual void OnWrite(u32 bytes) = 0;
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
private:
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
private:
bool QueueWSARecvFrom(RecvFromOverlapped *recvOv);
void OnWSARecvFromComplete(ThreadPoolLocalStorage *tls, int error, RecvFromOverlapped *recvOv, u32 bytes);
bool QueueWSASendTo(const NetAddr &addr, TypedOverlapped *sendOv, u32 bytes);
void OnWSASendToComplete(int error, u32 bytes);
};
} // namespace cat
#endif // CAT_THREAD_POOL_UDP_ENDPOINT_HPP

View File

@ -0,0 +1,126 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_TCP_CLIENT_HPP
#define CAT_TCP_CLIENT_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
namespace cat {
/*
class TCPClient
Object that represents a TCPClient bound to a single port
ValidClient() : Returns true if the client socket is valid
Connect() : Connects to the given address
DisconnectServer() : Disconnects from the server
PostToServer() : Send a message to the server (will fail if not connected)
OnConnectToServer() : Called when connection is accepted
OnReadFromServer() : Return false to disconnect the server in response to data
OnWriteToServer() : Informs the derived class that data has been sent
OnDisconnectFromServer() : Informs the derived class that the server has disconnected
*/
class TCPClient : public ThreadRefObject
{
// Remembers if socket is IPv6 so that user-provided
// addresses can be promoted if necessary.
bool _ipv6;
Socket _socket;
volatile u32 _disconnecting; // Disconnect flag
public:
TCPClient(int priorityLevel);
virtual ~TCPClient();
CAT_INLINE bool Valid() { return _socket != SOCKET_ERROR; }
void Disconnect();
bool Connect(bool onlySupportIPv4, const NetAddr &remoteServerAddress);
public:
bool Post(u8 *data, u32 data_bytes, u32 skip_bytes = 0);
private:
bool ConnectEx(const NetAddr &remoteServerAddress);
bool Read(AsyncBuffer *buffer = 0);
bool Disco(AsyncBuffer *buffer = 0);
private:
bool OnConnectEx(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
bool OnRead(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
bool OnWrite(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
bool OnDisco(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
protected:
virtual void OnConnectToServer(ThreadPoolLocalStorage *tls) = 0;
virtual bool OnReadFromServer(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes) = 0; // false = disconnect
virtual bool OnWriteToServer(ThreadPoolLocalStorage *tls, AsyncBuffer *buffer, u32 bytes) = 0; // true = delete AsyncBuffer object
virtual void OnDisconnectFromServer() = 0;
};
/*
class TCPClientQueued
Base class for a TCP client that needs to queue up data for sending before
a connection has been established. e.g. Uplink for a proxy server.
PostQueuedToServer() : Call in OnConnectToServer() to post the queued messages.
*/
class TCPClientQueued : public TCPClient
{
private:
volatile bool _queuing;
Mutex _queueLock;
AsyncBuffer *_queueBuffer;
protected:
void PostQueuedToServer();
public:
TCPClientQueued(int priorityLevel);
virtual ~TCPClientQueued();
bool Post(u8 *data, u32 data_bytes, u32 skip_bytes = 0);
};
} // namespace cat
#endif // CAT_TCP_CLIENT_HPP

View File

@ -0,0 +1,102 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_TCP_CONNECTION_HPP
#define CAT_TCP_CONNECTION_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
namespace cat {
/*
class TCPConnection
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
DisconnectClient() : Disconnect the client
PostToClient() : Send a message to the client
ValidServerConnection() : Returns true iff the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnection : public ThreadRefObject
{
friend class TCPServer;
friend class ThreadPool;
public:
TCPConnection(int priorityLevel);
virtual ~TCPConnection();
bool ValidServerConnection();
void DisconnectClient();
bool PostToClient(void *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(u8 *data, u32 bytes) = 0; // false = disconnect
virtual void OnWriteToClient(u32 bytes) = 0;
virtual void OnDisconnectFromClient() = 0;
private:
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
TypedOverlapped *_recvOv;
volatile u32 _disconnecting;
private:
bool AcceptConnection(Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
bool QueueWSARecv();
void OnWSARecvComplete(int error, u32 bytes);
bool QueueWSASend(TypedOverlapped *sendOv, u32 bytes);
void OnWSASendComplete(int error, u32 bytes);
bool QueueDisconnectEx();
void OnDisconnectExComplete(int error);
};
} // namespace cat
#endif // CAT_TCP_CONNECTION_HPP

View File

@ -0,0 +1,98 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_TCP_CONNEXION_HPP
#define CAT_TCP_CONNEXION_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
namespace cat {
/*
class TCPConnexion
Object that represents a TCPServer's connection from a TCPClient
Object is instantiated just before accepting a connection
Disconnect() : Disconnect the client
Post() : Send a message to the client
Valid() : Returns true if the connection is valid
OnConnectFromClient() : Return false to deny this connection
OnReadFromClient() : Return false to disconnect the client in response to a message
OnWriteToClient() : Informs the derived class that data has been sent
OnDisconectFromClient() : Informs the derived class that the client has disconnected
*/
class TCPConnexion : public ThreadRefObject
{
friend class TCPServer;
Socket _socket;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
volatile u32 _disconnecting;
bool Accept(ThreadPoolLocalStorage *tls, Socket listenSocket, Socket acceptSocket,
LPFN_DISCONNECTEX lpfnDisconnectEx, const NetAddr &acceptAddress,
const NetAddr &remoteClientAddress);
public:
TCPConnexion(int priorityLevel);
virtual ~TCPConnexion();
CAT_INLINE bool Valid() { return _socket != SOCKET_ERROR; }
void Disconnect();
bool Post(u8 *data, u32 data_bytes, u32 skip_bytes = 0);
private:
bool Read(AsyncBuffer *buffer = 0);
bool Disco(AsyncBuffer *buffer = 0);
private:
bool OnRead(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
bool OnWrite(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
bool OnDisco(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
protected:
virtual bool OnConnectFromClient(ThreadPoolLocalStorage *tls, const NetAddr &remoteClientAddress) = 0; // false = disconnect
virtual bool OnReadFromClient(ThreadPoolLocalStorage *tls, u8 *data, u32 bytes) = 0; // false = disconnect
virtual bool OnWriteToClient(ThreadPoolLocalStorage *tls, AsyncBuffer *buffer, u32 bytes) = 0; // true = delete AsyncBuffer
virtual void OnDisconnectFromClient() = 0;
};
} // namespace cat
#endif // CAT_TCP_CONNEXION_HPP

View File

@ -0,0 +1,97 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_TCP_SERVER_HPP
#define CAT_TCP_SERVER_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
namespace cat {
/*
class TCPServer
Object that represents a TCP server bound to a single port
Overload InstantiateServerConnexion() to subclass connections with the server
*/
class TCPServer : public ThreadRefObject
{
friend class TCPConnexion;
Socket _socket;
LPFN_ACCEPTEX _lpfnAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS _lpfnGetAcceptExSockAddrs;
LPFN_DISCONNECTEX _lpfnDisconnectEx;
Port _port;
struct AcceptTag
{
Socket acceptSocket;
// Space pre-allocated to receive addresses
// NOTE: This is not necessarily how the addresses are organized in memory
struct
{
// Not necessarily an IPv6 address
sockaddr_in6 addr[2];
u8 padding[2*16];
} addresses;
};
bool PostAccept(AsyncBuffer *buffer = 0);
bool QueueAccepts();
public:
TCPServer(int priorityLevel);
virtual ~TCPServer();
bool ValidServer();
Port GetPort();
bool Bind(bool onlySupportIPv4, Port port = 0);
void Close();
protected:
// Return true to release overlapped object memory, or return false to keep it
virtual bool OnAccept(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
protected:
virtual TCPConnexion *InstantiateServerConnexion() = 0;
};
} // namespace cat
#endif // CAT_TCP_SERVER_HPP

View File

@ -0,0 +1,105 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_UDP_ENDPOINT_HPP
#define CAT_UDP_ENDPOINT_HPP
/*
Windows version of thread pool sockets with IO Completion Ports
Included from <cat/net/ThreadPoolSockets.hpp>
Do not include directly
*/
namespace cat {
/*
class UDPEndpoint
Object that represents a UDP endpoint bound to a single port
*/
class UDPEndpoint : public ThreadRefObject
{
Socket _socket;
Port _port;
volatile u32 _closing;
bool _ipv6;
struct RecvFromTag
{
// Not necessarily an IPv6 address, but we allocate enough space for one
int addrLen;
sockaddr_in6 addr;
};
public:
UDPEndpoint(int priorityLevel);
virtual ~UDPEndpoint();
CAT_INLINE bool Valid() { return _socket != SOCKET_ERROR; }
Port GetPort();
// Is6() result is only valid AFTER Bind()
CAT_INLINE bool Is6() { return _ipv6; }
CAT_INLINE bool IsClosed() { return _closing != 0; }
// For servers: Bind() with ignoreUnreachable = true ((default))
// For clients: Bind() with ignoreUnreachable = false and call this
// after the first packet from the server is received.
bool IgnoreUnreachable();
// Disabled by default; useful for MTU discovery
bool DontFragment(bool df = true);
void Close(); // Invalidates this object
bool Bind(bool onlySupportIPv4, Port port = 0, bool ignoreUnreachable = true, int kernelReceiveBufferBytes = 0);
bool QueueWSARecvFrom();
// If Is6() == true, the address must be promoted to IPv6
// before calling PostWrite() with addr.PromoteTo6()
// skip_bytes: Number of bytes to skip at the start of the post buffer
bool Post(const NetAddr &addr, u8 *data, u32 data_bytes, u32 skip_bytes = 0);
private:
bool Read(AsyncBuffer *buffer = 0);
bool OnReadComplete(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
bool OnWriteComplete(ThreadPoolLocalStorage *tls, int error, AsyncBuffer *buffer, u32 bytes);
protected:
virtual void OnRead(ThreadPoolLocalStorage *tls, const NetAddr &addr, u8 *data, u32 bytes) = 0; // false = close
virtual bool OnWrite(ThreadPoolLocalStorage *tls, AsyncBuffer *buffer, u32 bytes) { return true; } // false = do not delete AsyncBase object
virtual void OnClose() = 0;
virtual void OnUnreachable(const NetAddr &addr) {} // Only IP is valid
};
} // namespace cat
#endif // CAT_UDP_ENDPOINT_HPP

View File

@ -0,0 +1,214 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// Not currently being maintained.
// FIXME: Big-endian code is untested
// FIXME: Not suitable for storing large buffers > 500 MB in size
#ifndef CAT_BIT_STREAM_HPP
#define CAT_BIT_STREAM_HPP
#include <cat/Platform.hpp>
namespace cat {
//// BitStream manipulators ////
namespace bs_bit
{
template<u32 N_BITS> struct set
{
u32 bits;
set(u32 c_bits) : bits(c_bits) { }
};
template<u32 N_BITS> struct get
{
u32 &ref;
get(u32 &c_ref) : ref(c_ref) { }
};
}
namespace bs_byte
{
struct set
{
u32 bytes;
const void *ref;
set(u32 b, const void *r) : ref(r), bytes(b) { }
};
struct get
{
u32 bytes;
void *ref;
get(u32 b, void *r) : ref(r), bytes(b) { }
};
}
//// BitStream ////
class BitStream
{
bool fixed_buffer;
u8 *buffer;
u32 buffer_bytes;
bool read_underrun;
// grow to be able to write a number of bits
void grow(u32 bits);
public:
u32 read_offset, write_offset; // in bits
public:
BitStream(u32 bytes = 0, void *vbuffer = 0);
~BitStream();
// free unused buffer space
void shrink();
public:
u8 *get() { return buffer; }
bool aligned() { return read_offset % 8 == 0; }
u8 *peek() { return buffer + read_offset / 8; }
public:
// returns true iff the buffer is valid
bool valid() { return buffer != 0; }
// returns count of remaining readable bits
int unread() { return write_offset - read_offset; }
// returns true if a recent read operation would have overrun the buffer
bool underrun();
// skip ahead a number of bits
void skip(u32 bits);
public:
// insertion
void write1(u8 data); // data MUST be 1 or 0
template<class T> void write(T data)
{
grow(sizeof(T) * 8);
u32 byte_offset = write_offset / 8;
u32 shift = write_offset % 8;
if (shift)
{
buffer[byte_offset] |= (u8)(data << shift);
data = data >> (8 - shift);
++byte_offset;
}
*(T*)(buffer + byte_offset) = data;
write_offset += sizeof(T) * 8;
}
template<> void write(s8 data) { write((u8)data); }
template<> void write(s16 data) { write((u16)data); }
template<> void write(s32 data) { write((u32)data); }
template<> void write(s64 data) { write((u64)data); }
template<> void write(float data) { write(*(u32*)&data); }
template<> void write(double data) { write(*(u64*)&data); }
void writeBits(u32 data, int count);
void writeBytes(const void *data, u32 byte_count);
public:
// stream-mode insertion
BitStream &operator<<(const char *data) { writeBytes(data, (u32)strlen(data)); return *this; }
template<class T> BitStream &operator<<(T data) { write(data); return *this; }
template<u32 N_BITS> BitStream &operator<<(const bs_bit::set<N_BITS> &n) { writeBits(n.bits, N_BITS); return *this; }
template<> BitStream &operator<<(const bs_bit::set<1> &n) { write1((u8)n.bits); return *this; }
template<> BitStream &operator<<(const bs_bit::set<8> &n) { write((u8)n.bits); return *this; }
template<> BitStream &operator<<(const bs_bit::set<16> &n) { write((u16)n.bits); return *this; }
template<> BitStream &operator<<(const bs_bit::set<32> &n) { write((u32)n.bits); return *this; }
BitStream &operator<<(const bs_byte::set &n) { writeBytes(n.ref, n.bytes); return *this; }
public:
// extraction
u8 read1();
template<class T> void read(T &data)
{
const u32 bits = sizeof(T) * 8;
if (read_offset + bits > write_offset)
{
read_underrun = true;
return;
}
u32 byte_offset = read_offset / 8;
u32 shift = read_offset % 8;
if (shift)
data = (*(T*)(buffer + byte_offset + 1) << (8 - shift)) | (buffer[byte_offset] >> shift);
else
data = *(T*)(buffer + byte_offset);
read_offset += bits;
}
template<> void read(float &data) { read((u32&)data); }
template<> void read(double &data) { write(*(u64*)&data); }
template<class T> T read() { T temp; read(temp); return temp; }
u32 readBits(u32 count);
void readBytes(void *data, u32 byte_count);
public:
// stream-mode extraction
template<class T> BitStream &operator>>(T &data) { read(data); return *this; }
template<u32 N_BITS> BitStream &operator>>(const bs_bit::get<N_BITS> &n) { n.ref = readBits(N_BITS); return *this; }
template<> BitStream &operator>>(const bs_bit::get<1> &n) { n.ref = read1(); return *this; }
template<> BitStream &operator>>(const bs_bit::get<8> &n) { n.ref = read<u8>(); return *this; }
template<> BitStream &operator>>(const bs_bit::get<16> &n) { n.ref = read<u16>(); return *this; }
template<> BitStream &operator>>(const bs_bit::get<32> &n) { read(n.ref); return *this; }
BitStream &operator>>(const bs_byte::get &n) { readBytes(n.ref, n.bytes); return *this; }
};
} // namespace cat
#endif // CAT_BIT_STREAM_HPP

View File

@ -0,0 +1,114 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_BUFFER_STREAM_HPP
#define CAT_BUFFER_STREAM_HPP
#include <cat/Platform.hpp>
#include <cat/port/EndianNeutral.hpp>
namespace cat {
/*
BufferStream
Extremely light-weight wrapper for a buffer data insertion and extraction.
Performs automatic endian conversion into and out of the buffer (sometimes).
Performs no checking for buffer overruns.
This class does not add any security to your code; it just makes it shorter.
Use at your peril.
*/
class BufferStream
{
protected:
u8 *_buffer;
public:
CAT_INLINE BufferStream(u8 *buffer) { _buffer = buffer; }
CAT_INLINE BufferStream &operator=(u8 *buffer) { _buffer = buffer; }
CAT_INLINE u32 GetOffset(void *buffer) { return (u32)(_buffer - reinterpret_cast<u8*>( buffer )); }
public:
// Auto-cast to u8* or char*
CAT_INLINE operator u8*() { return _buffer; }
CAT_INLINE char *c_str() { return reinterpret_cast<char*>( _buffer ); }
CAT_INLINE BufferStream &operator++() { _buffer++; return *this; }
CAT_INLINE BufferStream &operator+=(int skip_bytes) { _buffer += skip_bytes; return *this; }
public:
// Insertion
CAT_INLINE BufferStream &operator<<(s8 data) { *_buffer++ = (u8)data; return *this; }
CAT_INLINE BufferStream &operator<<(s16 data) { *(u16*)_buffer = getLE16((u16)data); _buffer += 2; return *this; }
CAT_INLINE BufferStream &operator<<(s32 data) { *(u32*)_buffer = getLE32((u32)data); _buffer += 4; return *this; }
CAT_INLINE BufferStream &operator<<(s64 data) { *(u64*)_buffer = getLE64((u64)data); _buffer += 8; return *this; }
CAT_INLINE BufferStream &operator<<(u8 data) { *_buffer++ = data; return *this; }
CAT_INLINE BufferStream &operator<<(u16 data) { *(u16*)_buffer = getLE16(data); _buffer += 2; return *this; }
CAT_INLINE BufferStream &operator<<(u32 data) { *(u32*)_buffer = getLE32(data); _buffer += 4; return *this; }
CAT_INLINE BufferStream &operator<<(u64 data) { *(u64*)_buffer = getLE64(data); _buffer += 8; return *this; }
CAT_INLINE void write(const void *data, u32 bytes)
{
memcpy(_buffer, data, bytes);
_buffer += bytes;
}
template<class T>
CAT_INLINE BufferStream &operator<<(const T &data) { write(&data, sizeof(T)); return *this; }
public:
// Extraction
CAT_INLINE BufferStream &operator>>(s8 &data) { data = (s8)*_buffer++; return *this; }
CAT_INLINE BufferStream &operator>>(s16 &data) { data = (s16)getLE16(*(u16*)_buffer); _buffer += 2; return *this; }
CAT_INLINE BufferStream &operator>>(s32 &data) { data = (s32)getLE32(*(u32*)_buffer); _buffer += 4; return *this; }
CAT_INLINE BufferStream &operator>>(s64 &data) { data = (s64)getLE64(*(u64*)_buffer); _buffer += 8; return *this; }
CAT_INLINE BufferStream &operator>>(u8 &data) { data = *_buffer++; return *this; }
CAT_INLINE BufferStream &operator>>(u16 &data) { data = getLE16(*(u16*)_buffer); _buffer += 2; return *this; }
CAT_INLINE BufferStream &operator>>(u32 &data) { data = getLE32(*(u32*)_buffer); _buffer += 4; return *this; }
CAT_INLINE BufferStream &operator>>(u64 &data) { data = getLE64(*(u64*)_buffer); _buffer += 8; return *this; }
CAT_INLINE void read(void *data, u32 bytes)
{
memcpy(data, _buffer, bytes);
_buffer += bytes;
}
template<class T>
CAT_INLINE BufferStream &operator>>(T &data) { read(&data, sizeof(T)); return *this; }
};
} // namespace cat
#endif // CAT_BUFFER_STREAM_HPP

View File

@ -0,0 +1,105 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_BUFFER_TOK_HPP
#define CAT_BUFFER_TOK_HPP
#include <cat/Platform.hpp>
namespace cat {
/*
MyBuf = " 123 5 : 6 "
BufferTok bt(MyBuf, 256);
int a, b, c;
bt() >> a; // empty delimiter means white space and newlines
bt(':') >> b >> c;
if (!bt) // out of buffer space
*/
// Tokenize a buffer
class BufferTok
{
const char *buffer;
int len;
char delimiter;
bool newline;
u32 readNext(char *token, u32 tokenBufferSize);
public:
BufferTok(const char *buffer, int len);
// Returns true when the buffer is empty
inline bool operator!() { return len <= 0; }
// Returns true when the buffer extraction is stuck on a new line
// Use operator[] to reset this flag
inline bool onNewline() { return newline; }
/*
* operator(char)
* Set the delimiter character
*
* This character is used to find the end of the current token
* Newlines are always a delimiter
*/
BufferTok &operator()(char ch = 0);
/*
* Same as operator(), see above
*
* Also resets the newline() flag, so that data can start being
* read from the next line. If newline() wasn't set, it searches
* for the next line to start reading.
*/
BufferTok &operator[](char ch);
/*
* operator>>
* Extract a token
*
* Strips whitespace and the end-of-token delimiter
* Newlines are always a delimiter
*
* After the tokenizer encounters a newline, it will continue
* returning no results with newline() flag set, until the
* delimiter is reset with [], so incomplete lines don't wrap.
*/
BufferTok &operator>>(int &n);
BufferTok &operator>>(char *n); // buffer must have at least 256 characters
};
} // namespace cat
#endif // CAT_BUFFER_TOK_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_MESSAGE_ROUTER_HPP
#define CAT_MESSAGE_ROUTER_HPP
#include <cat/parse/BitStream.hpp>
#include <cat/port/FastDelegate.h>
namespace cat {
typedef fastdelegate::FastDelegate<void (BitStream &m)> MessageHandler;
class MessageRouter
{
MessageHandler handlers[256];
public:
void Set(u8 opcode, const MessageHandler &handler);
void Clear(u8 opcode);
void Invoke(u8 opcode, BitStream &msg);
};
} // namespace cat
#endif // CAT_MESSAGE_ROUTER_HPP

View File

@ -0,0 +1,271 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_ALIGNED_ALLOC_HPP
#define CAT_ALIGNED_ALLOC_HPP
#include <cat/Platform.hpp>
#include <cstddef> // size_t
#include <vector> // std::_Construct and std::_Destroy
namespace cat {
// Small to medium -size aligned heap allocator
class Aligned
{
public:
CAT_INLINE Aligned() {}
// Acquires memory aligned to a CPU cache-line byte boundary from the heap
static void *Acquire(u32 bytes);
// Resizes an aligned pointer
static void *Resize(void *ptr, u32 bytes);
// Release an aligned pointer
static void Release(void *ptr);
template<class T>
static inline void Delete(T *ptr)
{
ptr->~T();
Release(ptr);
}
static Aligned ii;
};
#if 0
// Use STLAlignedAllocator in place of the standard STL allocator
// to make use of the Aligned in STL types.
template<typename T>
class STLAlignedAllocator
{
public:
typedef std::size_t size_type;
typedef std::size_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
typedef T value_type;
template<typename S>
struct rebind
{
typedef STLAlignedAllocator<S> other;
};
pointer address(reference X) const
{
return &X;
}
const_pointer address(const_reference X) const
{
return &X;
}
STLAlignedAllocator() throw ()
{
}
template<typename S>
STLAlignedAllocator(const STLAlignedAllocator<S> &cp) throw ()
{
}
template<typename S>
STLAlignedAllocator<T> &operator=(const STLAlignedAllocator<S> &cp) throw ()
{
return *this;
}
pointer allocate(size_type Count, const void *Hint = 0)
{
return (pointer)Aligned::Acquire((u32)Count * sizeof(T));
}
void deallocate(pointer Ptr, size_type Count)
{
Aligned::Release(Ptr);
}
void construct(pointer Ptr, const T &Val)
{
std::_Construct(Ptr, Val);
}
void destroy(pointer Ptr)
{
std::_Destroy(Ptr);
}
size_type max_size() const
{
return 0x00FFFFFF;
}
template<typename S>
bool operator==(STLAlignedAllocator <S> const &) const throw()
{
return true;
}
template<typename S>
bool operator!=(STLAlignedAllocator <S> const &) const throw()
{
return false;
}
};
#endif
// Large-size aligned heap allocator
class LargeAligned
{
public:
// Acquires memory aligned to a CPU cache-line byte boundary from the heap
static void *Acquire(u32 bytes);
// Release an aligned pointer
static void Release(void *ptr);
};
#if 0
// Use STLAlignedAllocator in place of the standard STL allocator
// to make use of the Aligned in STL types.
template<typename T>
class STLLargeAlignedAllocator
{
public:
typedef std::size_t size_type;
typedef std::size_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
typedef T value_type;
template<typename S>
struct rebind
{
typedef STLLargeAlignedAllocator<S> other;
};
pointer address(reference X) const
{
return &X;
}
const_pointer address(const_reference X) const
{
return &X;
}
STLLargeAlignedAllocator() throw ()
{
}
template<typename S>
STLLargeAlignedAllocator(const STLLargeAlignedAllocator<S> &cp) throw ()
{
}
template<typename S>
STLLargeAlignedAllocator<T> &operator=(const STLLargeAlignedAllocator<S> &cp) throw ()
{
return *this;
}
pointer allocate(size_type Count, const void *Hint = 0)
{
return (pointer)LargeAligned::Acquire((u32)Count * sizeof(T));
}
void deallocate(pointer Ptr, size_type Count)
{
LargeAligned::Release(Ptr);
}
void construct(pointer Ptr, const T &Val)
{
std::_Construct(Ptr, Val);
}
void destroy(pointer Ptr)
{
std::_Destroy(Ptr);
}
size_type max_size() const
{
return 0x00FFFFFF;
}
template<typename S>
bool operator==(STLLargeAlignedAllocator <S> const &) const throw()
{
return true;
}
template<typename S>
bool operator!=(STLLargeAlignedAllocator <S> const &) const throw()
{
return false;
}
};
#endif
u32 GetCacheLineBytes();
} // namespace cat
// Provide placement new constructor and delete pair to allow for
// an easy syntax to create objects from the RegionAllocator:
// T *a = new (Aligned()) T();
// The object can be freed with:
// Aligned::Delete(a);
// Which insures that the destructor is called before freeing memory
CAT_INLINE void *operator new[](std::size_t bytes, cat::Aligned &) throw()
{
return cat::Aligned::Acquire((int)bytes);
}
// Placement "delete": Does not call destructor
CAT_INLINE void operator delete(void *ptr, cat::Aligned &) throw()
{
cat::Aligned::Release(ptr);
}
#endif // CAT_ENDIAN_NEUTRAL_HPP

View File

@ -0,0 +1,185 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_ENDIAN_NEUTRAL_HPP
#define CAT_ENDIAN_NEUTRAL_HPP
#include <cat/Platform.hpp>
namespace cat {
// getLE() converts from little-endian word to native byte-order word
// getBE() converts from big-endian word to native byte-order word
template<typename T>
CAT_INLINE T NoChangeNeeded(const T t)
{
return t;
}
#if defined(CAT_ENDIAN_LITTLE)
# define swapLE(n) NoChangeNeeded(n)
# define getLE(n) NoChangeNeeded(n)
# define getLE16(n) NoChangeNeeded(n)
# define getLE32(n) NoChangeNeeded(n)
# define getLE64(n) NoChangeNeeded(n)
CAT_INLINE u16 swapBE(u16 &n) { return n = CAT_BOSWAP16(n); }
CAT_INLINE u32 swapBE(u32 &n) { return n = CAT_BOSWAP32(n); }
CAT_INLINE u64 swapBE(u64 &n) { return n = CAT_BOSWAP64(n); }
CAT_INLINE u16 getBE(u16 n) { return CAT_BOSWAP16(n); }
CAT_INLINE u32 getBE(u32 n) { return CAT_BOSWAP32(n); }
CAT_INLINE u64 getBE(u64 n) { return CAT_BOSWAP64(n); }
CAT_INLINE u16 getBE16(u16 n) { return CAT_BOSWAP16(n); }
CAT_INLINE u32 getBE32(u32 n) { return CAT_BOSWAP32(n); }
CAT_INLINE u64 getBE64(u64 n) { return CAT_BOSWAP64(n); }
CAT_INLINE s16 swapBE(s16 &n) { return n = CAT_BOSWAP16((u16)n); }
CAT_INLINE s32 swapBE(s32 &n) { return n = CAT_BOSWAP32((u32)n); }
CAT_INLINE s64 swapBE(s64 &n) { return n = CAT_BOSWAP64((u64)n); }
CAT_INLINE s16 getBE(s16 n) { return CAT_BOSWAP16((u16)n); }
CAT_INLINE s32 getBE(s32 n) { return CAT_BOSWAP32((u32)n); }
CAT_INLINE s64 getBE(s64 n) { return CAT_BOSWAP64((u64)n); }
CAT_INLINE float getBE(float n) {
Float32 c = n;
c.i = CAT_BOSWAP32(c.i);
return c.f;
}
#elif defined(CAT_ENDIAN_BIG)
# define swapBE(n) NoChangeNeeded(n)
# define getBE(n) NoChangeNeeded(n)
# define getBE16(n) NoChangeNeeded(n)
# define getBE32(n) NoChangeNeeded(n)
# define getBE64(n) NoChangeNeeded(n)
CAT_INLINE u16 swapLE(u16 &n) { return n = CAT_BOSWAP16(n); }
CAT_INLINE u32 swapLE(u32 &n) { return n = CAT_BOSWAP32(n); }
CAT_INLINE u64 swapLE(u64 &n) { return n = CAT_BOSWAP64(n); }
CAT_INLINE u16 getLE(u16 n) { return CAT_BOSWAP16(n); }
CAT_INLINE u32 getLE(u32 n) { return CAT_BOSWAP32(n); }
CAT_INLINE u64 getLE(u64 n) { return CAT_BOSWAP64(n); }
CAT_INLINE u16 getLE16(u16 n) { return CAT_BOSWAP16(n); }
CAT_INLINE u32 getLE32(u32 n) { return CAT_BOSWAP32(n); }
CAT_INLINE u64 getLE64(u64 n) { return CAT_BOSWAP64(n); }
CAT_INLINE s16 swapLE(s16 &n) { return n = CAT_BOSWAP16((u16)n); }
CAT_INLINE s32 swapLE(s32 &n) { return n = CAT_BOSWAP32((u32)n); }
CAT_INLINE s64 swapLE(s64 &n) { return n = CAT_BOSWAP64((u64)n); }
CAT_INLINE s16 getLE(s16 n) { return CAT_BOSWAP16((u16)n); }
CAT_INLINE s32 getLE(s32 n) { return CAT_BOSWAP32((u32)n); }
CAT_INLINE s64 getLE(s64 n) { return CAT_BOSWAP64((u64)n); }
CAT_INLINE float getLE(float n) {
Float32 c = n;
c.i = CAT_BOSWAP32(c.i);
return c.f;
}
#elif defined(CAT_ENDIAN_UNKNOWN)
class RuntimeEndianDetector
{
public:
bool _big_endian, _little_endian;
RuntimeEndianDetector();
};
class Endianness
{
public:
static RuntimeEndianDetector detector;
static CAT_INLINE bool IsBigEndian() { return detector._big_endian; }
static CAT_INLINE bool IsLittleEndian() { return detector._little_endian; }
};
CAT_INLINE u16 swapBE(u16 &n) { return Endianness::IsBigEndian() ? n : n = CAT_BOSWAP16(n); }
CAT_INLINE u32 swapBE(u32 &n) { return Endianness::IsBigEndian() ? n : n = CAT_BOSWAP32(n); }
CAT_INLINE u64 swapBE(u64 &n) { return Endianness::IsBigEndian() ? n : n = CAT_BOSWAP64(n); }
CAT_INLINE u16 getBE(u16 n) { return Endianness::IsBigEndian() ? n : CAT_BOSWAP16(n); }
CAT_INLINE u32 getBE(u32 n) { return Endianness::IsBigEndian() ? n : CAT_BOSWAP32(n); }
CAT_INLINE u64 getBE(u64 n) { return Endianness::IsBigEndian() ? n : CAT_BOSWAP64(n); }
CAT_INLINE u16 getBE16(u16 n) { return Endianness::IsBigEndian() ? n : CAT_BOSWAP16(n); }
CAT_INLINE u32 getBE32(u32 n) { return Endianness::IsBigEndian() ? n : CAT_BOSWAP32(n); }
CAT_INLINE u64 getBE64(u64 n) { return Endianness::IsBigEndian() ? n : CAT_BOSWAP64(n); }
CAT_INLINE s16 swapBE(s16 &n) { return Endianness::IsBigEndian() ? n : n = CAT_BOSWAP16((u16)n); }
CAT_INLINE s32 swapBE(s32 &n) { return Endianness::IsBigEndian() ? n : n = CAT_BOSWAP32((u32)n); }
CAT_INLINE s64 swapBE(s64 &n) { return Endianness::IsBigEndian() ? n : n = CAT_BOSWAP64((u64)n); }
CAT_INLINE s16 getBE(s16 n) { return Endianness::IsBigEndian() ? n : CAT_BOSWAP16((u16)n); }
CAT_INLINE s32 getBE(s32 n) { return Endianness::IsBigEndian() ? n : CAT_BOSWAP32((u32)n); }
CAT_INLINE s64 getBE(s64 n) { return Endianness::IsBigEndian() ? n : CAT_BOSWAP64((u64)n); }
CAT_INLINE float getBE(float n)
{
if (Endianness::IsBigEndian())
return n;
else
{
Float32 c = n;
c.i = CAT_BOSWAP32(c.i);
return c.f;
}
}
CAT_INLINE u16 swapLE(u16 &n) { return Endianness::IsLittleEndian() ? n : n = CAT_BOSWAP16(n); }
CAT_INLINE u32 swapLE(u32 &n) { return Endianness::IsLittleEndian() ? n : n = CAT_BOSWAP32(n); }
CAT_INLINE u64 swapLE(u64 &n) { return Endianness::IsLittleEndian() ? n : n = CAT_BOSWAP64(n); }
CAT_INLINE u16 getLE(u16 n) { return Endianness::IsLittleEndian() ? n : CAT_BOSWAP16(n); }
CAT_INLINE u32 getLE(u32 n) { return Endianness::IsLittleEndian() ? n : CAT_BOSWAP32(n); }
CAT_INLINE u64 getLE(u64 n) { return Endianness::IsLittleEndian() ? n : CAT_BOSWAP64(n); }
CAT_INLINE u16 getLE16(u16 n) { return Endianness::IsLittleEndian() ? n : CAT_BOSWAP16(n); }
CAT_INLINE u32 getLE32(u32 n) { return Endianness::IsLittleEndian() ? n : CAT_BOSWAP32(n); }
CAT_INLINE u64 getLE64(u64 n) { return Endianness::IsLittleEndian() ? n : CAT_BOSWAP64(n); }
CAT_INLINE s16 swapLE(s16 &n) { return Endianness::IsLittleEndian() ? n : n = CAT_BOSWAP16((u16)n); }
CAT_INLINE s32 swapLE(s32 &n) { return Endianness::IsLittleEndian() ? n : n = CAT_BOSWAP32((u32)n); }
CAT_INLINE s64 swapLE(s64 &n) { return Endianness::IsLittleEndian() ? n : n = CAT_BOSWAP64((u64)n); }
CAT_INLINE s16 getLE(s16 n) { return Endianness::IsLittleEndian() ? n : CAT_BOSWAP16((u16)n); }
CAT_INLINE s32 getLE(s32 n) { return Endianness::IsLittleEndian() ? n : CAT_BOSWAP32((u32)n); }
CAT_INLINE s64 getLE(s64 n) { return Endianness::IsLittleEndian() ? n : CAT_BOSWAP64((u64)n); }
CAT_INLINE float getLE(float n)
{
if (Endianness::IsLittleEndian())
return n;
else
{
Float32 c = n;
c.i = CAT_BOSWAP32(c.i);
return c.f;
}
}
#endif
} // namespace cat
#endif // CAT_ENDIAN_NEUTRAL_HPP

View File

@ -0,0 +1,40 @@
/*
Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_WINDOWS_INCLUDE_HPP
#define CAT_WINDOWS_INCLUDE_HPP
#undef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0502 /* Windows XP SP2 or later */
#include <windows.h>
#endif // CAT_WINDOWS_INCLUDE_HPP

View File

@ -0,0 +1,76 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_I_RANDOM_HPP
#define CAT_I_RANDOM_HPP
#include <cat/Platform.hpp>
namespace cat {
// Pseudo-random number generators will derive from IRandom and implement its public methods
// WARNING: Not seeded by default. Be sure to call Initialize() before Generate()
class IRandom
{
public:
virtual ~IRandom() {}
// Generate a 32-bit random number
virtual u32 Generate() = 0;
// Generate a variable number of random bytes
virtual void Generate(void *buffer, int bytes) = 0;
public:
// Generate a 32-bit random number in the range [low..high] inclusive
u32 GenerateUnbiased(u32 low, u32 high)
{
u32 range = high - low;
// Round range up to the next pow(2)-1 using a Stanford Bit Twiddling Hack
u32 v = range - 1;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
// Generate an unbiased random number in the inclusive range [0..(high-low)]
u32 x;
do x = Generate() & v;
while (x > range);
return low + x;
}
};
} // namespace cat
#endif // CAT_I_RANDOM_HPP

View File

@ -0,0 +1,90 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Algorithm by Makoto Matsumoto
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
*/
#ifndef CAT_MERSENNE_TWISTER_HPP
#define CAT_MERSENNE_TWISTER_HPP
#include <cat/rand/IRandom.hpp>
namespace cat {
// Noncryptographic pseudo-random number generator
class MersenneTwister : public IRandom
{
static const u32 MEXP = 19937;
static const u32 N128 = MEXP/128 + 1;
static const u32 N64 = N128 * 2;
static const u32 N32 = N128 * 4;
static const u32 POS1 = 122;
static const u32 SL1 = 18;
static const u32 SL2 = 1;
static const u32 SL2BITS = SL2*8;
static const u32 SR1 = 11;
static const u32 SR2 = 1;
static const u32 SR2BITS = SR2*8;
static const u32 MSK1 = 0xdfffffefU;
static const u32 MSK2 = 0xddfecb7fU;
static const u32 MSK3 = 0xbffaffffU;
static const u32 MSK4 = 0xbffffff6U;
struct MT128 {
u32 u[4];
};
MT128 state[19937/128 + 1];
u32 *state32;
u32 used;
CAT_INLINE void shiftLeft128(MT128 *r, MT128 *n, u32 bits);
CAT_INLINE void shiftRight128(MT128 *r, MT128 *n, u32 bits);
void enforcePeriod(); // make corrections to ensure that the generator has the full period
void round(MT128 *a, MT128 *b, MT128 *c, MT128 *d); // a = MTMIX(a,b,c,d)
void update(); // permute the existing state into a new one
public:
MersenneTwister();
bool Initialize(u32 seed);
bool Initialize(u32 *seeds, u32 words);
bool Initialize();
u32 Generate(); // generate a 32-bit number
void Generate(void *buffer, int bytes); // generate a series of random numbers
};
} // namespace cat
#endif // CAT_MERSENNE_TWISTER_HPP

View File

@ -0,0 +1,66 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CAT_STDRAND_HPP
#define CAT_STDRAND_HPP
#include <cat/Platform.hpp>
namespace cat {
// Microsoft VC++ 7.0 stdlib srand(), rand(), old RANDU()
class StandardRand
{
protected:
s32 seed;
public:
StandardRand(u32 ns = 0) { seed = ns; }
inline void srand32(u32 ns) { seed = ns; } // 32-bit version
inline void srand16(u16 ns) { seed = ns; } // 16-bit version (yup)
u16 rand(); // Linear Congruential Generator: X = X * M + A (mod N)
u16 randu(); // RANDU LCG: X = X * M (mod N)
float sfrand(); // Fast [-1.f,1.f] generator from Inigo Quilez (2005)
};
// Non-linear congruential 32-bit random mixing function for given x, y and seed
// This function is used in every example of Perlin noise I found online for some reason!
u32 NLCRand32(int x, int y, u32 seed);
// Uses NLCRand32 as a front-end, and then maps the output to a number between -1 and 1
float NLCRandNorm(int x, int y, u32 seed);
} // namespace cat
#endif // CAT_STDRAND_HPP

View File

@ -0,0 +1,118 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/AllFramework.hpp>
using namespace cat;
static DNSClient *dns_client = 0;
// Framework Initialize
bool cat::InitializeFramework(const char *settings_file, const char *service_name)
{
// Initialize clock subsystem
if (!Clock::Initialize())
{
FatalStop("Clock subsystem failed to initialize");
}
// Initialize custom memory allocator subsystem
if (!RegionAllocator::ref()->Valid())
{
FatalStop("Custom memory allocator failed to initialize");
}
// Initialize logging subsystem with INFO reporting level
Logging::ref()->Initialize(LVL_INFO);
if (service_name) Logging::ii->EnableServiceMode(service_name);
// Initialize disk settings subsystem
Settings::ref()->readSettingsFromFile(settings_file);
// Read logging subsystem settings
Logging::ref()->ReadSettings();
// Start the CSPRNG subsystem
if (!FortunaFactory::ref()->Initialize())
{
FATAL("Framework") << "Unable to initialize the CSPRNG";
ShutdownFramework(false);
return false;
}
// Start the socket subsystem
if (!StartupSockets())
{
FATAL("Framework") << "Unable to initialize Sockets: " << SocketGetLastErrorString();
ShutdownFramework(false);
return false;
}
// Start the worker threads
if (!ThreadPool::ref()->Startup())
{
FATAL("Framework") << "Unable to initialize the ThreadPool";
ShutdownFramework(false);
return false;
}
// Create DNSClient
if (!DNSClient::ref())
{
FATAL("Framework") << "Out of memory: Unable to create the DNSClient";
ShutdownFramework(false);
return false;
}
// Add a reference so that DNSClient cannot be destroyed
DNSClient::ii->AddRef();
return true;
}
// Framework Shutdown
void cat::ShutdownFramework(bool WriteSettings)
{
// Shutdown DNS client
DNSClient::ref()->Shutdown();
// Terminate worker threads
ThreadPool::ref()->Shutdown();
// Terminate sockets
CleanupSockets();
// Terminate the entropy collection thread in the CSPRNG
FortunaFactory::ref()->Shutdown();
// Write settings to disk if requested
if (WriteSettings)
Settings::ref()->write();
// Cleanup clock subsystem
Clock::Shutdown();
}

View File

@ -0,0 +1,769 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/codec/RangeCoder.hpp>
#include <cat/hash/MurmurHash2.hpp>
#include <cat/port/EndianNeutral.hpp>
#include <cmath>
#include <cstring>
using namespace cat;
using namespace std;
const u64 Top = (u64)1 << 56;
const u64 MaxRange = (u64)1 << 48;
#define SYMBOL_LUT_BITS 8
#define SYMBOL_LUT_SHIFT (16 - SYMBOL_LUT_BITS)
#define SYMBOL_LUT_BYTES (1 << SYMBOL_LUT_BITS)
#define SYMBOL_BYTES(total) (SYMBOL_LUT_BYTES + (total) - 1)
#define STATIC_TABLE_BYTES(total) (4 + 2 + 2 + 256 + 256 + 2 * (total) * SYMBOL_BYTES(total) + (total) * (16 * 4))
#define GET_SYMBOL_LUT(frequencies, total, index) ((const u8 *)((frequencies) + (index) * SYMBOL_BYTES(total)))
#define GET_SYMBOL_BASE(frequencies, total, index) ((const u16 *)(GET_SYMBOL_LUT((frequencies), (total), (index)) + SYMBOL_LUT_BYTES*2))
//// TextStatsCollector
TextStatsCollector::TextStatsCollector()
{
CAT_OBJCLR(frequencies);
CAT_OBJCLR(seen);
last = 0;
total = 0;
// The '\0' null terminator is always symbol 0 and always present
seen[0] = 1;
total = 1;
frequencies[0][0] = 1;
}
void TextStatsCollector::Tally(u8 x)
{
u32 &tf = frequencies[last][x];
// Increment frequency in table and check for overflow
// 2^24 is used as the limit so that there can be no cumulative
// overflow if all the frequencies are added together.
if (++tf >= 0x01000000)
{
// For each symbol that follows the last symbol,
for (int ii = 0; ii < 256; ++ii)
{
u32 &tm = frequencies[last][ii];
// Divide the frequencies by two
if (tm > 1) tm >>= 1;
}
}
if (!seen[x])
{
++total;
seen[x] = 1;
}
last = x;
}
bool TextStatsCollector::GenerateMinimalStaticTable(const char *TableName, std::ostream &osout)
{
u32 bytes = STATIC_TABLE_BYTES(total);
u8 *output = new u8[bytes + 3];
if (!output)
{
osout << "Out of memory";
return false;
}
TableFormat *table = (TableFormat *)output;
// Write char2index table and some index2char
u32 ii, jj;
for (jj = 0, ii = 0; ii < 256; ++ii)
{
if (seen[ii])
{
table->index2char[jj] = ii;
table->char2index[ii] = jj;
++jj;
}
else
{
table->char2index[ii] = 0;
}
}
// Write remainder of index2char table
while (jj < 256)
{
table->index2char[jj++] = 0;
}
// Generate normalized frequency table
u16 *freq = table->frequencies;
for (ii = 0; ii < total; ++ii)
{
u32 sum = 0, adjcum = 0;
u32 work[256];
u32 tlast = table->index2char[ii];
for (jj = 0; jj < total; ++jj)
{
sum += frequencies[tlast][table->index2char[jj]];
work[jj] = sum;
}
char *dict = (char*)freq;
//memcpy(dict, frequent_words[table->index2char[ii]], DICTIONARY_WORDS * DICTIONARY_CHARS);
//u8 *lut_low = (u8*)(dict + DICTIONARY_WORDS * DICTIONARY_CHARS);
u8 *lut_low = (u8*)freq;
u8 *lut_high = lut_low + SYMBOL_LUT_BYTES;
freq += SYMBOL_LUT_BYTES;
u16 *symbol_freqs = freq;
u32 smax = work[total-1];
for (jj = 0; jj < total-1; ++jj)
{
// Normalize the cumulative frequency to the range [0, 2^16)
u32 adjcum_new;
if (smax)
adjcum_new = (u32)(((u64)work[jj] << 32) / smax) >> 16;
else
adjcum_new = (u32)(((u64)(jj+1) << 32) / total) >> 16;
// Insure monotonic increase
if (adjcum >= adjcum_new) adjcum_new = adjcum + 1;
adjcum = adjcum_new;
*freq++ = (u16)adjcum_new;
}
// It is possible that very unlikely symbols at the end will cause
// an overflow since monotonicity is enforced. Detect that overflow
// and correct it by borrowing from earlier symbols.
if (adjcum >= 0x10000)
{
u32 count = adjcum - 0xFFFF;
u32 last = 0;
u32 cumsub = 0;
for (jj = 0; jj < total-1; ++jj)
{
u32 slack = symbol_freqs[jj] - last;
if (slack >= 0x100)
cumsub = count;
symbol_freqs[jj] -= cumsub;
}
}
// Write LUT
u8 symbol = 0, last_high = 0, last_low = 0;
u32 high = 0;
for (jj = 0; jj < SYMBOL_LUT_BYTES; ++jj)
{
for (;;)
{
high = symbol_freqs[symbol] >> SYMBOL_LUT_SHIFT;
if (high > jj || symbol >= total - 1)
break;
last_high = symbol++;
}
lut_low[jj] = last_low;
lut_high[jj] = last_high;
last_low = last_high;
}
}
// Write header
table->total = total;
table->log2total = (u16)(std::log((double)total)/std::log((double)2) * 32768.0f / 8.0f);
table->hash = MurmurHash32(output + 4, bytes - 4, 0);
// Convert it to C code
osout << "// To include this table, do something like this:" << endl;
osout << "// #include \"" << TableName << ".stats\"" << endl << endl;
osout << "static const u32 _" << TableName << "[] = {" << endl;
u32 words = (bytes + 3)/4;
u32 *output32 = (u32*)output;
int line = 0;
while (words--)
{
//if (!line) osout << " ";
osout << "0x" << hex << *output32++;
// Cases for commas and newlines
if (words)
{
osout << ',';
if (++line >= 16)
{
osout << endl;
line = 0;
}
}
}
osout << "};" << endl << endl;
osout << "static const TextStatsCollector::TableFormat *" << TableName
<< " = (const TextStatsCollector::TableFormat*)_" << TableName << ';' << endl;
// Free memory from workspace
delete []output;
return true;
}
// Check for errors in the in-memory version of the table that was generated
bool TextStatsCollector::VerifyTableIntegrity(const TableFormat *table)
{
u32 total = table->total;
u32 bytes = STATIC_TABLE_BYTES(total);
if (MurmurHash32(&table->total, bytes - 4, 0) != table->hash)
return false;
if (table->total > 256)
return false;
int used = 0;
for (int ii = 0; ii < 256; ++ii)
{
u8 index = table->char2index[ii];
if (index)
{
if (table->index2char[index] != ii)
return false;
++used;
}
}
if (used + 1 != (int)total)
return false;
u16 flog = (u16)(std::log((double)total)/std::log((double)2) * 32768.0f / 8.0f);
if (flog != table->log2total)
return false;
used = 0;
for (int ii = 0; ii < 256; ++ii)
{
if (table->index2char[ii])
++used;
}
if (used + 1 != (int)total)
return false;
for (u32 ii = 0; ii < total; ++ii)
{
u32 last = 0;
for (u32 jj = 0; jj < total - 1; ++jj)
{
u32 x = GET_SYMBOL_BASE(table->frequencies, total, ii)[jj];
if (last >= x)
return false;
//u32 range = x - last;
last = x;
}
const u8 *lut_low = GET_SYMBOL_LUT(table->frequencies, total, ii);
const u8 *lut_high = lut_low + SYMBOL_LUT_BYTES;
for (u32 jj = 0; jj < SYMBOL_LUT_BYTES; ++jj)
{
if (lut_low[jj] > lut_high[jj])
return false;
if (lut_low[jj] >= total - 1)
return false;
if (lut_high[jj] >= total - 1)
return false;
}
}
return true;
}
//// RangeEncoder
// Intializing constructor
RangeEncoder::RangeEncoder(void *output_i, int limit_i)
{
output = (u8*)output_i;
remaining = limit = limit_i;
range = 0;
}
// Copy Constructor
// See header for usage
RangeEncoder::RangeEncoder(RangeEncoder &cp)
{
output = cp.output;
limit = cp.limit;
remaining = cp.remaining;
low = cp.low;
range = cp.range;
}
// Overwrite one context with another. Using context references instead
// of working on the contexts directly is probably more efficient.
RangeEncoder &RangeEncoder::operator=(RangeEncoder &cp)
{
output = cp.output;
limit = cp.limit;
remaining = cp.remaining;
low = cp.low;
range = cp.range;
return *this;
}
// Write out bytes as needed
void RangeEncoder::Normalize()
{
while ((low ^ (low + range)) < Top ||
range < MaxRange && ((range = -(s64)low & (MaxRange - 1)),1))
{
// If we're out of room, fail
if (!remaining)
{
output = 0;
return;
}
--remaining;
// Store the shifted out byte
*output++ = (u8)(low >> 56);
range <<= 8;
low <<= 8;
}
}
// Grab symbol low frequency and range from the table
void RangeEncoder::GetTableSymbol(const TextStatsCollector::TableFormat *stats, u32 &last, u8 ch, u16 &symbol_low, u16 &symbol_range)
{
u8 symbol = stats->char2index[ch];
const u16 *base = GET_SYMBOL_BASE(stats->frequencies, stats->total, last);
if (symbol)
{
symbol_low = base[symbol - 1];
if (symbol == stats->total - 1)
symbol_range = (u16)(0x10000 - symbol_low);
else
symbol_range = base[symbol] - symbol_low;
}
else
{
symbol_low = 0;
symbol_range = base[0];
}
last = symbol;
}
// Encode the given text with the given statistics
// NOTE: May be up to one byte longer than the original message
void RangeEncoder::Text(const char *msg, const TextStatsCollector::TableFormat *stats)
{
u8 *backup_output = output;
int backup_remaining = remaining;
u64 backup_low = low, backup_range = range;
const char *backup_msg = msg;
BiasedBit(0, 0xFF000000);
// Encode with order-1 statistics
u16 symbol_low, symbol_range;
u32 last = 0;
do
{
Normalize();
GetTableSymbol(stats, last, (u8)*msg++, symbol_low, symbol_range);
range >>= 16;
low += symbol_low * range;
range *= symbol_range;
} while (symbol_low);
int len = (int)(msg - backup_msg);
// If the tables failed, fall back to uniform distribution
if ((backup_remaining - remaining) > (len * stats->log2total) >> 15)
{
// Restore state
output = backup_output;
remaining = backup_remaining;
low = backup_low;
range = backup_range;
msg = backup_msg;
BiasedBit(1, 0xFF000000);
// Uniform range encode
u8 ch;
do
{
Normalize();
ch = (u8)*msg++;
range /= stats->total;
low += stats->char2index[ch] * range;
} while (ch);
}
}
// Compress a biased bit given the frequency it is set
// frequency = average times out of 2^32 trials the bit will be 0
void RangeEncoder::BiasedBit(u32 b, u32 frequency)
{
if (!range)
{
if (b)
{
low = (u64)frequency << 32;
range = (u64)(-(s32)frequency) << 32;
}
else
{
low = 0;
range = (u64)frequency << 32;
}
}
else
{
Normalize();
range >>= 32;
if (b)
{
low += frequency * range;
range *= (u32)(-(s32)frequency);
}
else
{
range *= frequency;
}
}
}
// Encode a field that takes on [0, total) values with equal likelihood
void RangeEncoder::Range(u32 symbol, u32 total)
{
if (!range)
{
range = 0xFFFFFFFFFFFFFFFFLL / total;
low = symbol * range;
}
else
{
Normalize();
range /= total;
low += symbol * range;
}
}
// Emit the final byte(s) needed to encode the symbols
void RangeEncoder::Finish()
{
// Output a minimal number of bytes, up to 2
Normalize();
if (!low) return;
if (!remaining)
output = 0;
else
{
--remaining;
low += range - 1;
*output++ = (u8)(low >> 56);
if (range < Top)
{
low <<= 8;
if (!remaining)
{
output = 0;
return;
}
*output++ = (u8)(low >> 56);
--remaining;
}
}
}
//// RangeDecoder
// Intializing constructor
RangeDecoder::RangeDecoder(const void *message, int bytes)
{
const u8 *m8 = (const u8*)message;
range = 0;
// Read up to 8 bytes of the frequency code
if (bytes < 8)
{
code = 0;
remaining = 0;
u8 *code8 = (u8*)&code;
switch (bytes)
{
#if defined(CAT_ENDIAN_LITTLE)
case 7: code8[1] = m8[6];
case 6: code8[2] = m8[5];
case 5: code8[3] = m8[4];
case 4: *(u32*)&code8[4] = getBE(*(u32*)m8);
break;
case 3: code8[5] = m8[2];
case 2: code8[6] = m8[1];
case 1: code8[7] = m8[0];
#elif defined(CAT_ENDIAN_BIG)
case 7: code8[6] = m8[6];
case 6: code8[5] = m8[5];
case 5: code8[4] = m8[4];
case 4: *(u32*)code8 = *(u32*)m8;
break;
case 3: code8[2] = m8[2];
case 2: code8[1] = m8[1];
case 1: code8[0] = m8[0];
#else
#error "Fix this you lazy bastard"
#endif
}
}
else
{
code = getBE(*(u64*)m8);
input = m8 + 8;
remaining = bytes - 8;
}
}
// Read in bytes as needed
void RangeDecoder::Normalize()
{
while ((low ^ (low + range)) < Top ||
range < MaxRange && ((range = -(s64)low & (MaxRange - 1)),1))
{
code <<= 8;
if (remaining)
{
code |= *input++;
--remaining;
}
low <<= 8;
range <<= 8;
}
}
// Grab symbol low frequency and range from the table
u8 RangeDecoder::GetTableSymbol(const TextStatsCollector::TableFormat *stats, u32 &last, u16 freq, u16 &symbol_low, u16 &symbol_range)
{
const u8 *lut = GET_SYMBOL_LUT(stats->frequencies, stats->total, last);
const u16 *base = (const u16 *)(lut + SYMBOL_LUT_BYTES * 2);
u32 lut_bits = freq >> SYMBOL_LUT_SHIFT;
// Binary search for the symbol
u32 below = lut[lut_bits], above = lut[SYMBOL_LUT_BYTES + lut_bits];
while (below != above)
{
u32 pivot = (above - below + 1) / 2 + below;
if (freq >= base[pivot])
below = pivot;
else
above = pivot - 1;
}
u8 symbol;
// Offset it for the unlisted zero element
if (below || freq >= base[0])
{
symbol_low = base[below];
++below;
if ((int)below == stats->total - 1)
symbol_range = (u16)(0x10000 - symbol_low);
else
symbol_range = base[below] - symbol_low;
symbol = (u8)below;
}
else
{
symbol_low = 0;
symbol_range = base[0];
symbol = 0;
}
last = symbol;
return symbol;
}
// Decode the given text with the given statistics
int RangeDecoder::Text(char *msg, int buffer_size, const TextStatsCollector::TableFormat *stats)
{
u16 symbol_low, symbol_range;
u32 last = 0;
char *init_msg = msg;
if (BiasedBit(0xFF000000))
{
// Selected uniform model
while (--buffer_size > 0)
{
Normalize();
range /= stats->total;
u8 symbol = (u8)((code - low) / range);
low += symbol * range;
last = stats->index2char[symbol];
if (!last) break;
*msg++ = (char)last;
}
}
else
{
// Selected order-1 static model
while (--buffer_size > 0)
{
Normalize();
range >>= 16;
u16 x = (u16)((code - low) / range);
u8 symbol = GetTableSymbol(stats, last, x, symbol_low, symbol_range);
low += symbol_low * range;
range *= symbol_range;
if (!symbol) break;
*msg++ = (char)stats->index2char[symbol];
--buffer_size;
}
}
*msg = '\0';
return (int)(msg - init_msg);
}
// Decompress a biased bit given the frequency it is set
// frequency = average times out of 2^32 trials the bit will be 0
u32 RangeDecoder::BiasedBit(u32 frequency)
{
if (!range)
{
// Treat the first encoding specially.
if ((u32)(code >> 32) < frequency)
{
low = 0;
range = (u64)frequency << 32;
return 0;
}
else
{
low = (u64)frequency << 32;
range = (u64)(-(s32)frequency) << 32;
return 1;
}
}
else
{
Normalize();
range >>= 32;
u32 x = (u32)((code - low) / range);
if (x < frequency)
{
range *= frequency;
return 0;
}
else
{
low += frequency * range;
range *= (u32)(-(s32)frequency);
return 1;
}
}
}
// Decode a field that takes on [0, total) values with equal likelihood
u32 RangeDecoder::Range(u32 total)
{
u32 symbol;
if (!range)
{
range = 0xFFFFFFFFFFFFFFFFLL / total;
symbol = (u32)(code / range);
low = symbol * range;
}
else
{
Normalize();
range /= total;
symbol = (u32)((code - low) / range);
low += symbol * range;
}
return symbol;
}

View File

@ -0,0 +1,72 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/crypt/SecureCompare.hpp>
namespace cat {
bool SecureEqual(const void *vA, const void *vB, int bytes)
{
const u8 *A = (const u8*)vA;
const u8 *B = (const u8*)vB;
u64 fail = 0;
// Accumulate failures, 8 bytes at a time
int qwords = bytes >> 3;
if (qwords)
{
const u64 *A64 = (const u64 *)A;
const u64 *B64 = (const u64 *)B;
for (int ii = 0; ii < qwords; ++ii)
fail |= A64[ii] ^ B64[ii];
A = (const u8 *)&A64[qwords];
B = (const u8 *)&B64[qwords];
}
// Accumulate failures, bytes at a time
bytes &= 7;
switch (bytes)
{
case 7: fail |= A[6] ^ B[6];
case 6: fail |= A[5] ^ B[5];
case 5: fail |= A[4] ^ B[4];
case 4: fail |= *(const u32 *)A ^ *(const u32 *)B;
break;
case 3: fail |= A[2] ^ B[2];
case 2: fail |= A[1] ^ B[1];
case 1: fail |= A[0] ^ B[0];
}
return fail == 0;
}
} // namespace cat

View File

@ -0,0 +1,169 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/crypt/cookie/CookieJar.hpp>
#include <cat/time/Clock.hpp>
#include <cat/math/BitMath.hpp>
using namespace cat;
// Initialize to a random 512-bit key on startup
void CookieJar::Initialize(FortunaOutput *csprng)
{
csprng->Generate(key, sizeof(key));
}
u32 CookieJar::Salsa6(u32 *x)
{
// 6 rounds of Salsa20
for (int ii = 6; ii > 0; ii -= 2)
{
x[4] ^= CAT_ROL32(x[0] + x[12], 7);
x[8] ^= CAT_ROL32(x[4] + x[0], 9);
x[12] ^= CAT_ROL32(x[8] + x[4], 13);
x[0] ^= CAT_ROL32(x[12] + x[8], 18);
x[9] ^= CAT_ROL32(x[5] + x[1], 7);
x[13] ^= CAT_ROL32(x[9] + x[5], 9);
x[1] ^= CAT_ROL32(x[13] + x[9], 13);
x[5] ^= CAT_ROL32(x[1] + x[13], 18);
x[14] ^= CAT_ROL32(x[10] + x[6], 7);
x[2] ^= CAT_ROL32(x[14] + x[10], 9);
x[6] ^= CAT_ROL32(x[2] + x[14], 13);
x[10] ^= CAT_ROL32(x[6] + x[2], 18);
x[3] ^= CAT_ROL32(x[15] + x[11], 7);
x[7] ^= CAT_ROL32(x[3] + x[15], 9);
x[11] ^= CAT_ROL32(x[7] + x[3], 13);
x[15] ^= CAT_ROL32(x[11] + x[7], 18);
x[1] ^= CAT_ROL32(x[0] + x[3], 7);
x[2] ^= CAT_ROL32(x[1] + x[0], 9);
x[3] ^= CAT_ROL32(x[2] + x[1], 13);
x[0] ^= CAT_ROL32(x[3] + x[2], 18);
x[6] ^= CAT_ROL32(x[5] + x[4], 7);
x[7] ^= CAT_ROL32(x[6] + x[5], 9);
x[4] ^= CAT_ROL32(x[7] + x[6], 13);
x[5] ^= CAT_ROL32(x[4] + x[7], 18);
x[11] ^= CAT_ROL32(x[10] + x[9], 7);
x[8] ^= CAT_ROL32(x[11] + x[10], 9);
x[9] ^= CAT_ROL32(x[8] + x[11], 13);
x[10] ^= CAT_ROL32(x[9] + x[8], 18);
x[12] ^= CAT_ROL32(x[15] + x[14], 7);
x[13] ^= CAT_ROL32(x[12] + x[15], 9);
x[14] ^= CAT_ROL32(x[13] + x[12], 13);
x[15] ^= CAT_ROL32(x[14] + x[13], 18);
}
return x[0] ^ x[5] ^ x[10] ^ x[15];
}
u32 CookieJar::Hash(u32 ip, u16 port, u32 epoch)
{
u32 x[16];
memcpy(x, key, sizeof(x));
x[4] += ip;
x[6] += epoch;
x[8] += port;
x[10] += epoch;
return Salsa6(x);
}
u32 CookieJar::Hash(const void *address_info, int bytes, u32 epoch)
{
u32 x[16];
memcpy(x, key, sizeof(x));
// Add address info to the key one word at a time
const u32 *info32 = (const u32 *)address_info;
u32 *y = &x[4];
while (bytes >= 4)
{
*y++ += *info32++;
bytes -= 4;
}
// Add final 1..3 address info bytes to the key
const u8 *info8 = (const u8 *)info32;
switch (bytes)
{
case 3: *y += ((u32)info8[2] << 16) | *(const u16*)info8; break;
case 2: *y += *(const u16*)info8; break;
case 1: *y += info8[0]; break;
}
x[6] += epoch;
x[10] += epoch;
return Salsa6(x);
}
u32 CookieJar::GetEpoch()
{
return Clock::msec_fast() / BIN_TIME;
}
u32 CookieJar::ReconstructEpoch(u32 cookie)
{
u32 epoch = GetEpoch();
u32 cookie_bin = cookie & BIN_MASK;
// Attempt to reconstruct the epoch used to generate this cookie
u32 cookie_epoch = (epoch & ~BIN_MASK) | cookie_bin;
// If the cookie's bin is ahead of the bin in this interval, then
// this cookie must be from the previous interval to be valid.
if (cookie_bin > (epoch & BIN_MASK)) cookie_epoch -= BIN_COUNT;
return cookie_epoch;
}
u32 CookieJar::Generate(u32 ip, u16 port)
{
u32 epoch = GetEpoch();
return (Hash(ip, port, epoch) << 4) | (epoch & BIN_MASK);
}
bool CookieJar::Verify(u32 ip, u16 port, u32 cookie)
{
return (Hash(ip, port, ReconstructEpoch(cookie)) << 4) == (cookie & ~BIN_MASK);
}
u32 CookieJar::Generate(const void *address_info, int bytes)
{
u32 epoch = GetEpoch();
return (Hash(address_info, bytes, epoch) << 4) | (epoch & BIN_MASK);
}
bool CookieJar::Verify(const void *address_info, int bytes, u32 cookie)
{
return (Hash(address_info, bytes, ReconstructEpoch(cookie)) << 4) == (cookie & ~BIN_MASK);
}

View File

@ -0,0 +1,367 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/crypt/hash/HMAC_MD5.hpp>
#include <cat/math/BitMath.hpp>
#include <cat/port/EndianNeutral.hpp>
using namespace cat;
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
// NOTE: Uses little-endian integers instead of big-endian as in standard MD5
#define ROUND(a, b, Fbcd, x, o, s, ac) \
(a) += Fbcd + getLE(x[o]) + (u32)(ac); \
(a) = CAT_ROL32((a), (s)); \
(a) += (b);
#define FF(a, b, c, d, x,o, s, ac) ROUND(a, b, F(b,c,d), x, o, s, ac)
#define GG(a, b, c, d, x,o, s, ac) ROUND(a, b, G(b,c,d), x, o, s, ac)
#define HH(a, b, c, d, x,o, s, ac) ROUND(a, b, H(b,c,d), x, o, s, ac)
#define II(a, b, c, d, x,o, s, ac) ROUND(a, b, I(b,c,d), x, o, s, ac)
//// HMAC_MD5
void HMAC_MD5::HashComputation(const void *message, int blocks, u32 *NextState)
{
u32 *words = (u32*)message;
u32 a0 = State[0], b0 = State[1], c0 = State[2], d0 = State[3];
while (blocks--)
{
u32 a = a0, b = b0, c = c0, d = d0;
#ifdef CAT_AUDIT
printf("AUDIT: MD5 ");
for (int ii = 0; ii < 64; ++ii)
{
printf("%02x", ((u8*)words)[ii]);
}
printf("\n");
#endif
// Round 1
const int S11 = 7;
const int S12 = 12;
const int S13 = 17;
const int S14 = 22;
FF(a, b, c, d, words, 0, S11, 0xd76aa478); // 1
FF(d, a, b, c, words, 1, S12, 0xe8c7b756); // 2
FF(c, d, a, b, words, 2, S13, 0x242070db); // 3
FF(b, c, d, a, words, 3, S14, 0xc1bdceee); // 4
FF(a, b, c, d, words, 4, S11, 0xf57c0faf); // 5
FF(d, a, b, c, words, 5, S12, 0x4787c62a); // 6
FF(c, d, a, b, words, 6, S13, 0xa8304613); // 7
FF(b, c, d, a, words, 7, S14, 0xfd469501); // 8
FF(a, b, c, d, words, 8, S11, 0x698098d8); // 9
FF(d, a, b, c, words, 9, S12, 0x8b44f7af); // 10
FF(c, d, a, b, words, 10, S13, 0xffff5bb1); // 11
FF(b, c, d, a, words, 11, S14, 0x895cd7be); // 12
FF(a, b, c, d, words, 12, S11, 0x6b901122); // 13
FF(d, a, b, c, words, 13, S12, 0xfd987193); // 14
FF(c, d, a, b, words, 14, S13, 0xa679438e); // 15
FF(b, c, d, a, words, 15, S14, 0x49b40821); // 16
// Round 2
const int S21 = 5;
const int S22 = 9;
const int S23 = 14;
const int S24 = 20;
GG(a, b, c, d, words, 1, S21, 0xf61e2562); // 17
GG(d, a, b, c, words, 6, S22, 0xc040b340); // 18
GG(c, d, a, b, words, 11, S23, 0x265e5a51); // 19
GG(b, c, d, a, words, 0, S24, 0xe9b6c7aa); // 20
GG(a, b, c, d, words, 5, S21, 0xd62f105d); // 21
GG(d, a, b, c, words, 10, S22, 0x2441453); // 22
GG(c, d, a, b, words, 15, S23, 0xd8a1e681); // 23
GG(b, c, d, a, words, 4, S24, 0xe7d3fbc8); // 24
GG(a, b, c, d, words, 9, S21, 0x21e1cde6); // 25
GG(d, a, b, c, words, 14, S22, 0xc33707d6); // 26
GG(c, d, a, b, words, 3, S23, 0xf4d50d87); // 27
GG(b, c, d, a, words, 8, S24, 0x455a14ed); // 28
GG(a, b, c, d, words, 13, S21, 0xa9e3e905); // 29
GG(d, a, b, c, words, 2, S22, 0xfcefa3f8); // 30
GG(c, d, a, b, words, 7, S23, 0x676f02d9); // 31
GG(b, c, d, a, words, 12, S24, 0x8d2a4c8a); // 32
// Round 3
const int S31 = 4;
const int S32 = 11;
const int S33 = 16;
const int S34 = 23;
HH(a, b, c, d, words, 5, S31, 0xfffa3942); // 33
HH(d, a, b, c, words, 8, S32, 0x8771f681); // 34
HH(c, d, a, b, words, 11, S33, 0x6d9d6122); // 35
HH(b, c, d, a, words, 14, S34, 0xfde5380c); // 36
HH(a, b, c, d, words, 1, S31, 0xa4beea44); // 37
HH(d, a, b, c, words, 4, S32, 0x4bdecfa9); // 38
HH(c, d, a, b, words, 7, S33, 0xf6bb4b60); // 39
HH(b, c, d, a, words, 10, S34, 0xbebfbc70); // 40
HH(a, b, c, d, words, 13, S31, 0x289b7ec6); // 41
HH(d, a, b, c, words, 0, S32, 0xeaa127fa); // 42
HH(c, d, a, b, words, 3, S33, 0xd4ef3085); // 43
HH(b, c, d, a, words, 6, S34, 0x4881d05); // 44
HH(a, b, c, d, words, 9, S31, 0xd9d4d039); // 45
HH(d, a, b, c, words, 12, S32, 0xe6db99e5); // 46
HH(c, d, a, b, words, 15, S33, 0x1fa27cf8); // 47
HH(b, c, d, a, words, 2, S34, 0xc4ac5665); // 48
// Round 4
const int S41 = 6;
const int S42 = 10;
const int S43 = 15;
const int S44 = 21;
II(a, b, c, d, words, 0, S41, 0xf4292244); // 49
II(d, a, b, c, words, 7, S42, 0x432aff97); // 50
II(c, d, a, b, words, 14, S43, 0xab9423a7); // 51
II(b, c, d, a, words, 5, S44, 0xfc93a039); // 52
II(a, b, c, d, words, 12, S41, 0x655b59c3); // 53
II(d, a, b, c, words, 3, S42, 0x8f0ccc92); // 54
II(c, d, a, b, words, 10, S43, 0xffeff47d); // 55
II(b, c, d, a, words, 1, S44, 0x85845dd1); // 56
II(a, b, c, d, words, 8, S41, 0x6fa87e4f); // 57
II(d, a, b, c, words, 15, S42, 0xfe2ce6e0); // 58
II(c, d, a, b, words, 6, S43, 0xa3014314); // 59
II(b, c, d, a, words, 13, S44, 0x4e0811a1); // 60
II(a, b, c, d, words, 4, S41, 0xf7537e82); // 61
II(d, a, b, c, words, 11, S42, 0xbd3af235); // 62
II(c, d, a, b, words, 2, S43, 0x2ad7d2bb); // 63
II(b, c, d, a, words, 9, S44, 0xeb86d391); // 64
a0 += a;
b0 += b;
c0 += c;
d0 += d;
words += 16;
}
NextState[0] = a0;
NextState[1] = b0;
NextState[2] = c0;
NextState[3] = d0;
}
HMAC_MD5::~HMAC_MD5()
{
CAT_OBJCLR(State);
CAT_OBJCLR(Work);
CAT_OBJCLR(CachedInitialState);
CAT_OBJCLR(CachedFinalState);
byte_counter = 0;
used_bytes = 0;
}
bool HMAC_MD5::SetKey(ICryptHash *parent)
{
State[0] = 0x27b70a85;
State[1] = 0x2e1b2138;
State[2] = 0x4d2c6dfc;
State[3] = 0x53380d13;
static const int KEY_BYTES = WORK_BYTES / 2;
u8 Key[KEY_BYTES];
parent->Generate(Key, KEY_BYTES);
// Using the parent hash function, generate key bytes to fill half a block
memcpy(Work, Key, KEY_BYTES);
memset(Work + KEY_BYTES, 0x36, WORK_BYTES - KEY_BYTES); // Pad to fill a whole block
// Crunch one whole block
HashComputation(Work, 1, State);
// Store this as the cached initial state
memcpy(CachedInitialState, State, DIGEST_BYTES);
// Using the parent hash function, generate key bytes to fill half a block
memcpy(Work, Key, KEY_BYTES);
memset(Work + KEY_BYTES, 0x5c, WORK_BYTES - KEY_BYTES); // Pad to fill a whole block
// Crunch one whole block
HashComputation(Work, 1, CachedFinalState);
return true;
}
void HMAC_MD5::RekeyFromMD5(HMAC_MD5 *parent)
{
memcpy(CachedInitialState, parent->CachedInitialState, sizeof(CachedInitialState));
memcpy(CachedFinalState, parent->CachedFinalState, sizeof(CachedFinalState));
}
bool HMAC_MD5::BeginMAC()
{
memcpy(State, CachedInitialState, DIGEST_BYTES);
byte_counter = WORK_BYTES;
used_bytes = 0;
return true;
}
void HMAC_MD5::Crunch(const void *_message, int bytes)
{
const u8 *buffer = (const u8*)_message;
byte_counter += bytes;
// If there are bytes left to hash from last time,
if (used_bytes)
{
// If we still cannot overflow the workspace,
if (used_bytes + bytes <= WORK_BYTES)
{
// Just append the new message bytes
memcpy(Work + used_bytes, buffer, bytes);
used_bytes += bytes;
return;
}
// Fill the rest of the workspace
u32 copied = WORK_BYTES - used_bytes;
memcpy(Work + used_bytes, buffer, copied);
HashComputation(Work, 1, State);
// Eat those bytes of the message
bytes -= copied;
buffer += copied;
}
// If the remaining bytes of the message overflows the workspace,
if (bytes > WORK_BYTES)
{
int eat_bytes = bytes - 1;
// Hash directly from the message
HashComputation(buffer, eat_bytes / WORK_BYTES, State);
// Eat those bytes of the message
eat_bytes &= ~(WORK_BYTES-1);
buffer += eat_bytes;
bytes -= eat_bytes;
}
// Copy what remains into the workspace
memcpy(Work, buffer, bytes);
used_bytes = bytes;
}
void HMAC_MD5::End()
{
// NOTE: We should always have at least one message hash to perform here
if (used_bytes >= WORK_BYTES)
{
HashComputation(Work, 1, State);
Work[0] = 0x80;
used_bytes = 1;
}
else if (used_bytes > (WORK_BYTES - 9))
{
Work[used_bytes++] = 0x80;
// Pad with zeros
CAT_CLR(Work + used_bytes, WORK_BYTES - used_bytes);
HashComputation(Work, 1, State);
used_bytes = 0;
}
// Pad out zeros
CAT_CLR(Work + used_bytes, (WORK_BYTES - 8) - used_bytes);
// Attach bit count to the end
u64 bit_counter = byte_counter << 3;
*(u32*)&Work[WORK_BYTES - 8] = getLE((u32)bit_counter);
*(u32*)&Work[WORK_BYTES - 4] = getLE((u32)(bit_counter >> 32));
u32 *Output = (u32 *)Work;
// Intermediate hash, output to start of workspace
HashComputation(Work, 1, Output);
memcpy(State, CachedFinalState, DIGEST_BYTES);
// Convert Intermediate State to an endian-neutral byte array
swapLE(Output[0]);
swapLE(Output[1]);
swapLE(Output[2]);
swapLE(Output[3]);
// Pad the hash-as-message as normal and crown it with a byte counter
byte_counter = 16;
Work[16] = 0x80;
CAT_CLR(Work + 17, (WORK_BYTES - 8) - 17);
*(u32*)&Work[WORK_BYTES - 8] = getLE32(16 << 3);
*(u32*)&Work[WORK_BYTES - 4] = 0;
// Final output hash
HashComputation(Work, 1, State);
// Convert Final State to an endian-neutral byte array
swapLE(State[0]);
swapLE(State[1]);
swapLE(State[2]);
swapLE(State[3]);
}
void HMAC_MD5::Generate(void *out, int bytes, int /*strengthening_rounds*/)
{
if (bytes > 16) bytes = 16;
memcpy(out, State, bytes);
}
#undef F
#undef G
#undef H
#undef I
#undef ROUND
#undef FF
#undef GG
#undef HH
#undef II

View File

@ -0,0 +1,295 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/crypt/hash/Skein.hpp>
#include <cat/port/EndianNeutral.hpp>
using namespace cat;
Skein::~Skein()
{
CAT_OBJCLR(State);
CAT_OBJCLR(Tweak);
CAT_OBJCLR(Work);
}
void Skein::GenerateInitialState(int bits)
{
u64 w[MAX_WORDS] = { getLE64(SCHEMA_VER), getLE64(static_cast<unsigned>(bits)), 0 };
CAT_OBJCLR(State);
// T1 = FIRST | FINAL | CFG
Tweak[0] = 0;
Tweak[1] = T1_MASK_FIRST | T1_MASK_FINAL | ((u64)BLK_TYPE_CFG << T1_POS_BLK_TYPE);
(this->*hash_func)(w, 1, 32, State);
}
// Cached copies of initial state for different bit lengths
static const u64 State0_160[4] = {
0xa38a0d80a3687723ULL, 0xb73cdb6a5963ffc9ULL, 0x9633e8ea07a1b447ULL, 0xca0ed09ec9529c22ULL
};
static const u64 State0_224[4] = {
0xb80929699ae0f431ULL, 0xd340dc14a06929dcULL, 0xae866594bde4dc5aULL, 0x339767c25a60ea1dULL
};
static const u64 State0_256[4] = {
0x388512680e660046ULL, 0x4b72d5dec5a8ff01ULL, 0x281a9298ca5eb3a5ULL, 0x54ca5249f46070c4ULL
};
static const u64 State0_384[8] = {
0xe5bf4d02ba62494cULL, 0x7aa1eabcc3e6fc68ULL, 0xbbe5fc26e1038c5aULL, 0x53c9903e8f88e9faULL,
0xf30d8dddfb940c83ULL, 0x500fda3c4865abecULL, 0x2226c67f745bc5e7ULL, 0x015da80077c639f7ULL
};
static const u64 State0_512[8] = {
0xa8d47980544a6e32ULL, 0x847511533e9b1a8aULL, 0x6faee870d8e81a00ULL, 0x58b0d9d6cb557f92ULL,
0x9bbc0051dac1d4e9ULL, 0xb744e2b1d189e7caULL, 0x979350fa709c5ef3ULL, 0x0350125a92067bcdULL
};
bool Skein::BeginKey(int bits)
{
if (bits <= 256) {
digest_bytes = 256 / 8;
digest_words = 256 / 64;
hash_func = &Skein::HashComputation256;
} else if (bits <= 512) {
digest_bytes = 512 / 8;
digest_words = 512 / 64;
hash_func = &Skein::HashComputation512;
} else return false;
// Try to use a cached copy of the initial state
switch (bits)
{
case 160: memcpy(State, State0_160, sizeof(State0_160)); break;
case 224: memcpy(State, State0_224, sizeof(State0_224)); break;
case 256: memcpy(State, State0_256, sizeof(State0_256)); break;
case 384: memcpy(State, State0_384, sizeof(State0_384)); break;
case 512: memcpy(State, State0_512, sizeof(State0_512)); break;
default: GenerateInitialState(bits);
}
// T1 = FIRST | KEY
Tweak[0] = 0;
Tweak[1] = T1_MASK_FIRST | ((u64)BLK_TYPE_KEY << T1_POS_BLK_TYPE);
used_bytes = 0;
output_prng_mode = false;
return true;
}
bool Skein::SetKey(ICryptHash *key_hash)
{
const Skein *parent = static_cast<const Skein *>(key_hash);
if (!parent) return false;
memcpy(State, parent->State, sizeof(State));
digest_bytes = parent->digest_bytes;
digest_words = parent->digest_words;
hash_func = parent->hash_func;
// The user will then call one of the Begin() functions below:
return true;
}
bool Skein::BeginMAC()
{
// T1 = FIRST | MSG
Tweak[0] = 0;
Tweak[1] = T1_MASK_FIRST | ((u64)BLK_TYPE_MSG << T1_POS_BLK_TYPE);
used_bytes = 0;
output_prng_mode = false;
return true;
}
bool Skein::BeginKDF()
{
// T1 = FIRST | KDF
Tweak[0] = 0;
Tweak[1] = T1_MASK_FIRST | ((u64)BLK_TYPE_KDF << T1_POS_BLK_TYPE);
used_bytes = 0;
output_prng_mode = false;
return true;
}
bool Skein::BeginPRNG()
{
// T1 = FIRST | NONCE
Tweak[0] = 0;
Tweak[1] = T1_MASK_FIRST | ((u64)BLK_TYPE_NONCE << T1_POS_BLK_TYPE);
used_bytes = 0;
output_prng_mode = true;
return true;
}
void Skein::Crunch(const void *_message, int bytes)
{
const u8 *buffer = (const u8*)_message;
// If there are bytes left to hash from last time,
if (used_bytes)
{
// If we still cannot overflow the workspace,
if (used_bytes + bytes <= digest_bytes)
{
// Just append the new message bytes
memcpy(Work + used_bytes, buffer, bytes);
used_bytes += bytes;
return;
}
// Fill the rest of the workspace
u32 copied = digest_bytes - used_bytes;
memcpy(Work + used_bytes, buffer, copied);
(this->*hash_func)(Work, 1, digest_bytes, State);
// Eat those bytes of the message
bytes -= copied;
buffer += copied;
}
// If the remaining bytes of the message overflows the workspace,
if (bytes > digest_bytes)
{
int eat_bytes = bytes - 1;
// Hash directly from the message
(this->*hash_func)(buffer, eat_bytes / digest_bytes, bytes, State);
// Eat those bytes of the message
eat_bytes &= ~(digest_bytes-1);
buffer += eat_bytes;
bytes -= eat_bytes;
}
// Copy what remains into the workspace
memcpy(Work, buffer, bytes);
used_bytes = bytes;
}
void Skein::End()
{
// NOTE: We should always have at least one message hash to perform here
// Pad with zeroes
CAT_CLR(Work + used_bytes, digest_bytes - used_bytes);
// Final message hash
Tweak[1] |= T1_MASK_FINAL;
(this->*hash_func)(Work, 1, used_bytes, State);
output_block_counter = 0;
}
void Skein::Generate(void *out, int bytes, int strengthening_rounds)
{
// Put the Skein generator in counter mode and generate WORDS at a time
u64 NextState[MAX_WORDS];
u64 FinalMessage[MAX_WORDS] = {output_block_counter, 0};
u64 *out64 = (u64 *)out;
// In strengthened mode, discard a number of rounds before producing real output
while (strengthening_rounds-- >= 1)
{
// T1 = FIRST | FINAL | OUT
Tweak[0] = 0;
Tweak[1] = T1_MASK_FIRST | T1_MASK_FINAL | ((u64)BLK_TYPE_OUT << T1_POS_BLK_TYPE);
// Produce next output
(this->*hash_func)(FinalMessage, 1, 8, NextState);
// Next counter
FinalMessage[0] = ++output_block_counter;
}
// In output mode, we hide the first block of each request
if (output_prng_mode)
{
// T1 = FIRST | FINAL | OUT
Tweak[0] = 0;
Tweak[1] = T1_MASK_FIRST | T1_MASK_FINAL | ((u64)BLK_TYPE_OUT << T1_POS_BLK_TYPE);
// Produce next output
(this->*hash_func)(FinalMessage, 1, 8, NextState);
// Next counter
FinalMessage[0] = ++output_block_counter;
}
while (bytes >= digest_bytes)
{
// T1 = FIRST | FINAL | OUT
Tweak[0] = 0;
Tweak[1] = T1_MASK_FIRST | T1_MASK_FINAL | ((u64)BLK_TYPE_OUT << T1_POS_BLK_TYPE);
// Produce next output
(this->*hash_func)(FinalMessage, 1, 8, out64);
for (int ii = 0; ii < digest_words; ++ii)
swapLE(out64[ii]);
// Next counter
out64 += digest_words;
bytes -= digest_bytes;
FinalMessage[0] = ++output_block_counter;
}
if (bytes > 0)
{
// T1 = FIRST | FINAL | OUT
Tweak[0] = 0;
Tweak[1] = T1_MASK_FIRST | T1_MASK_FINAL | ((u64)BLK_TYPE_OUT << T1_POS_BLK_TYPE);
// Produce final output
(this->*hash_func)(FinalMessage, 1, 8, FinalMessage);
for (int ii = CAT_CEIL_UNIT(bytes, sizeof(u64)); ii >= 0; --ii)
swapLE(FinalMessage[ii]);
// Copy however many bytes they wanted
memcpy(out64, FinalMessage, bytes);
++output_block_counter;
}
// In PRNG output mode, use the first hidden output block as the next state
if (output_prng_mode)
memcpy(State, NextState, digest_bytes);
}

View File

@ -0,0 +1,194 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/crypt/hash/Skein.hpp>
#include <cat/port/EndianNeutral.hpp>
using namespace cat;
#define THREEFISH(R0, R1, R2, R3) \
x0 += x1; x1 = CAT_ROL64(x1, R0); x1 ^= x0; \
x2 += x3; x3 = CAT_ROL64(x3, R1); x3 ^= x2; \
x0 += x3; x3 = CAT_ROL64(x3, R2); x3 ^= x0; \
x2 += x1; x1 = CAT_ROL64(x1, R3); x1 ^= x2;
#define INJECTKEY(K0, K1, K2, K3, T0, T1, R) \
x0 += (K0); \
x1 += (K1) + (T0); \
x2 += (K2) + (T1); \
x3 += (K3) + (R);
void Skein::HashComputation256(const void *_message, int blocks, u32 byte_count, u64 *NextState)
{
const int BITS = 256;
const int WORDS = BITS / 64;
const int BYTES = BITS / 8;
const u64 *message = (const u64 *)_message;
// Key schedule: Chaining
u64 k[5];
memcpy(k, State, BYTES);
// Key schedule: Tweak
u64 t0 = Tweak[0];
u64 t1 = Tweak[1];
do
{
t0 += byte_count;
// Parity extension
u64 t2 = t0 ^ t1;
k[4] = 0x1BD11BDAA9FC1A22LL ^ k[0] ^ k[1] ^ k[2] ^ k[3];
// First full key injection
register u64 x0 = k[0] + getLE(message[0]);
register u64 x1 = k[1] + getLE(message[1]) + t0;
register u64 x2 = k[2] + getLE(message[2]) + t1;
register u64 x3 = k[3] + getLE(message[3]);
// 72 rounds
// 10/26/09: Updated for SHA-3 competition Round 2
enum {
R_256_0_0=14, R_256_0_1=16,
R_256_1_0=52, R_256_1_1=57,
R_256_2_0=23, R_256_2_1=40,
R_256_3_0= 5, R_256_3_1=37,
R_256_4_0=25, R_256_4_1=33,
R_256_5_0=46, R_256_5_1=12,
R_256_6_0=58, R_256_6_1=22,
R_256_7_0=32, R_256_7_1=32
};
for (int round = 1; round <= 18; round += 6)
{
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
u64 k1 = k[(round)%5];
u64 k2 = k[(round+1)%5];
u64 k3 = k[(round+2)%5];
u64 k4 = k[(round+3)%5];
u64 k0 = k[(round+4)%5];
INJECTKEY(k1, k2, k3, k4, t1, t2, round);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k2, k3, k4, k0, t2, t0, round+1);
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k3, k4, k0, k1, t0, t1, round+2);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k4, k0, k1, k2, t1, t2, round+3);
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k0, k1, k2, k3, t2, t0, round+4);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k1, k2, k3, k4, t0, t1, round+5);
}
/*
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k1, k2, k3, k4, t1, t2, 1);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k2, k3, k4, k0, t2, t0, 2);
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k3, k4, k0, k1, t0, t1, 3);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k4, k0, k1, k2, t1, t2, 4);
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k0, k1, k2, k3, t2, t0, 5);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k1, k2, k3, k4, t0, t1, 6);
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k2, k3, k4, k0, t1, t2, 7);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k3, k4, k0, k1, t2, t0, 8);
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k4, k0, k1, k2, t0, t1, 9);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k0, k1, k2, k3, t1, t2, 10);
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k1, k2, k3, k4, t2, t0, 11);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k2, k3, k4, k0, t0, t1, 12);
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k3, k4, k0, k1, t1, t2, 13);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k4, k0, k1, k2, t2, t0, 14);
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k0, k1, k2, k3, t0, t1, 15);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k1, k2, k3, k4, t1, t2, 16);
THREEFISH(R_256_0_0, R_256_0_1, R_256_1_0, R_256_1_1);
THREEFISH(R_256_2_0, R_256_2_1, R_256_3_0, R_256_3_1);
INJECTKEY(k2, k3, k4, k0, t2, t0, 17);
THREEFISH(R_256_4_0, R_256_4_1, R_256_5_0, R_256_5_1);
THREEFISH(R_256_6_0, R_256_6_1, R_256_7_0, R_256_7_1);
INJECTKEY(k3, k4, k0, k1, t0, t1, 18);
*/
// Feedforward XOR
k[0] = x0 ^ getLE(message[0]);
k[1] = x1 ^ getLE(message[1]);
k[2] = x2 ^ getLE(message[2]);
k[3] = x3 ^ getLE(message[3]);
// Update tweak
t1 &= ~T1_MASK_FIRST;
// Eat data bytes
message += WORDS;
} while (--blocks > 0);
// Update tweak
Tweak[0] = t0;
Tweak[1] = t1;
// Update state
memcpy(NextState, k, BYTES);
}
#undef THREEFISH
#undef INJECTKEY

View File

@ -0,0 +1,246 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/crypt/hash/Skein.hpp>
#include <cat/port/EndianNeutral.hpp>
using namespace cat;
#define THREEFISH(R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, RA, RB, RC, RD, RE, RF) \
x[0] += x[1]; x[1] = CAT_ROL64(x[1], R0); x[1] ^= x[0]; \
x[2] += x[3]; x[3] = CAT_ROL64(x[3], R1); x[3] ^= x[2]; \
x[4] += x[5]; x[5] = CAT_ROL64(x[5], R2); x[5] ^= x[4]; \
x[6] += x[7]; x[7] = CAT_ROL64(x[7], R3); x[7] ^= x[6]; \
x[2] += x[1]; x[1] = CAT_ROL64(x[1], R4); x[1] ^= x[2]; \
x[4] += x[7]; x[7] = CAT_ROL64(x[7], R5); x[7] ^= x[4]; \
x[6] += x[5]; x[5] = CAT_ROL64(x[5], R6); x[5] ^= x[6]; \
x[0] += x[3]; x[3] = CAT_ROL64(x[3], R7); x[3] ^= x[0]; \
x[4] += x[1]; x[1] = CAT_ROL64(x[1], R8); x[1] ^= x[4]; \
x[6] += x[3]; x[3] = CAT_ROL64(x[3], R9); x[3] ^= x[6]; \
x[0] += x[5]; x[5] = CAT_ROL64(x[5], RA); x[5] ^= x[0]; \
x[2] += x[7]; x[7] = CAT_ROL64(x[7], RB); x[7] ^= x[2]; \
x[6] += x[1]; x[1] = CAT_ROL64(x[1], RC); x[1] ^= x[6]; \
x[0] += x[7]; x[7] = CAT_ROL64(x[7], RD); x[7] ^= x[0]; \
x[2] += x[5]; x[5] = CAT_ROL64(x[5], RE); x[5] ^= x[2]; \
x[4] += x[3]; x[3] = CAT_ROL64(x[3], RF); x[3] ^= x[4];
#define INJECTKEY(K0, K1, K2, K3, K4, K5, K6, K7, T0, T1, R) \
x[0] += (K0); \
x[1] += (K1); \
x[2] += (K2); \
x[3] += (K3); \
x[4] += (K4); \
x[5] += (K5) + (T0); \
x[6] += (K6) + (T1); \
x[7] += (K7) + (R);
void Skein::HashComputation512(const void *_message, int blocks, u32 byte_count, u64 *NextState)
{
const int BITS = 512;
const int WORDS = BITS / 64;
const int BYTES = BITS / 8;
const u64 *message = (const u64 *)_message;
// Key schedule: Chaining
u64 k[WORDS+1];
memcpy(k, State, BYTES);
// Key schedule: Tweak
u64 t[3];
memcpy(t, Tweak, sizeof(Tweak));
do
{
t[0] += byte_count;
// Parity extension
t[2] = t[0] ^ t[1];
k[WORDS] = 0x1BD11BDAA9FC1A22LL;
// First full key injection
u64 x[WORDS];
for (int ii = 0; ii < WORDS; ++ii)
{
x[ii] = k[ii] + getLE(message[ii]);
k[WORDS] ^= k[ii];
}
x[WORDS-3] += t[0];
x[WORDS-2] += t[1];
// 72 rounds
// 10/26/09: Updated for SHA-3 competition Round 2
enum {
R_512_0_0=46, R_512_0_1=36, R_512_0_2=19, R_512_0_3=37,
R_512_1_0=33, R_512_1_1=27, R_512_1_2=14, R_512_1_3=42,
R_512_2_0=17, R_512_2_1=49, R_512_2_2=36, R_512_2_3=39,
R_512_3_0=44, R_512_3_1= 9, R_512_3_2=54, R_512_3_3=56,
R_512_4_0=39, R_512_4_1=30, R_512_4_2=34, R_512_4_3=24,
R_512_5_0=13, R_512_5_1=50, R_512_5_2=10, R_512_5_3=17,
R_512_6_0=25, R_512_6_1=29, R_512_6_2=39, R_512_6_3=43,
R_512_7_0= 8, R_512_7_1=35, R_512_7_2=56, R_512_7_3=22
};
#if defined(CAT_WORD_64)
// Should unroll farther on 64-bit OS
for (int round = 1; round <= 18; round += 6)
{
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
u64 k0 = k[(round)%9];
u64 k1 = k[(round+1)%9];
u64 k2 = k[(round+2)%9];
u64 k3 = k[(round+3)%9];
u64 k4 = k[(round+4)%9];
u64 k5 = k[(round+5)%9];
u64 k6 = k[(round+6)%9];
u64 k7 = k[(round+7)%9];
u64 k8 = k[(round+8)%9];
INJECTKEY(k0, k1, k2, k3, k4, k5, k6, k7, t[1], t[2], round);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k1, k2, k3, k4, k5, k6, k7, k8, t[2], t[0], round+1);
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k2, k3, k4, k5, k6, k7, k8, k0, t[0], t[1], round+2);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k3, k4, k5, k6, k7, k8, k0, k1, t[1], t[2], round+3);
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k4, k5, k6, k7, k8, k0, k1, k2, t[2], t[0], round+4);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k5, k6, k7, k8, k0, k1, k2, k3, t[0], t[1], round+5);
}
#else
for (int round = 1; round <= 18; round += 2)
{
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
u64 k0 = k[(round)%9];
u64 k1 = k[(round+1)%9];
u64 k2 = k[(round+2)%9];
u64 k3 = k[(round+3)%9];
u64 k4 = k[(round+4)%9];
u64 k5 = k[(round+5)%9];
u64 k6 = k[(round+6)%9];
u64 k7 = k[(round+7)%9];
u64 k8 = k[(round+8)%9];
u64 t1 = t[(round+1)%3];
INJECTKEY(k0, k1, k2, k3, k4, k5, k6, k7, t[(round)%3], t1, round);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k1, k2, k3, k4, k5, k6, k7, k8, t1, t[(round+2)%3], round+1);
}
#endif
/*
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k[1], k[2], k[3], k[4], k[5], k[6], k[7], k[8], t1, t2, 1);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k[2], k[3], k[4], k[5], k[6], k[7], k[8], k[0], t2, t0, 2);
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k[3], k[4], k[5], k[6], k[7], k[8], k[0], k[1], t0, t1, 3);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k[4], k[5], k[6], k[7], k[8], k[0], k[1], k[2], t1, t2, 4);
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k[5], k[6], k[7], k[8], k[0], k[1], k[2], k[3], t2, t0, 5);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k[6], k[7], k[8], k[0], k[1], k[2], k[3], k[4], t0, t1, 6);
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k[7], k[8], k[0], k[1], k[2], k[3], k[4], k[5], t1, t2, 7);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k[8], k[0], k[1], k[2], k[3], k[4], k[5], k[6], t2, t0, 8);
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k[0], k[1], k[2], k[3], k[4], k[5], k[6], k[7], t0, t1, 9);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k[1], k[2], k[3], k[4], k[5], k[6], k[7], k[8], t1, t2, 10);
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k[2], k[3], k[4], k[5], k[6], k[7], k[8], k[0], t2, t0, 11);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k[3], k[4], k[5], k[6], k[7], k[8], k[0], k[1], t0, t1, 12);
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k[4], k[5], k[6], k[7], k[8], k[0], k[1], k[2], t1, t2, 13);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k[5], k[6], k[7], k[8], k[0], k[1], k[2], k[3], t2, t0, 14);
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k[6], k[7], k[8], k[0], k[1], k[2], k[3], k[4], t0, t1, 15);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k[7], k[8], k[0], k[1], k[2], k[3], k[4], k[5], t1, t2, 16);
THREEFISH(R_512_0_0, R_512_0_1, R_512_0_2, R_512_0_3, R_512_1_0, R_512_1_1, R_512_1_2, R_512_1_3,
R_512_2_0, R_512_2_1, R_512_2_2, R_512_2_3, R_512_3_0, R_512_3_1, R_512_3_2, R_512_3_3);
INJECTKEY(k[8], k[0], k[1], k[2], k[3], k[4], k[5], k[6], t2, t0, 17);
THREEFISH(R_512_4_0, R_512_4_1, R_512_4_2, R_512_4_3, R_512_5_0, R_512_5_1, R_512_5_2, R_512_5_3,
R_512_6_0, R_512_6_1, R_512_6_2, R_512_6_3, R_512_7_0, R_512_7_1, R_512_7_2, R_512_7_3);
INJECTKEY(k[0], k[1], k[2], k[3], k[4], k[5], k[6], k[7], t0, t1, 18);
*/
// Feedforward XOR
for (int ii = 0; ii < WORDS; ++ii)
k[ii] = x[ii] ^ getLE(message[ii]);
// Update tweak
t[1] &= ~T1_MASK_FIRST;
// Eat data bytes
message += WORDS;
} while (--blocks > 0);
// Update tweak
memcpy(Tweak, t, sizeof(Tweak));
// Update state
memcpy(NextState, k, BYTES);
}
#undef THREEFISH
#undef INJECTKEY

View File

@ -0,0 +1,117 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/crypt/pass/Passwords.hpp>
#include <cat/crypt/hash/Skein.hpp>
#include <cat/lang/Strings.hpp>
using namespace cat;
//// PasswordCreator
bool PasswordCreator::HashPassword(const void *in_name, int name_bytes,
const void *in_password, int password_bytes,
void *out_hash /* 32 bytes */)
{
#if defined(CAT_USER_ERROR_CHECKING)
if (!in_name || !in_password || !out_hash || name_bytes < 0 || password_bytes < 0) return false;
#endif
Skein hash;
if (!hash.BeginKey(HASH_BITS)) return false;
hash.Crunch(in_name, name_bytes);
hash.Crunch("\r:\n", 3);
hash.Crunch(in_password, password_bytes);
hash.End();
hash.Generate(out_hash, HASH_BYTES, STRENGTHENING_FACTOR);
return true;
}
bool PasswordCreator::HashPasswordString(const char *in_name,
const char *in_password,
void *out_hash /* 32 bytes */)
{
int name_bytes = (int)strlen(in_name);
int password_bytes = (int)strlen(in_password);
// Convert name to lower case and count characters
char *lcase_name = new char[name_bytes + 1];
CopyToLowercaseString(in_name, lcase_name);
bool success = HashPassword(lcase_name, name_bytes, in_password, password_bytes, out_hash);
delete []lcase_name;
return success;
}
//// PasswordVerifier
bool PasswordVerifier::SaltHash(IRandom *prng,
const void *in_hash /* 32 bytes */,
void *out_salted_hash /* 32 bytes */,
u32 *out_salt /* 4 bytes */)
{
#if defined(CAT_USER_ERROR_CHECKING)
if (!prng || !in_hash || !out_salted_hash || !out_salt) return false;
#endif
Skein hash;
*out_salt = prng->Generate();
if (!hash.BeginKey(HASH_BITS)) return false;
hash.Crunch(in_hash, HASH_BYTES);
hash.Crunch(out_salt, sizeof(*out_salt));
hash.End();
hash.Generate(out_salted_hash, HASH_BYTES);
return true;
}
bool PasswordVerifier::VerifyHash(const void *in_hash /* 32 bytes */,
const void *in_salted_hash /* 32 bytes */,
u32 in_salt /* 4 bytes */)
{
#if defined(CAT_USER_ERROR_CHECKING)
if (!in_hash || !in_salted_hash) return false;
#endif
Skein hash;
u8 Jp[HASH_BYTES];
if (!hash.BeginKey(HASH_BITS)) return false;
hash.Crunch(&in_salt, sizeof(in_salt));
hash.Crunch(in_hash, HASH_BYTES);
hash.End();
hash.Generate(Jp, HASH_BYTES);
return cat::SecureEqual(in_salted_hash, Jp, HASH_BYTES);
}

View File

@ -0,0 +1,183 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/crypt/symmetric/ChaCha.hpp>
#include <cat/port/EndianNeutral.hpp>
#include <string.h>
using namespace cat;
//// ChaChaKey
ChaChaKey::~ChaChaKey()
{
CAT_OBJCLR(state);
}
static u32 InitialState[12] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
// These are from BLAKE-32:
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
// Took the rest of these from the SHA-256 SBOX constants:
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13
};
// Key up to 384 bits
void ChaChaKey::Set(const void *key, int bytes)
{
// Precondition: Bytes must be a multiple of 4
if (bytes > 48) bytes = 48;
memcpy(state, InitialState, sizeof(InitialState));
const u32 *in32 = (const u32 *)key;
int words = bytes / 4;
for (int ii = 0; ii < words; ++ii)
{
state[ii] ^= getLE(in32[ii]);
}
}
//// ChaChaOutput
#define QUARTERROUND(a,b,c,d) \
x[a] += x[b]; x[d] = CAT_ROL32(x[d] ^ x[a], 16); \
x[c] += x[d]; x[b] = CAT_ROL32(x[b] ^ x[c], 12); \
x[a] += x[b]; x[d] = CAT_ROL32(x[d] ^ x[a], 8); \
x[c] += x[d]; x[b] = CAT_ROL32(x[b] ^ x[c], 7);
void ChaChaOutput::GenerateKeyStream(u32 *out_words)
{
// Update block counter
if (!++state[12]) state[13]++;
register u32 x[16];
// Copy state into work registers
for (int ii = 0; ii < 16; ++ii)
x[ii] = state[ii];
// Mix state for 12 rounds
for (int round = 12; round > 0; round -= 2)
{
QUARTERROUND(0, 4, 8, 12)
QUARTERROUND(1, 5, 9, 13)
QUARTERROUND(2, 6, 10, 14)
QUARTERROUND(3, 7, 11, 15)
QUARTERROUND(0, 5, 10, 15)
QUARTERROUND(1, 6, 11, 12)
QUARTERROUND(2, 7, 8, 13)
QUARTERROUND(3, 4, 9, 14)
}
// Add state to mixed state, little-endian
for (int jj = 0; jj < 16; ++jj)
out_words[jj] = getLE(x[jj] + state[jj]);
}
ChaChaOutput::ChaChaOutput(const ChaChaKey &key, u64 iv)
{
for (int ii = 0; ii < 12; ++ii)
state[ii] = key.state[ii];
// Initialize block counter to zero
state[12] = 0;
state[13] = 0;
// Initialize IV
state[14] = (u32)iv;
state[15] = (u32)(iv >> 32);
}
ChaChaOutput::~ChaChaOutput()
{
CAT_OBJCLR(state);
}
// Message with any number of bytes
void ChaChaOutput::Crypt(const void *in_bytes, void *out_bytes, int bytes)
{
const u32 *in32 = (const u32 *)in_bytes;
u32 *out32 = (u32 *)out_bytes;
#ifdef CAT_AUDIT
int initial_bytes = bytes;
printf("AUDIT: ChaCha input ");
for (int ii = 0; ii < bytes; ++ii)
{
printf("%02x", ((cat::u8*)in_bytes)[ii]);
}
printf("\n");
#endif
while (bytes >= 64)
{
u32 key32[16];
GenerateKeyStream(key32);
for (int ii = 0; ii < 16; ++ii)
out32[ii] = in32[ii] ^ key32[ii];
out32 += 16;
in32 += 16;
bytes -= 64;
}
if (bytes)
{
u32 key32[16];
GenerateKeyStream(key32);
int words = bytes / 4;
for (int ii = 0; ii < words; ++ii)
out32[ii] = in32[ii] ^ key32[ii];
const u8 *in8 = (const u8 *)(in32 + words);
u8 *out8 = (u8 *)(out32 + words);
const u8 *key8 = (const u8 *)(key32 + words);
switch (bytes % 4)
{
case 3: out8[2] = in8[2] ^ key8[2];
case 2: out8[1] = in8[1] ^ key8[1];
case 1: out8[0] = in8[0] ^ key8[0];
}
}
#ifdef CAT_AUDIT
printf("AUDIT: ChaCha output ");
for (int ii = 0; ii < initial_bytes; ++ii)
{
printf("%02x", ((cat::u8*)out_bytes)[ii]);
}
printf("\n");
#endif
}
#undef QUARTERROUND

View File

@ -0,0 +1,101 @@
/*
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of LibCat nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <cat/crypt/rand/Fortuna.hpp>
using namespace cat;
// Used for MacOSX, iPhone, PS3, XBox, and others (for now)
// I want to have more of these operating systems defined
#if !defined(CAT_OS_WINDOWS) && !defined(CAT_OS_LINUX)
#include <fcntl.h>
#include <unistd.h>
#if !defined(CAT_NO_ENTROPY_THREAD)
bool FortunaFactory::ThreadFunction(void *)
{
// Generic version does not spawn a thread
return true;
}
#endif // !defined(CAT_NO_ENTROPY_THREAD)
bool FortunaFactory::InitializeEntropySources()
{
// Fire poll for entropy all goes into pool 0
PollInvariantSources(0);
return true;
}
void FortunaFactory::ShutdownEntropySources()
{
}
void FortunaFactory::PollInvariantSources(int pool_index)
{
Skein &pool = Pool[pool_index];
struct {
u32 cycles_start;
u8 system_prng[32];
u32 cycles_end;
} Sources;
// Cycles at the start
Sources.cycles_start = Clock::cycles();
int random_fd = open("/dev/random", O_RDONLY);
// /dev/random large request
if (random_fd >= 0)
{
read(random_fd, Sources.system_prng, sizeof(Sources.system_prng));
close(random_fd);
}
// Cycles at the end
Sources.cycles_end = Clock::cycles();
pool.Crunch(&Sources, sizeof(Sources));
}
void FortunaFactory::PollSlowEntropySources(int pool_index)
{
}
void FortunaFactory::PollFastEntropySources(int pool_index)
{
}
#endif

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