update libks
This commit is contained in:
parent
238e228942
commit
9fd0b6bd2f
|
@ -0,0 +1,10 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
build/compile
|
||||
build/libtool.m4
|
||||
build/ltoptions.m4
|
||||
build/ltsugar.m4
|
||||
build/ltversion.m4
|
||||
build/lt~obsolete.m4
|
||||
dht-example.id
|
||||
configure
|
|
@ -0,0 +1,370 @@
|
|||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell command `./configure && make && make install'
|
||||
should configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package. Some packages provide this
|
||||
`INSTALL' file but do not implement all of the features documented
|
||||
below. The lack of an optional feature in a given package is not
|
||||
necessarily a bug. More recommendations for GNU packages can be found
|
||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
||||
you want to change it or regenerate `configure' using a newer version
|
||||
of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system.
|
||||
|
||||
Running `configure' might take a while. While running, it prints
|
||||
some messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package, generally using the just-built uninstalled binaries.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation. When installing into a prefix owned by root, it is
|
||||
recommended that the package be configured and built as a regular
|
||||
user, and only the `make install' phase executed with root
|
||||
privileges.
|
||||
|
||||
5. Optionally, type `make installcheck' to repeat any self-tests, but
|
||||
this time using the binaries in their final installed location.
|
||||
This target does not install anything. Running this target as a
|
||||
regular user, particularly if the prior `make install' required
|
||||
root privileges, verifies that the installation completed
|
||||
correctly.
|
||||
|
||||
6. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
7. Often, you can also type `make uninstall' to remove the installed
|
||||
files again. In practice, not all packages have tested that
|
||||
uninstallation works correctly, even though it is required by the
|
||||
GNU Coding Standards.
|
||||
|
||||
8. Some packages, particularly those that use Automake, provide `make
|
||||
distcheck', which can by used by developers to test that all other
|
||||
targets like `make install' and `make uninstall' work correctly.
|
||||
This target is generally not run by end users.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. Run `./configure --help'
|
||||
for details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'. This
|
||||
is known as a "VPATH" build.
|
||||
|
||||
With a non-GNU `make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use `make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
On MacOS X 10.5 and later systems, you can create libraries and
|
||||
executables that work on multiple system types--known as "fat" or
|
||||
"universal" binaries--by specifying multiple `-arch' options to the
|
||||
compiler but only a single `-arch' option to the preprocessor. Like
|
||||
this:
|
||||
|
||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CPP="gcc -E" CXXCPP="g++ -E"
|
||||
|
||||
This is not guaranteed to produce working output in all cases, you
|
||||
may have to build one architecture at a time and combine the results
|
||||
using the `lipo' tool if you have problems.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an
|
||||
absolute file name.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them. In general, the
|
||||
default for these options is expressed in terms of `${prefix}', so that
|
||||
specifying just `--prefix' will affect all of the other directory
|
||||
specifications that were not explicitly provided.
|
||||
|
||||
The most portable way to affect installation locations is to pass the
|
||||
correct locations to `configure'; however, many packages provide one or
|
||||
both of the following shortcuts of passing variable assignments to the
|
||||
`make install' command line to change installation locations without
|
||||
having to reconfigure or recompile.
|
||||
|
||||
The first method involves providing an override variable for each
|
||||
affected directory. For example, `make install
|
||||
prefix=/alternate/directory' will choose an alternate location for all
|
||||
directory configuration variables that were expressed in terms of
|
||||
`${prefix}'. Any directories that were specified during `configure',
|
||||
but not in terms of `${prefix}', must each be overridden at install
|
||||
time for the entire installation to be relocated. The approach of
|
||||
makefile variable overrides for each directory variable is required by
|
||||
the GNU Coding Standards, and ideally causes no recompilation.
|
||||
However, some platforms have known limitations with the semantics of
|
||||
shared libraries that end up requiring recompilation when using this
|
||||
method, particularly noticeable in packages that use GNU Libtool.
|
||||
|
||||
The second method involves providing the `DESTDIR' variable. For
|
||||
example, `make install DESTDIR=/alternate/directory' will prepend
|
||||
`/alternate/directory' before all installation names. The approach of
|
||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and
|
||||
does not work on platforms that have drive letters. On the other hand,
|
||||
it does better at avoiding recompilation issues, and works well even
|
||||
when some directory options were not specified in terms of `${prefix}'
|
||||
at `configure' time.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Some packages offer the ability to configure how verbose the
|
||||
execution of `make' will be. For these packages, running `./configure
|
||||
--enable-silent-rules' sets the default to minimal output, which can be
|
||||
overridden with `make V=1'; while running `./configure
|
||||
--disable-silent-rules' sets the default to verbose, which can be
|
||||
overridden with `make V=0'.
|
||||
|
||||
Particular systems
|
||||
==================
|
||||
|
||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
|
||||
CC is not installed, it is recommended to use the following options in
|
||||
order to use an ANSI C compiler:
|
||||
|
||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
||||
|
||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||
|
||||
HP-UX `make' updates targets which have the same time stamps as
|
||||
their prerequisites, which makes it generally unusable when shipped
|
||||
generated files such as `configure' are involved. Use GNU `make'
|
||||
instead.
|
||||
|
||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
|
||||
a workaround. If GNU CC is not installed, it is therefore recommended
|
||||
to try
|
||||
|
||||
./configure CC="cc"
|
||||
|
||||
and if that doesn't work, try
|
||||
|
||||
./configure CC="cc -nodtk"
|
||||
|
||||
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
|
||||
directory contains several dysfunctional programs; working variants of
|
||||
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
|
||||
in your `PATH', put it _after_ `/usr/bin'.
|
||||
|
||||
On Haiku, software installed for all users goes in `/boot/common',
|
||||
not `/usr/local'. It is recommended to use the following options:
|
||||
|
||||
./configure --prefix=/boot/common
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out
|
||||
automatically, but needs to determine by the type of machine the package
|
||||
will run on. Usually, assuming the package is built to be run on the
|
||||
_same_ architectures, `configure' can figure that out, but if it prints
|
||||
a message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS
|
||||
KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the option `--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
||||
an Autoconf limitation. Until the limitation is lifted, you can use
|
||||
this workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of all of the options to `configure', and exit.
|
||||
|
||||
`--help=short'
|
||||
`--help=recursive'
|
||||
Print a summary of the options unique to this package's
|
||||
`configure', and exit. The `short' variant lists options used
|
||||
only in the top level, while the `recursive' variant lists options
|
||||
also present in any nested packages.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--prefix=DIR'
|
||||
Use DIR as the installation prefix. *note Installation Names::
|
||||
for more details, including other options available for fine-tuning
|
||||
the installation locations.
|
||||
|
||||
`--no-create'
|
||||
`-n'
|
||||
Run the configure checks, but stop before creating any output
|
||||
files.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
|
@ -0,0 +1,36 @@
|
|||
ACLOCAL_AMFLAGS=-I build
|
||||
EXTRA_DIST =
|
||||
SUBDIRS = . test
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
|
||||
AM_CFLAGS += -I$(top_srcdir)/src -I$(top_srcdir)/src/include -I$(top_srcdir)/crypt
|
||||
AM_CPPFLAGS = $(AM_CFLAGS)
|
||||
|
||||
lib_LTLIBRARIES = libks.la
|
||||
libks_la_SOURCES = src/ks.c src/ks_string.c src/ks_json.c src/ks_thread.c src/ks_mutex.c src/ks_config.c
|
||||
libks_la_SOURCES += src/ks_log.c src/ks_socket.c src/ks_buffer.c src/ks_pool.c src/simclist.c
|
||||
libks_la_SOURCES += src/ks_time.c src/ks_printf.c src/ks_hash.c src/ks_q.c src/ks_dso.c src/ks_dht.c
|
||||
libks_la_SOURCES += src/ks_ssl.c src/kws.c src/ks_rng.c
|
||||
libks_la_SOURCES += src/utp/utp_api.cpp src/utp/utp_callbacks.cpp src/utp/utp_hash.cpp src/utp/utp_internal.cpp
|
||||
libks_la_SOURCES += src/utp/utp_packedsockaddr.cpp src/utp/utp_utils.cpp src/ks_bencode.c
|
||||
libks_la_SOURCES += crypt/aeskey.c crypt/aestab.c crypt/sha2.c crypt/twofish.c crypt/aes_modes.c crypt/aescrypt.c crypt/twofish_cfb.c
|
||||
#aes.h aescpp.h brg_endian.h aesopt.h aestab.h brg_types.h sha2.h twofish.h
|
||||
|
||||
libks_la_CFLAGS = $(AM_CFLAGS)
|
||||
libks_la_CPPFLAGS = -DPOSIX
|
||||
libks_la_LDFLAGS = $(AM_LDFLAGS) -version-info 0:1:0 -lncurses -lpthread -lm
|
||||
|
||||
library_includedir = $(prefix)/include
|
||||
library_include_HEADERS = src/include/ks_config.h src/include/ks.h src/include/ks_threadmutex.h src/include/ks_json.h src/include/ks_buffer.h
|
||||
library_include_HEADERS += src/include/ks_pool.h src/include/simclist.h src/include/ks_time.h src/include/ks_q.h src/include/ks_socket.h
|
||||
library_include_HEADERS += src/include/ks_dso.h src/include/ks_dht.h src/include/ks_platform.h src/include/ks_types.h # src/include/ks_rng.h
|
||||
library_include_HEADERS += src/include/ks_printf.h src/include/ks_hash.h src/include/ks_ssl.h src/include/kws.h
|
||||
library_include_HEADERS += src/utp/utp_internal.h src/utp/utp.h src/utp/utp_types.h src/utp/utp_callbacks.h src/utp/utp_templates.h
|
||||
library_include_HEADERS += src/utp/utp_hash.h src/utp/utp_packedsockaddr.h src/utp/utp_utils.h src/include/ks_utp.h
|
||||
|
||||
tests: libks.la
|
||||
$(MAKE) -C test tests
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
m4_include([build/config/ax_compiler_vendor.m4])
|
||||
m4_include([build/config/ax_cflags_warn_all_ansi.m4])
|
||||
m4_include([build/config/ax_cc_maxopt.m4])
|
||||
m4_include([build/config/ax_check_compiler_flags.m4])
|
||||
m4_include([build/config/ac_gcc_archflag.m4])
|
||||
m4_include([build/config/ac_gcc_x86_cpuid.m4])
|
||||
m4_include([build/config/sac-openssl.m4])
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -x
|
||||
${AUTORECONF:-autoreconf} -fi
|
|
@ -0,0 +1,142 @@
|
|||
AC_DEFUN([AX_CFLAGS_GCC_OPTION_OLD], [dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_gcc_option_$2])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for gcc m4_ifval($2,$2,-option)],
|
||||
VAR,[VAR="no, unknown"
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
for ac_arg dnl
|
||||
in "-pedantic % m4_ifval($2,$2,-option)" dnl GCC
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_TRY_COMPILE([],[return 0;],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_ifvaln($4,$4) ;;
|
||||
*) m4_ifvaln($3,$3,[
|
||||
if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
|
||||
then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
|
||||
else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
|
||||
m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
|
||||
fi ]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])
|
||||
|
||||
|
||||
dnl the only difference - the LANG selection... and the default FLAGS
|
||||
|
||||
AC_DEFUN([AX_CXXFLAGS_GCC_OPTION_OLD], [dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_gcc_option_$2])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for gcc m4_ifval($2,$2,-option)],
|
||||
VAR,[VAR="no, unknown"
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CXX
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
for ac_arg dnl
|
||||
in "-pedantic % m4_ifval($2,$2,-option)" dnl GCC
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_TRY_COMPILE([],[return 0;],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_ifvaln($4,$4) ;;
|
||||
*) m4_ifvaln($3,$3,[
|
||||
if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
|
||||
then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
|
||||
else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
|
||||
m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
|
||||
fi ]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])
|
||||
|
||||
dnl -------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([AX_CFLAGS_GCC_OPTION_NEW], [dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_gcc_option_$1])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for gcc m4_ifval($1,$1,-option)],
|
||||
VAR,[VAR="no, unknown"
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
for ac_arg dnl
|
||||
in "-pedantic % m4_ifval($1,$1,-option)" dnl GCC
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_TRY_COMPILE([],[return 0;],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_ifvaln($4,$4) ;;
|
||||
*) m4_ifvaln($3,$3,[
|
||||
if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
|
||||
then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR])
|
||||
else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"])
|
||||
m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"
|
||||
fi ]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])
|
||||
|
||||
|
||||
dnl the only difference - the LANG selection... and the default FLAGS
|
||||
|
||||
AC_DEFUN([AX_CXXFLAGS_GCC_OPTION_NEW], [dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_gcc_option_$1])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for gcc m4_ifval($1,$1,-option)],
|
||||
VAR,[VAR="no, unknown"
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CXX
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
for ac_arg dnl
|
||||
in "-pedantic % m4_ifval($1,$1,-option)" dnl GCC
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_TRY_COMPILE([],[return 0;],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_ifvaln($4,$4) ;;
|
||||
*) m4_ifvaln($3,$3,[
|
||||
if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
|
||||
then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR])
|
||||
else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"])
|
||||
m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"
|
||||
fi ]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])
|
||||
|
||||
AC_DEFUN([AX_CFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1,
|
||||
[AX_CFLAGS_GCC_OPTION_NEW($@)],[AX_CFLAGS_GCC_OPTION_OLD($@)])])
|
||||
|
||||
AC_DEFUN([AX_CXXFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1,
|
||||
[AX_CXXFLAGS_GCC_OPTION_NEW($@)],[AX_CXXFLAGS_GCC_OPTION_OLD($@)])])
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
AC_DEFUN([AX_CFLAGS_SUN_OPTION_OLD], [dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_sun_option_$2])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for sun/cc m4_ifval($2,$2,-option)],
|
||||
VAR,[VAR="no, unknown"
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
for ac_arg dnl
|
||||
in "+xstrconst % -xc99=all m4_ifval($2,$2,-option)" dnl Solaris C
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_TRY_COMPILE([],[return 0;],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_ifvaln($4,$4) ;;
|
||||
*) m4_ifvaln($3,$3,[
|
||||
if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
|
||||
then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
|
||||
else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
|
||||
m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
|
||||
fi ]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])
|
||||
|
||||
dnl the only difference - the LANG selection... and the default FLAGS
|
||||
|
||||
AC_DEFUN([AX_CXXFLAGS_SUN_OPTION_OLD], [dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_sun_option_$2])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for sun/cc m4_ifval($2,$2,-option)],
|
||||
VAR,[VAR="no, unknown"
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CXX
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
for ac_arg dnl
|
||||
in "+xstrconst % -xc99=all m4_ifval($2,$2,-option)" dnl Solaris C
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_TRY_COMPILE([],[return 0;],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_ifvaln($4,$4) ;;
|
||||
*) m4_ifvaln($3,$3,[
|
||||
if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
|
||||
then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
|
||||
else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
|
||||
m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
|
||||
fi ]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])
|
||||
|
||||
dnl -----------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([AX_CFLAGS_SUN_OPTION_NEW], [dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_sun_option_$1])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for sun/cc m4_ifval($1,$1,-option)],
|
||||
VAR,[VAR="no, unknown"
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
for ac_arg dnl
|
||||
in "+xstrconst % -xc99=all m4_ifval($1,$1,-option)" dnl Solaris C
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_TRY_COMPILE([],[return 0;],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_ifvaln($4,$4) ;;
|
||||
*) m4_ifvaln($3,$3,[
|
||||
if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
|
||||
then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR])
|
||||
else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"])
|
||||
m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"
|
||||
fi ]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])
|
||||
|
||||
dnl the only difference - the LANG selection... and the default FLAGS
|
||||
|
||||
AC_DEFUN([AX_CXXFLAGS_SUN_OPTION_NEW], [dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_sun_option_$1])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for sun/cc m4_ifval($1,$1,-option)],
|
||||
VAR,[VAR="no, unknown"
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CXX
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
for ac_arg dnl
|
||||
in "+xstrconst % -xc99=all m4_ifval($1,$1,-option)" dnl Solaris C
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_TRY_COMPILE([],[return 0;],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_ifvaln($4,$4) ;;
|
||||
*) m4_ifvaln($3,$3,[
|
||||
if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
|
||||
then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR])
|
||||
else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"])
|
||||
m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"
|
||||
fi ]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])
|
||||
|
||||
AC_DEFUN([AX_CFLAGS_SUN_OPTION],[ifelse(m4_regexp([$2],[-]),-1,
|
||||
[AX_CFLAGS_SUN_OPTION_NEW($@)],[AX_CFLAGS_SUN_OPTION_OLD($@)])])
|
||||
|
||||
AC_DEFUN([AX_CXXFLAGS_SUN_OPTION],[ifelse(m4_regexp([$2],[-]),-1,
|
||||
[AX_CXXFLAGS_SUN_OPTION_NEW($@)],[AX_CXXFLAGS_SUN_OPTION_OLD($@)])])
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
AC_DEFUN([AX_GCC_ARCHFLAG],
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
|
||||
AC_ARG_WITH(gcc-arch, [AC_HELP_STRING([--with-gcc-arch=<arch>], [use architecture <arch> for gcc -march/-mtune, instead of guessing])],
|
||||
ax_gcc_arch=$withval, ax_gcc_arch=yes)
|
||||
|
||||
AC_MSG_CHECKING([for gcc architecture flag])
|
||||
AC_MSG_RESULT([])
|
||||
AC_CACHE_VAL(ax_cv_gcc_archflag,
|
||||
[
|
||||
ax_cv_gcc_archflag="unknown"
|
||||
|
||||
if test "$GCC" = yes; then
|
||||
|
||||
if test "x$ax_gcc_arch" = xyes; then
|
||||
ax_gcc_arch=""
|
||||
if test "$cross_compiling" = no; then
|
||||
case $host_cpu in
|
||||
i[[3456]]86*|x86_64*) # use cpuid codes, in part from x86info-1.7 by D. Jones
|
||||
AX_GCC_X86_CPUID(0)
|
||||
AX_GCC_X86_CPUID(1)
|
||||
case $ax_cv_gcc_x86_cpuid_0 in
|
||||
*:756e6547:*:*) # Intel
|
||||
case $ax_cv_gcc_x86_cpuid_1 in
|
||||
*5[[48]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;;
|
||||
*5??:*:*:*) ax_gcc_arch=pentium ;;
|
||||
*6[[3456]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;;
|
||||
*6a?:*[[01]]:*:*) ax_gcc_arch="pentium2 pentiumpro" ;;
|
||||
*6a?:*[[234]]:*:*) ax_gcc_arch="pentium3 pentiumpro" ;;
|
||||
*6[[9d]]?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;;
|
||||
*6[[78b]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;;
|
||||
*6??:*:*:*) ax_gcc_arch=pentiumpro ;;
|
||||
*f3[[347]]:*:*:*|*f4[1347]:*:*:*)
|
||||
case $host_cpu in
|
||||
x86_64*) ax_gcc_arch="nocona pentium4 pentiumpro" ;;
|
||||
*) ax_gcc_arch="prescott pentium4 pentiumpro" ;;
|
||||
esac ;;
|
||||
*f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro";;
|
||||
esac ;;
|
||||
*:68747541:*:*) # AMD
|
||||
case $ax_cv_gcc_x86_cpuid_1 in
|
||||
*5[[67]]?:*:*:*) ax_gcc_arch=k6 ;;
|
||||
*5[[8d]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;;
|
||||
*5[[9]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;;
|
||||
*60?:*:*:*) ax_gcc_arch=k7 ;;
|
||||
*6[[12]]?:*:*:*) ax_gcc_arch="athlon k7" ;;
|
||||
*6[[34]]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;;
|
||||
*67?:*:*:*) ax_gcc_arch="athlon-4 athlon k7" ;;
|
||||
*6[[68a]]?:*:*:*)
|
||||
AX_GCC_X86_CPUID(0x80000006) # L2 cache size
|
||||
case $ax_cv_gcc_x86_cpuid_0x80000006 in
|
||||
*:*:*[[1-9a-f]]??????:*) # (L2 = ecx >> 16) >= 256
|
||||
ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;;
|
||||
*) ax_gcc_arch="athlon-4 athlon k7" ;;
|
||||
esac ;;
|
||||
*f[[4cef8b]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;;
|
||||
*f5?:*:*:*) ax_gcc_arch="opteron k8" ;;
|
||||
*f7?:*:*:*) ax_gcc_arch="athlon-fx opteron k8" ;;
|
||||
*f??:*:*:*) ax_gcc_arch="k8" ;;
|
||||
esac ;;
|
||||
*:746e6543:*:*) # IDT
|
||||
case $ax_cv_gcc_x86_cpuid_1 in
|
||||
*54?:*:*:*) ax_gcc_arch=winchip-c6 ;;
|
||||
*58?:*:*:*) ax_gcc_arch=winchip2 ;;
|
||||
*6[[78]]?:*:*:*) ax_gcc_arch=c3 ;;
|
||||
*69?:*:*:*) ax_gcc_arch="c3-2 c3" ;;
|
||||
esac ;;
|
||||
esac
|
||||
if test x"$ax_gcc_arch" = x; then # fallback
|
||||
case $host_cpu in
|
||||
i586*) ax_gcc_arch=pentium ;;
|
||||
i686*) ax_gcc_arch=pentiumpro ;;
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
|
||||
sparc*)
|
||||
AC_PATH_PROG([PRTDIAG], [prtdiag], [prtdiag], [$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/])
|
||||
cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null`
|
||||
cputype=`echo "$cputype" | tr -d ' -' |tr $as_cr_LETTERS $as_cr_letters`
|
||||
case $cputype in
|
||||
*ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;;
|
||||
*ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;;
|
||||
*ultrasparc*) ax_gcc_arch="ultrasparc v9" ;;
|
||||
*supersparc*|*tms390z5[[05]]*) ax_gcc_arch="supersparc v8" ;;
|
||||
*hypersparc*|*rt62[[056]]*) ax_gcc_arch="hypersparc v8" ;;
|
||||
*cypress*) ax_gcc_arch=cypress ;;
|
||||
esac ;;
|
||||
|
||||
alphaev5) ax_gcc_arch=ev5 ;;
|
||||
alphaev56) ax_gcc_arch=ev56 ;;
|
||||
alphapca56) ax_gcc_arch="pca56 ev56" ;;
|
||||
alphapca57) ax_gcc_arch="pca57 pca56 ev56" ;;
|
||||
alphaev6) ax_gcc_arch=ev6 ;;
|
||||
alphaev67) ax_gcc_arch=ev67 ;;
|
||||
alphaev68) ax_gcc_arch="ev68 ev67" ;;
|
||||
alphaev69) ax_gcc_arch="ev69 ev68 ev67" ;;
|
||||
alphaev7) ax_gcc_arch="ev7 ev69 ev68 ev67" ;;
|
||||
alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;;
|
||||
|
||||
powerpc*)
|
||||
cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | sed 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null`
|
||||
cputype=`echo $cputype | sed -e 's/ppc//g;s/ *//g'`
|
||||
case $cputype in
|
||||
*750*) ax_gcc_arch="750 G3" ;;
|
||||
*740[[0-9]]*) ax_gcc_arch="$cputype 7400 G4" ;;
|
||||
*74[[4-5]][[0-9]]*) ax_gcc_arch="$cputype 7450 G4" ;;
|
||||
*74[[0-9]][[0-9]]*) ax_gcc_arch="$cputype G4" ;;
|
||||
*970*) ax_gcc_arch="970 G5 power4";;
|
||||
*POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";;
|
||||
*POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";;
|
||||
603ev|8240) ax_gcc_arch="$cputype 603e 603";;
|
||||
*) ax_gcc_arch=$cputype ;;
|
||||
esac
|
||||
ax_gcc_arch="$ax_gcc_arch powerpc"
|
||||
;;
|
||||
esac
|
||||
fi # not cross-compiling
|
||||
fi # guess arch
|
||||
|
||||
if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then
|
||||
for arch in $ax_gcc_arch; do
|
||||
if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code
|
||||
flags="-mtune=$arch"
|
||||
# -mcpu=$arch and m$arch generate nonportable code on every arch except
|
||||
# x86. And some other arches (e.g. Alpha) don't accept -mtune. Grrr.
|
||||
case $host_cpu in i*86|x86_64*) flags="$flags -mcpu=$arch -m$arch";; esac
|
||||
else
|
||||
flags="-march=$arch -mcpu=$arch -m$arch"
|
||||
fi
|
||||
for flag in $flags; do
|
||||
AX_CHECK_COMPILER_FLAGS($flag, [ax_cv_gcc_archflag=$flag; break])
|
||||
done
|
||||
test "x$ax_cv_gcc_archflag" = xunknown || break
|
||||
done
|
||||
fi
|
||||
|
||||
fi # $GCC=yes
|
||||
])
|
||||
AC_MSG_CHECKING([for gcc architecture flag])
|
||||
AC_MSG_RESULT($ax_cv_gcc_archflag)
|
||||
if test "x$ax_cv_gcc_archflag" = xunknown; then
|
||||
m4_default([$3],:)
|
||||
else
|
||||
m4_default([$2], [CFLAGS="$CFLAGS $ax_cv_gcc_archflag"])
|
||||
fi
|
||||
])
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
AC_DEFUN([AX_GCC_X86_CPUID],
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_LANG_PUSH([C])
|
||||
AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1,
|
||||
[AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <stdio.h>], [
|
||||
int op = $1, eax, ebx, ecx, edx;
|
||||
FILE *f;
|
||||
__asm__("cpuid"
|
||||
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
|
||||
: "a" (op));
|
||||
f = fopen("conftest_cpuid", "w"); if (!f) return 1;
|
||||
fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
|
||||
fclose(f);
|
||||
return 0;
|
||||
])],
|
||||
[ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid],
|
||||
[ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid],
|
||||
[ax_cv_gcc_x86_cpuid_$1=unknown])])
|
||||
AC_LANG_POP([C])
|
||||
])
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
AC_DEFUN([AC_PROG_GZIP],[
|
||||
AC_CHECK_PROGS(gzip,[gzip],no)
|
||||
export gzip;
|
||||
if test $gzip = "no" ;
|
||||
then
|
||||
AC_MSG_ERROR([Unable to find the gzip application]);
|
||||
fi
|
||||
AC_SUBST(gzip)
|
||||
])
|
|
@ -0,0 +1,9 @@
|
|||
AC_DEFUN([AC_PROG_WGET],[
|
||||
AC_CHECK_PROGS(wget,[wget],no)
|
||||
export wget;
|
||||
if test $wget = "no" ;
|
||||
then
|
||||
AC_MSG_ERROR([Unable to find the wget application]);
|
||||
fi
|
||||
AC_SUBST(wget)
|
||||
])
|
|
@ -0,0 +1,120 @@
|
|||
AC_DEFUN([AX_CC_MAXOPT],
|
||||
[
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AX_COMPILER_VENDOR])
|
||||
|
||||
AC_ARG_ENABLE(portable-binary, [AC_HELP_STRING([--enable-portable-binary], [disable compiler optimizations that would produce unportable binaries])],
|
||||
acx_maxopt_portable=$withval, acx_maxopt_portable=no)
|
||||
|
||||
# Try to determine "good" native compiler flags if none specified via CFLAGS
|
||||
if test "$ac_test_CFLAGS" != "set"; then
|
||||
CFLAGS=""
|
||||
case $ax_cv_c_compiler_vendor in
|
||||
dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host"
|
||||
if test "x$acx_maxopt_portable" = xno; then
|
||||
CFLAGS="$CFLAGS -arch host"
|
||||
fi;;
|
||||
|
||||
sun) CFLAGS="-native -fast -xO5 -dalign -xc99=all"
|
||||
if test "x$acx_maxopt_portable" = xyes; then
|
||||
CFLAGS="$CFLAGS -xarch=generic"
|
||||
fi;;
|
||||
|
||||
hp) CFLAGS="+Oall +Optrs_ansi +DSnative"
|
||||
if test "x$acx_maxopt_portable" = xyes; then
|
||||
CFLAGS="$CFLAGS +DAportable"
|
||||
fi;;
|
||||
|
||||
ibm) if test "x$acx_maxopt_portable" = xno; then
|
||||
xlc_opt="-qarch=auto -qtune=auto"
|
||||
else
|
||||
xlc_opt="-qtune=auto"
|
||||
fi
|
||||
AX_CHECK_COMPILER_FLAGS($xlc_opt,
|
||||
CFLAGS="-O3 -qansialias -w $xlc_opt",
|
||||
[CFLAGS="-O3 -qansialias -w"
|
||||
echo "******************************************************"
|
||||
echo "* You seem to have the IBM C compiler. It is *"
|
||||
echo "* recommended for best performance that you use: *"
|
||||
echo "* *"
|
||||
echo "* CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *"
|
||||
echo "* ^^^ ^^^ *"
|
||||
echo "* where xxx is pwr2, pwr3, 604, or whatever kind of *"
|
||||
echo "* CPU you have. (Set the CFLAGS environment var. *"
|
||||
echo "* and re-run configure.) For more info, man cc. *"
|
||||
echo "******************************************************"])
|
||||
;;
|
||||
|
||||
intel) CFLAGS="-O3 -ansi_alias"
|
||||
if test "x$acx_maxopt_portable" = xno; then
|
||||
icc_archflag=unknown
|
||||
icc_flags=""
|
||||
case $host_cpu in
|
||||
i686*|x86_64*)
|
||||
# icc accepts gcc assembly syntax, so these should work:
|
||||
AX_GCC_X86_CPUID(0)
|
||||
AX_GCC_X86_CPUID(1)
|
||||
case $ax_cv_gcc_x86_cpuid_0 in # see AX_GCC_ARCHFLAG
|
||||
*:756e6547:*:*) # Intel
|
||||
case $ax_cv_gcc_x86_cpuid_1 in
|
||||
*6a?:*[[234]]:*:*|*6[[789b]]?:*:*:*) icc_flags="-xK";;
|
||||
*f3[[347]]:*:*:*|*f4[1347]:*:*:*) icc_flags="-xP -xN -xW -xK";;
|
||||
*f??:*:*:*) icc_flags="-xN -xW -xK";;
|
||||
esac ;;
|
||||
esac ;;
|
||||
esac
|
||||
if test "x$icc_flags" != x; then
|
||||
for flag in $icc_flags; do
|
||||
AX_CHECK_COMPILER_FLAGS($flag, [icc_archflag=$flag; break])
|
||||
done
|
||||
fi
|
||||
AC_MSG_CHECKING([for icc architecture flag])
|
||||
AC_MSG_RESULT($icc_archflag)
|
||||
if test "x$icc_archflag" != xunknown; then
|
||||
CFLAGS="$CFLAGS $icc_archflag"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
gnu)
|
||||
# default optimization flags for gcc on all systems
|
||||
CFLAGS="-O3 -fomit-frame-pointer"
|
||||
|
||||
# -malign-double for x86 systems
|
||||
AX_CHECK_COMPILER_FLAGS(-malign-double, CFLAGS="$CFLAGS -malign-double")
|
||||
|
||||
# -fstrict-aliasing for gcc-2.95+
|
||||
AX_CHECK_COMPILER_FLAGS(-fstrict-aliasing,
|
||||
CFLAGS="$CFLAGS -fstrict-aliasing")
|
||||
|
||||
# note that we enable "unsafe" fp optimization with other compilers, too
|
||||
AX_CHECK_COMPILER_FLAGS(-ffast-math, CFLAGS="$CFLAGS -ffast-math")
|
||||
|
||||
AX_GCC_ARCHFLAG($acx_maxopt_portable)
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -z "$CFLAGS"; then
|
||||
echo ""
|
||||
echo "********************************************************"
|
||||
echo "* WARNING: Don't know the best CFLAGS for this system *"
|
||||
echo "* Use ./configure CFLAGS=... to specify your own flags *"
|
||||
echo "* (otherwise, a default of CFLAGS=-O3 will be used) *"
|
||||
echo "********************************************************"
|
||||
echo ""
|
||||
CFLAGS="-O3"
|
||||
fi
|
||||
|
||||
AX_CHECK_COMPILER_FLAGS($CFLAGS, [], [
|
||||
echo ""
|
||||
echo "********************************************************"
|
||||
echo "* WARNING: The guessed CFLAGS don't seem to work with *"
|
||||
echo "* your compiler. *"
|
||||
echo "* Use ./configure CFLAGS=... to specify your own flags *"
|
||||
echo "********************************************************"
|
||||
echo ""
|
||||
CFLAGS=""
|
||||
])
|
||||
|
||||
fi
|
||||
])
|
|
@ -0,0 +1,94 @@
|
|||
AC_DEFUN([AX_CFLAGS_WARN_ALL_ANSI],[dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all_ansi])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ansi warnings],
|
||||
VAR,[VAR="no, unknown"
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
# IRIX C compiler:
|
||||
# -use_readonly_const is the default for IRIX C,
|
||||
# puts them into .rodata, but they are copied later.
|
||||
# need to be "-G0 -rdatashared" for strictmode but
|
||||
# I am not sure what effect that has really. - guidod
|
||||
for ac_arg dnl
|
||||
in "-pedantic % -Wall -std=c99 -pedantic" dnl GCC
|
||||
"-xstrconst % -v -xc99=all" dnl Solaris C
|
||||
"-std1 % -verbose -w0 -warnprotos -std1" dnl Digital Unix
|
||||
" % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
|
||||
" % -ansi -ansiE -fullwarn" dnl IRIX
|
||||
"+ESlit % +w1 -Aa" dnl HP-UX C
|
||||
"-Xc % -pvctl[,]fullmsg -Xc" dnl NEC SX-5 (Super-UX 10)
|
||||
"-h conform % -h msglevel 2 -h conform" dnl Cray C (Unicos)
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_TRY_COMPILE([],[return 0;],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
|
||||
AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
|
||||
m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
|
||||
*) m4_ifvaln($3,$3,[
|
||||
if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
|
||||
then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
|
||||
else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
|
||||
m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
|
||||
fi ]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])
|
||||
|
||||
dnl the only difference - the LANG selection... and the default FLAGS
|
||||
|
||||
AC_DEFUN([AX_CXXFLAGS_WARN_ALL_ANSI],[dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_warn_all_ansi])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ansi warnings],
|
||||
VAR,[VAR="no, unknown"
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CXX
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
# IRIX C compiler:
|
||||
# -use_readonly_const is the default for IRIX C,
|
||||
# puts them into .rodata, but they are copied later.
|
||||
# need to be "-G0 -rdatashared" for strictmode but
|
||||
# I am not sure what effect that has really. - guidod
|
||||
for ac_arg dnl
|
||||
in "-pedantic % -Wall -ansi -pedantic" dnl GCC
|
||||
"-xstrconst % -v -Xc" dnl Solaris C
|
||||
"-std1 % -verbose -w0 -warnprotos -std1" dnl Digital Unix
|
||||
" % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
|
||||
" % -ansi -ansiE -fullwarn" dnl IRIX
|
||||
"+ESlit % +w1 -Aa" dnl HP-UX C
|
||||
"-Xc % -pvctl[,]fullmsg -Xc" dnl NEC SX-5 (Super-UX 10)
|
||||
"-h conform % -h msglevel 2 -h conform" dnl Cray C (Unicos)
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_TRY_COMPILE([],[return 0;],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
|
||||
AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
|
||||
m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
|
||||
*) m4_ifvaln($3,$3,[
|
||||
if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
|
||||
then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
|
||||
else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
|
||||
m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
|
||||
fi ]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
AC_DEFUN([AX_CHECK_COMPILER_FLAGS],
|
||||
[AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX
|
||||
AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1])
|
||||
dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname:
|
||||
AS_LITERAL_IF([$1],
|
||||
[AC_CACHE_VAL(AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1), [
|
||||
ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
|
||||
_AC_LANG_PREFIX[]FLAGS="$1"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
|
||||
AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes,
|
||||
AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no)
|
||||
_AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])],
|
||||
[ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
|
||||
_AC_LANG_PREFIX[]FLAGS="$1"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
|
||||
eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes,
|
||||
eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no)
|
||||
_AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])
|
||||
eval ax_check_compiler_flags=$AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)
|
||||
AC_MSG_RESULT($ax_check_compiler_flags)
|
||||
if test "x$ax_check_compiler_flags" = xyes; then
|
||||
m4_default([$2], :)
|
||||
else
|
||||
m4_default([$3], :)
|
||||
fi
|
||||
])dnl AX_CHECK_COMPILER_FLAG
|
|
@ -0,0 +1,15 @@
|
|||
AC_DEFUN([AX_COMPILER_VENDOR],
|
||||
[
|
||||
AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
|
||||
[ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
|
||||
# note: don't check for gcc first since some other compilers define __GNUC__
|
||||
for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
|
||||
vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
|
||||
#if !($vencpp)
|
||||
thisisanerror;
|
||||
#endif
|
||||
])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break])
|
||||
done
|
||||
])
|
||||
])
|
|
@ -0,0 +1,49 @@
|
|||
dnl ======================================================================
|
||||
dnl SAC_OPENSSL
|
||||
dnl ======================================================================
|
||||
AC_DEFUN([SAC_OPENSSL], [
|
||||
|
||||
AC_ARG_WITH(openssl,
|
||||
[ --with-openssl use OpenSSL [[enabled]]],, with_openssl=pkg-config)
|
||||
|
||||
dnl SOSXXX:SAC_ASSERT_DEF([openssl libraries])
|
||||
|
||||
|
||||
if test "$with_openssl" = no ;then
|
||||
: # No openssl
|
||||
else
|
||||
|
||||
if test "$with_openssl" = "pkg-config" ; then
|
||||
PKG_CHECK_MODULES(openssl, openssl,
|
||||
[HAVE_TLS=1 HAVE_OPENSSL=1 LIBS="$openssl_LIBS $LIBS"],
|
||||
[HAVE_OPENSSL=0])
|
||||
fi
|
||||
|
||||
if test x$HAVE_OPENSSL = x1 ; then
|
||||
AC_DEFINE([HAVE_LIBCRYPTO], 1, [Define to 1 if you have the `crypto' library (-lcrypto).])
|
||||
AC_DEFINE([HAVE_LIBSSL], 1, [Define to 1 if you have the `ssl' library (-lssl).])
|
||||
else
|
||||
AC_CHECK_HEADERS([openssl/tls1.h], [
|
||||
HAVE_OPENSSL=1 HAVE_TLS=1
|
||||
|
||||
AC_CHECK_LIB(crypto, BIO_new,,
|
||||
HAVE_OPENSSL=0
|
||||
AC_MSG_WARN(OpenSSL crypto library was not found))
|
||||
|
||||
AC_CHECK_LIB(ssl, TLSv1_method,,
|
||||
HAVE_TLS=0
|
||||
AC_MSG_WARN(OpenSSL protocol library was not found))
|
||||
],[AC_MSG_WARN(OpenSSL include files were not found)],[#include <openssl/safestack.h>])
|
||||
fi
|
||||
|
||||
if test x$HAVE_OPENSSL = x1; then
|
||||
AC_DEFINE([HAVE_OPENSSL], 1, [Define to 1 if you have OpenSSL])
|
||||
fi
|
||||
|
||||
if test x$HAVE_TLS = x1; then
|
||||
AC_DEFINE([HAVE_TLS], 1, [Define to 1 if you have TLS])
|
||||
fi
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(HAVE_TLS, test x$HAVE_TLS = x1)
|
||||
])
|
|
@ -0,0 +1,258 @@
|
|||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(libks, 0.1, bugs@freeswitch.org)
|
||||
AC_CONFIG_AUX_DIR(build)
|
||||
AC_CONFIG_MACRO_DIR([build])
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_CONFIG_SRCDIR([src])
|
||||
|
||||
# disable checks
|
||||
m4_defun([_LT_AC_LANG_CXX_CONFIG], [:])
|
||||
m4_defun([_LT_AC_LANG_F77_CONFIG], [:])
|
||||
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_INSTALL
|
||||
|
||||
# Optimize
|
||||
AC_ARG_ENABLE(optimization,
|
||||
[AC_HELP_STRING([--enable-optimization],[Set if you want us to add max optimising compiler flags])],[enable_optimizer="$enableval"],[enable_optimizer="no"])
|
||||
|
||||
if test "${enable_optimizer}" = "yes" ; then
|
||||
AC_DEFINE([OPTIMZER],[],[Enable Optimization.])
|
||||
AX_CC_MAXOPT
|
||||
fi
|
||||
|
||||
# Enable debugging
|
||||
AC_ARG_ENABLE(debug,
|
||||
[AC_HELP_STRING([--enable-debug],[build with debug information])],[enable_debug="$enable_debug"],[enable_debug="no"])
|
||||
|
||||
if test "${enable_debug}" = "yes"; then
|
||||
AC_DEFINE([DEBUG],[],[Enable extra debugging.])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([WANT_DEBUG],[test "${enable_debug}" = "yes"])
|
||||
|
||||
dnl check for the compiler used
|
||||
AX_COMPILER_VENDOR
|
||||
|
||||
case "$host" in
|
||||
*-solaris2*)
|
||||
if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then
|
||||
AM_CFLAGS="-KPIC -DPIC"
|
||||
AM_LDFLAGS="-R${prefix}/lib"
|
||||
fi
|
||||
;;
|
||||
*-darwin*)
|
||||
if test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
|
||||
AM_CFLAGS="-DMACOSX"
|
||||
fi
|
||||
;;
|
||||
x86_64-unknown-linux-gnu)
|
||||
AM_CFLAGS="-fPIC"
|
||||
AM_LDFLAGS=""
|
||||
;;
|
||||
i*6-unknown-linux-gnu)
|
||||
AM_CFLAGS="-fpic"
|
||||
AM_LDFLAGS=""
|
||||
;;
|
||||
x86_64-*-freebsd*|amd64-*-freebsd*)
|
||||
AM_CFLAGS="-fpic"
|
||||
AM_LDFLAGS=""
|
||||
;;
|
||||
i*6-*-freebsd*)
|
||||
AM_CFLAGS="-fpic"
|
||||
AM_LDFLAGS=""
|
||||
;;
|
||||
esac
|
||||
|
||||
AX_CFLAGS_WARN_ALL_ANSI
|
||||
|
||||
AC_CHECK_LIB(rt, clock_gettime, [AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define if you have clock_gettime()])])
|
||||
AC_CHECK_LIB(rt, clock_getres, [AC_DEFINE(HAVE_CLOCK_GETRES, 1, [Define if you have clock_getres()])])
|
||||
AC_CHECK_LIB(rt, clock_nanosleep, [AC_DEFINE(HAVE_CLOCK_NANOSLEEP, 1, [Define if you have clock_nanosleep()])])
|
||||
AC_CHECK_FUNCS([usleep])
|
||||
|
||||
#
|
||||
# sched_setcheduler + round-robin scheduler prerequisites
|
||||
#
|
||||
AC_CHECK_HEADERS([sched.h byteswap.h sys/endian.h])
|
||||
AC_CHECK_DECL([SCHED_RR],
|
||||
[AC_DEFINE([HAVE_SCHED_RR],[1],[SCHED_RR constant for sched_setscheduler])],,
|
||||
[#ifdef HAVE_SCHED_H
|
||||
#include <sched.h>
|
||||
#endif])
|
||||
AC_CHECK_FUNCS([sched_setscheduler memmem])
|
||||
|
||||
if test "x${ac_cv_func_sched_setscheduler}" = "xyes" -a \
|
||||
"x${ac_cv_have_decl_SCHED_RR}" = "xyes"
|
||||
then
|
||||
AC_DEFINE([USE_SCHED_SETSCHEDULER],[1],[Enable round-robin scheduler using sched_setscheduler])
|
||||
AM_CFLAGS="${AM_CFLAGS} -DUSE_SCHED_SETSCHEDULER=1"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
#
|
||||
# gcc visibility cflag checks
|
||||
#
|
||||
AC_ARG_ENABLE([visibility],
|
||||
[AS_HELP_STRING([--disable-visibility], [Disable or enable API visibility support (default: use if available)])],
|
||||
[enable_visibility="${enableval}"],
|
||||
[enable_visibility="detect"]
|
||||
)
|
||||
HAVE_VISIBILITY="no"
|
||||
|
||||
if test "x${enable_visibility}" != "xno" ; then
|
||||
|
||||
case "${ax_cv_c_compiler_vendor}" in
|
||||
gnu)
|
||||
save_CFLAGS="${CFLAGS}"
|
||||
CFLAGS="${CFLAGS} -fvisibility=hidden"
|
||||
AC_MSG_CHECKING([whether the compiler supports -fvisibility=hidden])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[int foo __attribute__ ((visibility("default")));],
|
||||
[;]
|
||||
)],
|
||||
|
||||
[AC_MSG_RESULT([yes])
|
||||
AM_CFLAGS="${AM_CFLAGS} -DKS_API_VISIBILITY=1 -fvisibility=hidden"
|
||||
AC_DEFINE([HAVE_VISIBILITY], [1], [GCC visibility support available])
|
||||
HAVE_VISIBILITY="yes"],
|
||||
|
||||
[AC_MSG_RESULT([no])]
|
||||
)
|
||||
CFLAGS="${save_CFLAGS}"
|
||||
;;
|
||||
|
||||
sun)
|
||||
save_CFLAGS="${CFLAGS}"
|
||||
CFLAGS="${CFLAGS} -xldscope=hidden"
|
||||
AC_MSG_CHECKING([whether the compiler supports -xldscope=hidden])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[int foo __attribute__ ((visibility("default")));],
|
||||
[;]
|
||||
)],
|
||||
|
||||
[AC_MSG_RESULT([yes])
|
||||
AM_CFLAGS="${AM_CFLAGS} -DKS_API_VISIBILITY=1 -xldscope=hidden"
|
||||
AC_DEFINE([HAVE_VISIBILITY], [1], [SUNCC visibility support available])
|
||||
HAVE_VISIBILITY="yes"],
|
||||
|
||||
[AC_MSG_RESULT([no])]
|
||||
)
|
||||
CFLAGS="${save_CFLAGS}"
|
||||
;;
|
||||
|
||||
*)
|
||||
if test "x${enable_visibility}" = "xyes" ; then
|
||||
AC_MSG_ERROR([Non-GNU / SUN compilers are currently unsupported])
|
||||
else
|
||||
AC_MSG_WARN([Non-GNU / SUN compilers are currently unsupported])
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
#
|
||||
# visibility explicitly requested but not supported by this compiler => error
|
||||
#
|
||||
if test "x${enable_visibility}" = "xyes" -a "x${HAVE_VISIBILITY}" = "xno" ; then
|
||||
AC_MSG_ERROR([API visibility not supported by this compiler])
|
||||
fi
|
||||
fi
|
||||
|
||||
AM_CFLAGS="${AM_CFLAGS} -Werror"
|
||||
AC_SUBST(AM_CFLAGS)
|
||||
AC_SUBST(AM_LDFLAGS)
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_TYPE_SIZE_T
|
||||
AC_HEADER_TIME
|
||||
AC_STRUCT_TM
|
||||
|
||||
# Checks for library functions.
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_MALLOC
|
||||
AC_TYPE_SIGNAL
|
||||
AC_FUNC_STRFTIME
|
||||
|
||||
AC_CHECK_LIB(pthread, pthread_setschedparam, [
|
||||
AC_DEFINE(HAVE_PTHREAD_SETSCHEDPARAM, 1, [Define if you have pthread_setschedparam()])
|
||||
AM_CFLAGS="${AM_CFLAGS} -DHAVE_PTHREAD_SETSCHEDPARAM=1"
|
||||
])
|
||||
|
||||
AC_C_BIGENDIAN(AC_DEFINE([__BYTE_ORDER],__BIG_ENDIAN,[Big Endian]),AC_DEFINE([__BYTE_ORDER],__LITTLE_ENDIAN,[Little Endian]))
|
||||
AC_DEFINE([__LITTLE_ENDIAN],1234,[for the places where it is not defined])
|
||||
AC_DEFINE([__BIG_ENDIAN],4321,[for the places where it is not defined])
|
||||
|
||||
path_remove () {
|
||||
echo "$1" | tr ':' '\n' | grep -Fxv "$2" | tr '\n' ':' | sed 's/:$//'
|
||||
}
|
||||
path_push_unique () {
|
||||
x="$(eval echo \$$1)"
|
||||
x="$(path_remove "$x" "$2")"
|
||||
if test -z "$x"; then
|
||||
eval export $1="$2"
|
||||
else
|
||||
eval export $1="$2:$x"
|
||||
fi
|
||||
}
|
||||
|
||||
case $host in
|
||||
*-darwin*)
|
||||
path_push_unique PKG_CONFIG_PATH /usr/local/opt/openssl/lib/pkgconfig
|
||||
;;
|
||||
esac
|
||||
|
||||
SAC_OPENSSL
|
||||
|
||||
if test x$HAVE_OPENSSL = x1; then
|
||||
openssl_CFLAGS="$openssl_CFLAGS -DHAVE_OPENSSL";
|
||||
AM_CFLAGS="${AM_CFLAGS} ${openssl_CFLAGS} -DHAVE_OPENSSL"
|
||||
AM_LDFLAGS="${AM_LDFLAGS} ${openssl_LIBS}"
|
||||
else
|
||||
AC_MSG_ERROR([OpenSSL and associated developement headers required])
|
||||
fi
|
||||
|
||||
|
||||
# Enable clang address sanitizer bit build
|
||||
AC_ARG_ENABLE(address_sanitizer,
|
||||
[AC_HELP_STRING([--enable-address-sanitizer],[build with address sanitizer])],
|
||||
[enable_address_sanitizer="$enable_address_sanitizer"],
|
||||
[enable_address_sanitizer="no"])
|
||||
|
||||
if test "${enable_address_sanitizer}" = "yes"; then
|
||||
if test "x${ax_cv_c_compiler_vendor}" = "xclang" ; then
|
||||
AM_CFLAGS="${AM_CFLAGS} -fsanitize=address -fno-omit-frame-pointer"
|
||||
AM_CXXFLAGS="${AM_CXXFLAGS} -fsanitize=address -fno-omit-frame-pointer"
|
||||
AM_LDFLAGS="${AM_LDFLAGS} -fsanitize=address"
|
||||
fi
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES([SODIUM], [libsodium >= 1.0.0],[AC_MSG_RESULT([yes])],[AC_MSG_ERROR([libsodium is required])])
|
||||
PKG_CHECK_MODULES([UUID], [uuid >= 1.0.0],[AC_MSG_RESULT([yes])],[AC_MSG_ERROR([libuuid is required])])
|
||||
|
||||
AM_CFLAGS="${AM_CFLAGS} -Werror ${SODIUM_CFLAGS} ${UUID_CFLAGS}"
|
||||
AM_LDFLAGS="${AM_LDFLAGS} ${SODIUM_LIBS} ${UUID_LIBS}"
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
test/Makefile
|
||||
libks.pc
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
This file contains the definitions required to use AES in C. See aesopt.h
|
||||
for optimisation details.
|
||||
*/
|
||||
|
||||
#ifndef _AES_H
|
||||
#define _AES_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* This include is used to find 8 & 32 bit unsigned integer types */
|
||||
#include "brg_types.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define AES_128 /* if a fast 128 bit key scheduler is needed */
|
||||
#define AES_192 /* if a fast 192 bit key scheduler is needed */
|
||||
#define AES_256 /* if a fast 256 bit key scheduler is needed */
|
||||
#define AES_VAR /* if variable key size scheduler is needed */
|
||||
#define AES_MODES /* if support is needed for modes */
|
||||
|
||||
/* The following must also be set in assembler files if being used */
|
||||
|
||||
#define AES_ENCRYPT /* if support for encryption is needed */
|
||||
#define AES_DECRYPT /* if support for decryption is needed */
|
||||
#define AES_REV_DKS /* define to reverse decryption key schedule */
|
||||
|
||||
#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */
|
||||
#define N_COLS 4 /* the number of columns in the state */
|
||||
|
||||
/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */
|
||||
/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */
|
||||
/* or 44, 52 or 60 32-bit words. */
|
||||
|
||||
#if defined( AES_VAR ) || defined( AES_256 )
|
||||
#define KS_LENGTH 60
|
||||
#elif defined( AES_192 )
|
||||
#define KS_LENGTH 52
|
||||
#else
|
||||
#define KS_LENGTH 44
|
||||
#endif
|
||||
|
||||
#define AES_RETURN INT_RETURN
|
||||
|
||||
/* the character array 'inf' in the following structures is used */
|
||||
/* to hold AES context information. This AES code uses cx->inf.b[0] */
|
||||
/* to hold the number of rounds multiplied by 16. The other three */
|
||||
/* elements can be used by code that implements additional modes */
|
||||
|
||||
typedef union
|
||||
{ uint_32t l;
|
||||
uint_8t b[4];
|
||||
} aes_inf;
|
||||
|
||||
typedef struct
|
||||
{ uint_32t ks[KS_LENGTH];
|
||||
aes_inf inf;
|
||||
} aes_encrypt_ctx;
|
||||
|
||||
typedef struct
|
||||
{ uint_32t ks[KS_LENGTH];
|
||||
aes_inf inf;
|
||||
} aes_decrypt_ctx;
|
||||
|
||||
/* This routine must be called before first use if non-static */
|
||||
/* tables are being used */
|
||||
|
||||
AES_RETURN ks_aes_init(void);
|
||||
|
||||
/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */
|
||||
/* those in the range 128 <= key_len <= 256 are given in bits */
|
||||
|
||||
#if defined( AES_ENCRYPT )
|
||||
|
||||
#if defined( AES_128 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_192 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_256 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_VAR )
|
||||
AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( AES_DECRYPT )
|
||||
|
||||
#if defined( AES_128 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_192 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_256 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_VAR )
|
||||
AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( AES_MODES )
|
||||
|
||||
/* Multiple calls to the following subroutines for multiple block */
|
||||
/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */
|
||||
/* long messages incremantally provided that the context AND the iv */
|
||||
/* are preserved between all such calls. For the ECB and CBC modes */
|
||||
/* each individual call within a series of incremental calls must */
|
||||
/* process only full blocks (i.e. len must be a multiple of 16) but */
|
||||
/* the CFB, OFB and CTR mode calls can handle multiple incremental */
|
||||
/* calls of any length. Each mode is reset when a new AES key is */
|
||||
/* set but ECB and CBC operations can be reset without setting a */
|
||||
/* new key by setting a new IV value. To reset CFB, OFB and CTR */
|
||||
/* without setting the key, aes_mode_reset() must be called and the */
|
||||
/* IV must be set. NOTE: All these calls update the IV on exit so */
|
||||
/* this has to be reset if a new operation with the same IV as the */
|
||||
/* previous one is required (or decryption follows encryption with */
|
||||
/* the same IV array). */
|
||||
|
||||
AES_RETURN aes_test_alignment_detection(unsigned int n);
|
||||
|
||||
AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_decrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_decrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
|
||||
|
||||
#define aes_ofb_encrypt aes_ofb_crypt
|
||||
#define aes_ofb_decrypt aes_ofb_crypt
|
||||
|
||||
AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
|
||||
|
||||
typedef void cbuf_inc(unsigned char *cbuf);
|
||||
|
||||
#define aes_ctr_encrypt aes_ctr_crypt
|
||||
#define aes_ctr_decrypt aes_ctr_crypt
|
||||
|
||||
AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,946 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
These subroutines implement multiple block AES modes for ECB, CBC, CFB,
|
||||
OFB and CTR encryption, The code provides support for the VIA Advanced
|
||||
Cryptography Engine (ACE).
|
||||
|
||||
NOTE: In the following subroutines, the AES contexts (ctx) must be
|
||||
16 byte aligned if VIA ACE is being used
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined( AES_MODES )
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER ) && ( _MSC_VER > 800 )
|
||||
#pragma intrinsic(memcpy)
|
||||
#endif
|
||||
|
||||
#define BFR_BLOCKS 8
|
||||
|
||||
/* These values are used to detect long word alignment in order to */
|
||||
/* speed up some buffer operations. This facility may not work on */
|
||||
/* some machines so this define can be commented out if necessary */
|
||||
|
||||
#define FAST_BUFFER_OPERATIONS
|
||||
|
||||
#define lp32(x) ((uint_32t*)(x))
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
#include "aes_via_ace.h"
|
||||
|
||||
#pragma pack(16)
|
||||
|
||||
aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA;
|
||||
aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA;
|
||||
aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA;
|
||||
aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA;
|
||||
aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA;
|
||||
aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA;
|
||||
|
||||
/* NOTE: These control word macros must only be used after */
|
||||
/* a key has been set up because they depend on key size */
|
||||
/* See the VIA ACE documentation for key type information */
|
||||
/* and aes_via_ace.h for non-default NEH_KEY_TYPE values */
|
||||
|
||||
#ifndef NEH_KEY_TYPE
|
||||
# define NEH_KEY_TYPE NEH_HYBRID
|
||||
#endif
|
||||
|
||||
#if NEH_KEY_TYPE == NEH_LOAD
|
||||
#define kd_adr(c) ((uint_8t*)(c)->ks)
|
||||
#elif NEH_KEY_TYPE == NEH_GENERATE
|
||||
#define kd_adr(c) ((uint_8t*)(c)->ks + (c)->inf.b[0])
|
||||
#elif NEH_KEY_TYPE == NEH_HYBRID
|
||||
#define kd_adr(c) ((uint_8t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0))
|
||||
#else
|
||||
#error no key type defined for VIA ACE
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define aligned_array(type, name, no, stride) type name[no]
|
||||
#define aligned_auto(type, name, no, stride) type name[no]
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER ) && _MSC_VER > 1200
|
||||
|
||||
#define via_cwd(cwd, ty, dir, len) \
|
||||
unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4))
|
||||
|
||||
#else
|
||||
|
||||
#define via_cwd(cwd, ty, dir, len) \
|
||||
aligned_auto(unsigned long, cwd, 4, 16); \
|
||||
cwd[1] = cwd[2] = cwd[3] = 0; \
|
||||
cwd[0] = neh_##dir##_##ty##_key(len)
|
||||
|
||||
#endif
|
||||
|
||||
/* test the code for detecting and setting pointer alignment */
|
||||
|
||||
AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */
|
||||
{ uint_8t p[16];
|
||||
uint_32t i, count_eq = 0, count_neq = 0;
|
||||
|
||||
if(n < 4 || n > 16)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
for(i = 0; i < n; ++i)
|
||||
{
|
||||
uint_8t *qf = ALIGN_FLOOR(p + i, n),
|
||||
*qh = ALIGN_CEIL(p + i, n);
|
||||
|
||||
if(qh == qf)
|
||||
++count_eq;
|
||||
else if(qh == qf + n)
|
||||
++count_neq;
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1])
|
||||
{
|
||||
ctx->inf.b[2] = 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_encrypt_ctx ctx[1])
|
||||
{ int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint_8t *ksp = (uint_8t*)(ctx->ks);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
|
||||
{
|
||||
via_ecb_op5(ksp, cwd, ibuf, obuf, nb);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ecb_op5(ksp, cwd, ip, op, m);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
while(nb--)
|
||||
{
|
||||
if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_decrypt_ctx ctx[1])
|
||||
{ int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint_8t *ksp = kd_adr(ctx);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
|
||||
{
|
||||
via_ecb_op5(ksp, cwd, ibuf, obuf, nb);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ecb_op5(ksp, cwd, ip, op, m);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
while(nb--)
|
||||
{
|
||||
if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_encrypt_ctx ctx[1])
|
||||
{ int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 ))
|
||||
{
|
||||
via_cbc_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cbc_op7(ksp, cwd, ip, op, m, ivp, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
if(iv != ivp)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
|
||||
while(nb--)
|
||||
{
|
||||
lp32(iv)[0] ^= lp32(ibuf)[0];
|
||||
lp32(iv)[1] ^= lp32(ibuf)[1];
|
||||
lp32(iv)[2] ^= lp32(ibuf)[2];
|
||||
lp32(iv)[3] ^= lp32(ibuf)[3];
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
memcpy(obuf, iv, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(nb--)
|
||||
{
|
||||
iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1];
|
||||
iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3];
|
||||
iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5];
|
||||
iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7];
|
||||
iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9];
|
||||
iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11];
|
||||
iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13];
|
||||
iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15];
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
memcpy(obuf, iv, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_decrypt_ctx ctx[1])
|
||||
{ unsigned char tmp[AES_BLOCK_SIZE];
|
||||
int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint_8t *ksp = kd_adr(ctx), *ivp = iv;
|
||||
aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 ))
|
||||
{
|
||||
via_cbc_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cbc_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
if(iv != ivp)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
|
||||
while(nb--)
|
||||
{
|
||||
memcpy(tmp, ibuf, AES_BLOCK_SIZE);
|
||||
if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
lp32(obuf)[0] ^= lp32(iv)[0];
|
||||
lp32(obuf)[1] ^= lp32(iv)[1];
|
||||
lp32(obuf)[2] ^= lp32(iv)[2];
|
||||
lp32(obuf)[3] ^= lp32(iv)[3];
|
||||
memcpy(iv, tmp, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(nb--)
|
||||
{
|
||||
memcpy(tmp, ibuf, AES_BLOCK_SIZE);
|
||||
if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1];
|
||||
obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3];
|
||||
obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5];
|
||||
obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7];
|
||||
obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9];
|
||||
obuf[10] ^= iv[10]; obuf[11] ^= iv[11];
|
||||
obuf[12] ^= iv[12]; obuf[13] ^= iv[13];
|
||||
obuf[14] ^= iv[14]; obuf[15] ^= iv[15];
|
||||
memcpy(iv, tmp, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
|
||||
{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len)
|
||||
{
|
||||
*obuf++ = (iv[b_pos++] ^= *ibuf++);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ int m;
|
||||
uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
|
||||
{
|
||||
via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
}
|
||||
else /* input, output or both are unaligned */
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0];
|
||||
lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1];
|
||||
lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2];
|
||||
lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1];
|
||||
obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3];
|
||||
obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5];
|
||||
obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7];
|
||||
obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9];
|
||||
obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11];
|
||||
obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13];
|
||||
obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len)
|
||||
{
|
||||
if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE)
|
||||
{
|
||||
*obuf++ = (iv[b_pos++] ^= *ibuf++);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint_8t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
|
||||
{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{ uint_8t t;
|
||||
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len)
|
||||
{
|
||||
t = *ibuf++;
|
||||
*obuf++ = t ^ iv[b_pos];
|
||||
iv[b_pos++] = t;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ int m;
|
||||
uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
|
||||
{
|
||||
via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
}
|
||||
else /* input, output or both are unaligned */
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf) /* input buffer is not aligned */
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cfb_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf) /* output buffer is not aligned */
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 ))
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{ uint_32t t;
|
||||
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t;
|
||||
t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t;
|
||||
t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t;
|
||||
t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{ uint_8t t;
|
||||
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t;
|
||||
t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t;
|
||||
t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t;
|
||||
t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t;
|
||||
t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t;
|
||||
t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t;
|
||||
t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t;
|
||||
t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t;
|
||||
t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t;
|
||||
t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t;
|
||||
t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t;
|
||||
t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t;
|
||||
t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t;
|
||||
t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t;
|
||||
t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t;
|
||||
t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len)
|
||||
{ uint_8t t;
|
||||
|
||||
if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE)
|
||||
{
|
||||
t = *ibuf++;
|
||||
*obuf++ = t ^ iv[b_pos];
|
||||
iv[b_pos++] = t;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint_8t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
|
||||
{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len)
|
||||
{
|
||||
*obuf++ = iv[b_pos++] ^ *ibuf++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ int m;
|
||||
uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
|
||||
{
|
||||
via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
}
|
||||
else /* input, output or both are unaligned */
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ofb_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0];
|
||||
lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1];
|
||||
lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2];
|
||||
lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1];
|
||||
obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3];
|
||||
obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5];
|
||||
obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7];
|
||||
obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9];
|
||||
obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11];
|
||||
obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13];
|
||||
obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len)
|
||||
{
|
||||
if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE)
|
||||
{
|
||||
*obuf++ = iv[b_pos++] ^ *ibuf++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint_8t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE)
|
||||
|
||||
AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1])
|
||||
{ unsigned char *ip;
|
||||
int i, blen, b_pos = (int)(ctx->inf.b[2]);
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
aligned_auto(uint_8t, buf, BFR_LENGTH, 16);
|
||||
if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
#else
|
||||
uint_8t buf[BFR_LENGTH];
|
||||
#endif
|
||||
|
||||
if(b_pos)
|
||||
{
|
||||
memcpy(buf, cbuf, AES_BLOCK_SIZE);
|
||||
if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while(b_pos < AES_BLOCK_SIZE && len)
|
||||
{
|
||||
*obuf++ = *ibuf++ ^ buf[b_pos++];
|
||||
--len;
|
||||
}
|
||||
|
||||
if(len)
|
||||
ctr_inc(cbuf), b_pos = 0;
|
||||
}
|
||||
|
||||
while(len)
|
||||
{
|
||||
blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen;
|
||||
|
||||
for(i = 0, ip = buf; i < (blen >> 4); ++i)
|
||||
{
|
||||
memcpy(ip, cbuf, AES_BLOCK_SIZE);
|
||||
ctr_inc(cbuf);
|
||||
ip += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if(blen & (AES_BLOCK_SIZE - 1))
|
||||
memcpy(ip, cbuf, AES_BLOCK_SIZE), i++;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
via_ecb_op5((ctx->ks), cwd, buf, buf, i);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
i = 0; ip = buf;
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 ))
|
||||
while(i + AES_BLOCK_SIZE <= blen)
|
||||
{
|
||||
lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0];
|
||||
lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1];
|
||||
lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2];
|
||||
lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3];
|
||||
i += AES_BLOCK_SIZE;
|
||||
ip += AES_BLOCK_SIZE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while(i + AES_BLOCK_SIZE <= blen)
|
||||
{
|
||||
obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1];
|
||||
obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3];
|
||||
obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5];
|
||||
obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7];
|
||||
obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9];
|
||||
obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11];
|
||||
obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13];
|
||||
obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15];
|
||||
i += AES_BLOCK_SIZE;
|
||||
ip += AES_BLOCK_SIZE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
while(i++ < blen)
|
||||
*obuf++ = *ibuf++ ^ ip[b_pos++];
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint_8t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
This file contains the definitions required to use AES (Rijndael) in C++.
|
||||
*/
|
||||
|
||||
#ifndef _AESCPP_H
|
||||
#define _AESCPP_H
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
#if defined( AES_ENCRYPT )
|
||||
|
||||
class AESencrypt
|
||||
{
|
||||
public:
|
||||
aes_encrypt_ctx cx[1];
|
||||
AESencrypt(void) { aes_init_zrtp(); };
|
||||
#if defined(AES_128)
|
||||
AESencrypt(const unsigned char key[])
|
||||
{ aes_encrypt_key128(key, cx); }
|
||||
AES_RETURN key128(const unsigned char key[])
|
||||
{ return aes_encrypt_key128(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_192)
|
||||
AES_RETURN key192(const unsigned char key[])
|
||||
{ return aes_encrypt_key192(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_256)
|
||||
AES_RETURN key256(const unsigned char key[])
|
||||
{ return aes_encrypt_key256(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_VAR)
|
||||
AES_RETURN key(const unsigned char key[], int key_len)
|
||||
{ return aes_encrypt_key(key, key_len, cx); }
|
||||
#endif
|
||||
AES_RETURN encrypt(const unsigned char in[], unsigned char out[]) const
|
||||
{ return aes_encrypt(in, out, cx); }
|
||||
#ifndef AES_MODES
|
||||
AES_RETURN ecb_encrypt(const unsigned char in[], unsigned char out[], int nb) const
|
||||
{ while(nb--)
|
||||
{ aes_encrypt(in, out, cx), in += AES_BLOCK_SIZE, out += AES_BLOCK_SIZE; }
|
||||
}
|
||||
#endif
|
||||
#ifdef AES_MODES
|
||||
AES_RETURN mode_reset(void) { return aes_mode_reset(cx); }
|
||||
|
||||
AES_RETURN ecb_encrypt(const unsigned char in[], unsigned char out[], int nb) const
|
||||
{ return aes_ecb_encrypt(in, out, nb, cx); }
|
||||
|
||||
AES_RETURN cbc_encrypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[]) const
|
||||
{ return aes_cbc_encrypt(in, out, nb, iv, cx); }
|
||||
|
||||
AES_RETURN cfb_encrypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[])
|
||||
{ return aes_cfb_encrypt(in, out, nb, iv, cx); }
|
||||
|
||||
AES_RETURN cfb_decrypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[])
|
||||
{ return aes_cfb_decrypt(in, out, nb, iv, cx); }
|
||||
|
||||
AES_RETURN ofb_crypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[])
|
||||
{ return aes_ofb_crypt(in, out, nb, iv, cx); }
|
||||
|
||||
typedef void ctr_fn(unsigned char ctr[]);
|
||||
|
||||
AES_RETURN ctr_crypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[], ctr_fn cf)
|
||||
{ return aes_ctr_crypt(in, out, nb, iv, cf, cx); }
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( AES_DECRYPT )
|
||||
|
||||
class AESdecrypt
|
||||
{
|
||||
public:
|
||||
aes_decrypt_ctx cx[1];
|
||||
AESdecrypt(void) { aes_init_zrtp(); };
|
||||
#if defined(AES_128)
|
||||
AESdecrypt(const unsigned char key[])
|
||||
{ aes_decrypt_key128(key, cx); }
|
||||
AES_RETURN key128(const unsigned char key[])
|
||||
{ return aes_decrypt_key128(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_192)
|
||||
AES_RETURN key192(const unsigned char key[])
|
||||
{ return aes_decrypt_key192(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_256)
|
||||
AES_RETURN key256(const unsigned char key[])
|
||||
{ return aes_decrypt_key256(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_VAR)
|
||||
AES_RETURN key(const unsigned char key[], int key_len)
|
||||
{ return aes_decrypt_key(key, key_len, cx); }
|
||||
#endif
|
||||
AES_RETURN decrypt(const unsigned char in[], unsigned char out[]) const
|
||||
{ return aes_decrypt(in, out, cx); }
|
||||
#ifndef AES_MODES
|
||||
AES_RETURN ecb_decrypt(const unsigned char in[], unsigned char out[], int nb) const
|
||||
{ while(nb--)
|
||||
{ aes_decrypt(in, out, cx), in += AES_BLOCK_SIZE, out += AES_BLOCK_SIZE; }
|
||||
}
|
||||
#endif
|
||||
#ifdef AES_MODES
|
||||
|
||||
AES_RETURN ecb_decrypt(const unsigned char in[], unsigned char out[], int nb) const
|
||||
{ return aes_ecb_decrypt(in, out, nb, cx); }
|
||||
|
||||
AES_RETURN cbc_decrypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[]) const
|
||||
{ return aes_cbc_decrypt(in, out, nb, iv, cx); }
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
#include "aestab.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c])
|
||||
#define so(y,x,c) word_out(y, c, s(x,c))
|
||||
|
||||
#if defined(ARRAYS)
|
||||
#define locals(y,x) x[4],y[4]
|
||||
#else
|
||||
#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
|
||||
#endif
|
||||
|
||||
#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
|
||||
s(y,2) = s(x,2); s(y,3) = s(x,3);
|
||||
#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
|
||||
#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
|
||||
#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
|
||||
|
||||
#if ( FUNCS_IN_C & ENCRYPTION_IN_C )
|
||||
|
||||
/* Visual C++ .Net v7.1 provides the fastest encryption code when using
|
||||
Pentium optimiation with small code but this is poor for decryption
|
||||
so we need to control this with the following VC++ pragmas
|
||||
*/
|
||||
|
||||
#if defined( _MSC_VER ) && !defined( _WIN64 )
|
||||
#pragma optimize( "s", on )
|
||||
#endif
|
||||
|
||||
/* Given the column (c) of the output state variable, the following
|
||||
macros give the input state variables which are needed in its
|
||||
computation for each row (r) of the state. All the alternative
|
||||
macros give the same end values but expand into different ways
|
||||
of calculating these values. In particular the complex macro
|
||||
used for dynamically variable block sizes is designed to expand
|
||||
to a compile time constant whenever possible but will expand to
|
||||
conditional clauses on some branches (I am grateful to Frank
|
||||
Yellin for this construction)
|
||||
*/
|
||||
|
||||
#define fwd_var(x,r,c)\
|
||||
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
|
||||
: r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
|
||||
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
|
||||
: ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
|
||||
|
||||
#if defined(FT4_SET)
|
||||
#undef dec_fmvars
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
|
||||
#elif defined(FT1_SET)
|
||||
#undef dec_fmvars
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c))
|
||||
#else
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c)))
|
||||
#endif
|
||||
|
||||
#if defined(FL4_SET)
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c))
|
||||
#elif defined(FL1_SET)
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c))
|
||||
#else
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c))
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1])
|
||||
{ uint_32t locals(b0, b1);
|
||||
const uint_32t *kp;
|
||||
#if defined( dec_fmvars )
|
||||
dec_fmvars; /* declare variables for fwd_mcol() if needed */
|
||||
#endif
|
||||
|
||||
if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 )
|
||||
return EXIT_FAILURE;
|
||||
|
||||
kp = cx->ks;
|
||||
state_in(b0, in, kp);
|
||||
|
||||
#if (ENC_UNROLL == FULL)
|
||||
|
||||
switch(cx->inf.b[0])
|
||||
{
|
||||
case 14 * 16:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
kp += 2 * N_COLS;
|
||||
case 12 * 16:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
kp += 2 * N_COLS;
|
||||
case 10 * 16:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 3 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 4 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 5 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 6 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 7 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 8 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 9 * N_COLS);
|
||||
round(fwd_lrnd, b0, b1, kp +10 * N_COLS);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (ENC_UNROLL == PARTIAL)
|
||||
{ uint_32t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd)
|
||||
{
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b0, b1, kp);
|
||||
}
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
#else
|
||||
{ uint_32t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd)
|
||||
{
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
l_copy(b0, b1);
|
||||
}
|
||||
#endif
|
||||
kp += N_COLS;
|
||||
round(fwd_lrnd, b0, b1, kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
state_out(out, b0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if ( FUNCS_IN_C & DECRYPTION_IN_C)
|
||||
|
||||
/* Visual C++ .Net v7.1 provides the fastest encryption code when using
|
||||
Pentium optimiation with small code but this is poor for decryption
|
||||
so we need to control this with the following VC++ pragmas
|
||||
*/
|
||||
|
||||
#if defined( _MSC_VER ) && !defined( _WIN64 )
|
||||
#pragma optimize( "t", on )
|
||||
#endif
|
||||
|
||||
/* Given the column (c) of the output state variable, the following
|
||||
macros give the input state variables which are needed in its
|
||||
computation for each row (r) of the state. All the alternative
|
||||
macros give the same end values but expand into different ways
|
||||
of calculating these values. In particular the complex macro
|
||||
used for dynamically variable block sizes is designed to expand
|
||||
to a compile time constant whenever possible but will expand to
|
||||
conditional clauses on some branches (I am grateful to Frank
|
||||
Yellin for this construction)
|
||||
*/
|
||||
|
||||
#define inv_var(x,r,c)\
|
||||
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
|
||||
: r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\
|
||||
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
|
||||
: ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0)))
|
||||
|
||||
#if defined(IT4_SET)
|
||||
#undef dec_imvars
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c))
|
||||
#elif defined(IT1_SET)
|
||||
#undef dec_imvars
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c))
|
||||
#else
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)))
|
||||
#endif
|
||||
|
||||
#if defined(IL4_SET)
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c))
|
||||
#elif defined(IL1_SET)
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c))
|
||||
#else
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))
|
||||
#endif
|
||||
|
||||
/* This code can work with the decryption key schedule in the */
|
||||
/* order that is used for encrytpion (where the 1st decryption */
|
||||
/* round key is at the high end ot the schedule) or with a key */
|
||||
/* schedule that has been reversed to put the 1st decryption */
|
||||
/* round key at the low end of the schedule in memory (when */
|
||||
/* AES_REV_DKS is defined) */
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
#define key_ofs 0
|
||||
#define rnd_key(n) (kp + n * N_COLS)
|
||||
#else
|
||||
#define key_ofs 1
|
||||
#define rnd_key(n) (kp - n * N_COLS)
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1])
|
||||
{ uint_32t locals(b0, b1);
|
||||
#if defined( dec_imvars )
|
||||
dec_imvars; /* declare variables for inv_mcol() if needed */
|
||||
#endif
|
||||
const uint_32t *kp;
|
||||
|
||||
if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 )
|
||||
return EXIT_FAILURE;
|
||||
|
||||
kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0);
|
||||
state_in(b0, in, kp);
|
||||
|
||||
#if (DEC_UNROLL == FULL)
|
||||
|
||||
kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2));
|
||||
switch(cx->inf.b[0])
|
||||
{
|
||||
case 14 * 16:
|
||||
round(inv_rnd, b1, b0, rnd_key(-13));
|
||||
round(inv_rnd, b0, b1, rnd_key(-12));
|
||||
case 12 * 16:
|
||||
round(inv_rnd, b1, b0, rnd_key(-11));
|
||||
round(inv_rnd, b0, b1, rnd_key(-10));
|
||||
case 10 * 16:
|
||||
round(inv_rnd, b1, b0, rnd_key(-9));
|
||||
round(inv_rnd, b0, b1, rnd_key(-8));
|
||||
round(inv_rnd, b1, b0, rnd_key(-7));
|
||||
round(inv_rnd, b0, b1, rnd_key(-6));
|
||||
round(inv_rnd, b1, b0, rnd_key(-5));
|
||||
round(inv_rnd, b0, b1, rnd_key(-4));
|
||||
round(inv_rnd, b1, b0, rnd_key(-3));
|
||||
round(inv_rnd, b0, b1, rnd_key(-2));
|
||||
round(inv_rnd, b1, b0, rnd_key(-1));
|
||||
round(inv_lrnd, b0, b1, rnd_key( 0));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (DEC_UNROLL == PARTIAL)
|
||||
{ uint_32t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd)
|
||||
{
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b0, b1, kp);
|
||||
}
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
#else
|
||||
{ uint_32t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd)
|
||||
{
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
l_copy(b0, b1);
|
||||
}
|
||||
#endif
|
||||
kp = rnd_key(1);
|
||||
round(inv_lrnd, b0, b1, kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
state_out(out, b0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,556 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
#include "aestab.h"
|
||||
|
||||
/*
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
# include "aes_via_ace.h"
|
||||
#endif
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Initialise the key schedule from the user supplied key. The key
|
||||
length can be specified in bytes, with legal values of 16, 24
|
||||
and 32, or in bits, with legal values of 128, 192 and 256. These
|
||||
values correspond with Nk values of 4, 6 and 8 respectively.
|
||||
|
||||
The following macros implement a single cycle in the key
|
||||
schedule generation process. The number of cycles needed
|
||||
for each cx->n_col and nk value is:
|
||||
|
||||
nk = 4 5 6 7 8
|
||||
------------------------------
|
||||
cx->n_col = 4 10 9 8 7 7
|
||||
cx->n_col = 5 14 11 10 9 9
|
||||
cx->n_col = 6 19 15 12 11 11
|
||||
cx->n_col = 7 21 19 16 13 14
|
||||
cx->n_col = 8 29 23 19 17 14
|
||||
*/
|
||||
|
||||
#if defined( REDUCE_CODE_SIZE )
|
||||
# define ls_box ls_sub
|
||||
uint_32t ls_sub(const uint_32t t, const uint_32t n);
|
||||
# define inv_mcol im_sub
|
||||
uint_32t im_sub(const uint_32t x);
|
||||
# ifdef ENC_KS_UNROLL
|
||||
# undef ENC_KS_UNROLL
|
||||
# endif
|
||||
# ifdef DEC_KS_UNROLL
|
||||
# undef DEC_KS_UNROLL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (FUNCS_IN_C & ENC_KEYING_IN_C)
|
||||
|
||||
#if defined(AES_128) || defined( AES_VAR )
|
||||
|
||||
#define ke4(k,i) \
|
||||
{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
|
||||
k[4*(i)+5] = ss[1] ^= ss[0]; \
|
||||
k[4*(i)+6] = ss[2] ^= ss[1]; \
|
||||
k[4*(i)+7] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1])
|
||||
{ uint_32t ss[4];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke4(cx->ks, 0); ke4(cx->ks, 1);
|
||||
ke4(cx->ks, 2); ke4(cx->ks, 3);
|
||||
ke4(cx->ks, 4); ke4(cx->ks, 5);
|
||||
ke4(cx->ks, 6); ke4(cx->ks, 7);
|
||||
ke4(cx->ks, 8);
|
||||
#else
|
||||
{ uint_32t i;
|
||||
for(i = 0; i < 9; ++i)
|
||||
ke4(cx->ks, i);
|
||||
}
|
||||
#endif
|
||||
ke4(cx->ks, 9);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 10 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined( AES_VAR )
|
||||
|
||||
#define kef6(k,i) \
|
||||
{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
|
||||
k[6*(i)+ 7] = ss[1] ^= ss[0]; \
|
||||
k[6*(i)+ 8] = ss[2] ^= ss[1]; \
|
||||
k[6*(i)+ 9] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke6(k,i) \
|
||||
{ kef6(k,i); \
|
||||
k[6*(i)+10] = ss[4] ^= ss[3]; \
|
||||
k[6*(i)+11] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1])
|
||||
{ uint_32t ss[6];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
cx->ks[4] = ss[4] = word_in(key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(key, 5);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke6(cx->ks, 0); ke6(cx->ks, 1);
|
||||
ke6(cx->ks, 2); ke6(cx->ks, 3);
|
||||
ke6(cx->ks, 4); ke6(cx->ks, 5);
|
||||
ke6(cx->ks, 6);
|
||||
#else
|
||||
{ uint_32t i;
|
||||
for(i = 0; i < 7; ++i)
|
||||
ke6(cx->ks, i);
|
||||
}
|
||||
#endif
|
||||
kef6(cx->ks, 7);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 12 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined( AES_VAR )
|
||||
|
||||
#define kef8(k,i) \
|
||||
{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
|
||||
k[8*(i)+ 9] = ss[1] ^= ss[0]; \
|
||||
k[8*(i)+10] = ss[2] ^= ss[1]; \
|
||||
k[8*(i)+11] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke8(k,i) \
|
||||
{ kef8(k,i); \
|
||||
k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \
|
||||
k[8*(i)+13] = ss[5] ^= ss[4]; \
|
||||
k[8*(i)+14] = ss[6] ^= ss[5]; \
|
||||
k[8*(i)+15] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1])
|
||||
{ uint_32t ss[8];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
cx->ks[4] = ss[4] = word_in(key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(key, 5);
|
||||
cx->ks[6] = ss[6] = word_in(key, 6);
|
||||
cx->ks[7] = ss[7] = word_in(key, 7);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke8(cx->ks, 0); ke8(cx->ks, 1);
|
||||
ke8(cx->ks, 2); ke8(cx->ks, 3);
|
||||
ke8(cx->ks, 4); ke8(cx->ks, 5);
|
||||
#else
|
||||
{ uint_32t i;
|
||||
for(i = 0; i < 6; ++i)
|
||||
ke8(cx->ks, i);
|
||||
}
|
||||
#endif
|
||||
kef8(cx->ks, 6);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 14 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( AES_VAR )
|
||||
|
||||
AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1])
|
||||
{
|
||||
switch(key_len)
|
||||
{
|
||||
case 16: case 128: return aes_encrypt_key128(key, cx);
|
||||
case 24: case 192: return aes_encrypt_key192(key, cx);
|
||||
case 32: case 256: return aes_encrypt_key256(key, cx);
|
||||
default: return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if (FUNCS_IN_C & DEC_KEYING_IN_C)
|
||||
|
||||
/* this is used to store the decryption round keys */
|
||||
/* in forward or reverse order */
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
#define v(n,i) ((n) - (i) + 2 * ((i) & 3))
|
||||
#else
|
||||
#define v(n,i) (i)
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES
|
||||
#define ff(x) (x)
|
||||
#else
|
||||
#define ff(x) inv_mcol(x)
|
||||
#if defined( dec_imvars )
|
||||
#define d_vars dec_imvars
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(AES_128) || defined( AES_VAR )
|
||||
|
||||
#define k4e(k,i) \
|
||||
{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
|
||||
k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \
|
||||
k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \
|
||||
k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
#define kdf4(k,i) \
|
||||
{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \
|
||||
ss[1] = ss[1] ^ ss[3]; \
|
||||
ss[2] = ss[2] ^ ss[3]; \
|
||||
ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; \
|
||||
ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \
|
||||
}
|
||||
|
||||
#define kd4(k,i) \
|
||||
{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \
|
||||
k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \
|
||||
k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \
|
||||
k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \
|
||||
k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \
|
||||
}
|
||||
|
||||
#define kdl4(k,i) \
|
||||
{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \
|
||||
k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \
|
||||
k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \
|
||||
k[v(40,(4*(i))+6)] = ss[0]; \
|
||||
k[v(40,(4*(i))+7)] = ss[1]; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define kdf4(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \
|
||||
}
|
||||
|
||||
#define kd4(k,i) \
|
||||
{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \
|
||||
ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \
|
||||
ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \
|
||||
ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \
|
||||
}
|
||||
|
||||
#define kdl4(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1])
|
||||
{ uint_32t ss[5];
|
||||
#if defined( d_vars )
|
||||
d_vars;
|
||||
#endif
|
||||
cx->ks[v(40,(0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(40,(1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(40,(2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(40,(3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
kdf4(cx->ks, 0); kd4(cx->ks, 1);
|
||||
kd4(cx->ks, 2); kd4(cx->ks, 3);
|
||||
kd4(cx->ks, 4); kd4(cx->ks, 5);
|
||||
kd4(cx->ks, 6); kd4(cx->ks, 7);
|
||||
kd4(cx->ks, 8); kdl4(cx->ks, 9);
|
||||
#else
|
||||
{ uint_32t i;
|
||||
for(i = 0; i < 10; ++i)
|
||||
k4e(cx->ks, i);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 10 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 10 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined( AES_VAR )
|
||||
|
||||
#define k6ef(k,i) \
|
||||
{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
|
||||
k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \
|
||||
k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \
|
||||
k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define k6e(k,i) \
|
||||
{ k6ef(k,i); \
|
||||
k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \
|
||||
k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
|
||||
#define kdf6(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \
|
||||
ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \
|
||||
ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \
|
||||
}
|
||||
|
||||
#define kd6(k,i) \
|
||||
{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \
|
||||
ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \
|
||||
ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \
|
||||
ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \
|
||||
ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \
|
||||
ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \
|
||||
}
|
||||
|
||||
#define kdl6(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1])
|
||||
{ uint_32t ss[7];
|
||||
#if defined( d_vars )
|
||||
d_vars;
|
||||
#endif
|
||||
cx->ks[v(48,(0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(48,(1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(48,(2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(48,(3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
ss[4] = word_in(key, 4);
|
||||
cx->ks[v(48,(4))] = ff(ss[4]);
|
||||
ss[5] = word_in(key, 5);
|
||||
cx->ks[v(48,(5))] = ff(ss[5]);
|
||||
kdf6(cx->ks, 0); kd6(cx->ks, 1);
|
||||
kd6(cx->ks, 2); kd6(cx->ks, 3);
|
||||
kd6(cx->ks, 4); kd6(cx->ks, 5);
|
||||
kd6(cx->ks, 6); kdl6(cx->ks, 7);
|
||||
#else
|
||||
cx->ks[v(48,(4))] = ss[4] = word_in(key, 4);
|
||||
cx->ks[v(48,(5))] = ss[5] = word_in(key, 5);
|
||||
{ uint_32t i;
|
||||
|
||||
for(i = 0; i < 7; ++i)
|
||||
k6e(cx->ks, i);
|
||||
k6ef(cx->ks, 7);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 12 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 12 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined( AES_VAR )
|
||||
|
||||
#define k8ef(k,i) \
|
||||
{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
|
||||
k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \
|
||||
k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \
|
||||
k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define k8e(k,i) \
|
||||
{ k8ef(k,i); \
|
||||
k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \
|
||||
k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \
|
||||
k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \
|
||||
k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
|
||||
#define kdf8(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \
|
||||
ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \
|
||||
ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \
|
||||
ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \
|
||||
ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \
|
||||
}
|
||||
|
||||
#define kd8(k,i) \
|
||||
{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \
|
||||
ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \
|
||||
ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \
|
||||
ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \
|
||||
ss[8] = ls_box(ss[3],0); \
|
||||
ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \
|
||||
ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \
|
||||
ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \
|
||||
ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \
|
||||
}
|
||||
|
||||
#define kdl8(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1])
|
||||
{ uint_32t ss[9];
|
||||
#if defined( d_vars )
|
||||
d_vars;
|
||||
#endif
|
||||
cx->ks[v(56,(0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(56,(1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(56,(2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(56,(3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
ss[4] = word_in(key, 4);
|
||||
cx->ks[v(56,(4))] = ff(ss[4]);
|
||||
ss[5] = word_in(key, 5);
|
||||
cx->ks[v(56,(5))] = ff(ss[5]);
|
||||
ss[6] = word_in(key, 6);
|
||||
cx->ks[v(56,(6))] = ff(ss[6]);
|
||||
ss[7] = word_in(key, 7);
|
||||
cx->ks[v(56,(7))] = ff(ss[7]);
|
||||
kdf8(cx->ks, 0); kd8(cx->ks, 1);
|
||||
kd8(cx->ks, 2); kd8(cx->ks, 3);
|
||||
kd8(cx->ks, 4); kd8(cx->ks, 5);
|
||||
kdl8(cx->ks, 6);
|
||||
#else
|
||||
cx->ks[v(56,(4))] = ss[4] = word_in(key, 4);
|
||||
cx->ks[v(56,(5))] = ss[5] = word_in(key, 5);
|
||||
cx->ks[v(56,(6))] = ss[6] = word_in(key, 6);
|
||||
cx->ks[v(56,(7))] = ss[7] = word_in(key, 7);
|
||||
{ uint_32t i;
|
||||
|
||||
for(i = 0; i < 6; ++i)
|
||||
k8e(cx->ks, i);
|
||||
k8ef(cx->ks, 6);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 14 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 14 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( AES_VAR )
|
||||
|
||||
AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1])
|
||||
{
|
||||
switch(key_len)
|
||||
{
|
||||
case 16: case 128: return aes_decrypt_key128(key, cx);
|
||||
case 24: case 192: return aes_decrypt_key192(key, cx);
|
||||
case 32: case 256: return aes_decrypt_key256(key, cx);
|
||||
default: return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,742 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
This file contains the compilation options for AES (Rijndael) and code
|
||||
that is common across encryption, key scheduling and table generation.
|
||||
|
||||
OPERATION
|
||||
|
||||
These source code files implement the AES algorithm Rijndael designed by
|
||||
Joan Daemen and Vincent Rijmen. This version is designed for the standard
|
||||
block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24
|
||||
and 32 bytes).
|
||||
|
||||
This version is designed for flexibility and speed using operations on
|
||||
32-bit words rather than operations on bytes. It can be compiled with
|
||||
either big or little endian internal byte order but is faster when the
|
||||
native byte order for the processor is used.
|
||||
|
||||
THE CIPHER INTERFACE
|
||||
|
||||
The cipher interface is implemented as an array of bytes in which lower
|
||||
AES bit sequence indexes map to higher numeric significance within bytes.
|
||||
|
||||
uint_8t (an unsigned 8-bit type)
|
||||
uint_32t (an unsigned 32-bit type)
|
||||
struct aes_encrypt_ctx (structure for the cipher encryption context)
|
||||
struct aes_decrypt_ctx (structure for the cipher decryption context)
|
||||
AES_RETURN the function return type
|
||||
|
||||
C subroutine calls:
|
||||
|
||||
AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out,
|
||||
const aes_decrypt_ctx cx[1]);
|
||||
|
||||
IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that
|
||||
you call aes_init() before AES is used so that the tables are initialised.
|
||||
|
||||
C++ aes class subroutines:
|
||||
|
||||
Class AESencrypt for encryption
|
||||
|
||||
Construtors:
|
||||
AESencrypt(void)
|
||||
AESencrypt(const unsigned char *key) - 128 bit key
|
||||
Members:
|
||||
AES_RETURN key128(const unsigned char *key)
|
||||
AES_RETURN key192(const unsigned char *key)
|
||||
AES_RETURN key256(const unsigned char *key)
|
||||
AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const
|
||||
|
||||
Class AESdecrypt for encryption
|
||||
Construtors:
|
||||
AESdecrypt(void)
|
||||
AESdecrypt(const unsigned char *key) - 128 bit key
|
||||
Members:
|
||||
AES_RETURN key128(const unsigned char *key)
|
||||
AES_RETURN key192(const unsigned char *key)
|
||||
AES_RETURN key256(const unsigned char *key)
|
||||
AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const
|
||||
*/
|
||||
|
||||
#if !defined( _AESOPT_H )
|
||||
#define _AESOPT_H
|
||||
|
||||
#if defined( __cplusplus )
|
||||
#include "aescpp.h"
|
||||
#else
|
||||
#include "aes.h"
|
||||
#endif
|
||||
|
||||
/* PLATFORM SPECIFIC INCLUDES */
|
||||
|
||||
#include "brg_endian.h"
|
||||
|
||||
/* CONFIGURATION - THE USE OF DEFINES
|
||||
|
||||
Later in this section there are a number of defines that control the
|
||||
operation of the code. In each section, the purpose of each define is
|
||||
explained so that the relevant form can be included or excluded by
|
||||
setting either 1's or 0's respectively on the branches of the related
|
||||
#if clauses. The following local defines should not be changed.
|
||||
*/
|
||||
|
||||
#define ENCRYPTION_IN_C 1
|
||||
#define DECRYPTION_IN_C 2
|
||||
#define ENC_KEYING_IN_C 4
|
||||
#define DEC_KEYING_IN_C 8
|
||||
|
||||
#define NO_TABLES 0
|
||||
#define ONE_TABLE 1
|
||||
#define FOUR_TABLES 4
|
||||
#define NONE 0
|
||||
#define PARTIAL 1
|
||||
#define FULL 2
|
||||
|
||||
/* --- START OF USER CONFIGURED OPTIONS --- */
|
||||
|
||||
/* 1. BYTE ORDER WITHIN 32 BIT WORDS
|
||||
|
||||
The fundamental data processing units in Rijndael are 8-bit bytes. The
|
||||
input, output and key input are all enumerated arrays of bytes in which
|
||||
bytes are numbered starting at zero and increasing to one less than the
|
||||
number of bytes in the array in question. This enumeration is only used
|
||||
for naming bytes and does not imply any adjacency or order relationship
|
||||
from one byte to another. When these inputs and outputs are considered
|
||||
as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to
|
||||
byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte.
|
||||
In this implementation bits are numbered from 0 to 7 starting at the
|
||||
numerically least significant end of each byte (bit n represents 2^n).
|
||||
|
||||
However, Rijndael can be implemented more efficiently using 32-bit
|
||||
words by packing bytes into words so that bytes 4*n to 4*n+3 are placed
|
||||
into word[n]. While in principle these bytes can be assembled into words
|
||||
in any positions, this implementation only supports the two formats in
|
||||
which bytes in adjacent positions within words also have adjacent byte
|
||||
numbers. This order is called big-endian if the lowest numbered bytes
|
||||
in words have the highest numeric significance and little-endian if the
|
||||
opposite applies.
|
||||
|
||||
This code can work in either order irrespective of the order used by the
|
||||
machine on which it runs. Normally the internal byte order will be set
|
||||
to the order of the processor on which the code is to be run but this
|
||||
define can be used to reverse this in special situations
|
||||
|
||||
WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set.
|
||||
This define will hence be redefined later (in section 4) if necessary
|
||||
*/
|
||||
|
||||
#if 1
|
||||
# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
|
||||
#elif 0
|
||||
# define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#elif 0
|
||||
# define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#else
|
||||
# error The algorithm byte order is not defined
|
||||
#endif
|
||||
|
||||
/* 2. VIA ACE SUPPORT */
|
||||
|
||||
#if defined( __GNUC__ ) && defined( __i386__ ) \
|
||||
|| defined( _WIN32 ) && defined( _M_IX86 ) \
|
||||
&& !(defined( _WIN64 ) || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 ))
|
||||
# define VIA_ACE_POSSIBLE
|
||||
#endif
|
||||
|
||||
/* Define this option if support for the VIA ACE is required. This uses
|
||||
inline assembler instructions and is only implemented for the Microsoft,
|
||||
Intel and GCC compilers. If VIA ACE is known to be present, then defining
|
||||
ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption
|
||||
code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if
|
||||
it is detected (both present and enabled) but the normal AES code will
|
||||
also be present.
|
||||
|
||||
When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte
|
||||
aligned; other input/output buffers do not need to be 16 byte aligned
|
||||
but there are very large performance gains if this can be arranged.
|
||||
VIA ACE also requires the decryption key schedule to be in reverse
|
||||
order (which later checks below ensure).
|
||||
*/
|
||||
|
||||
#if 1 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT )
|
||||
# define USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
|
||||
#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# define ASSUME_VIA_ACE_PRESENT
|
||||
# endif
|
||||
|
||||
/* 3. ASSEMBLER SUPPORT
|
||||
|
||||
This define (which can be on the command line) enables the use of the
|
||||
assembler code routines for encryption, decryption and key scheduling
|
||||
as follows:
|
||||
|
||||
ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for
|
||||
encryption, decryption and key scheduling
|
||||
ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
|
||||
Change one 'if 0' below to 'if 1' to select the version or define
|
||||
as a compilation option.
|
||||
*/
|
||||
|
||||
#if 0 && !defined( ASM_X86_V1C )
|
||||
# define ASM_X86_V1C
|
||||
#elif 0 && !defined( ASM_X86_V2 )
|
||||
# define ASM_X86_V2
|
||||
#elif 0 && !defined( ASM_X86_V2C )
|
||||
# define ASM_X86_V2C
|
||||
#elif 0 && !defined( ASM_AMD64_C )
|
||||
# define ASM_AMD64_C
|
||||
#endif
|
||||
|
||||
#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \
|
||||
&& !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 )
|
||||
# error Assembler code is only available for x86 and AMD64 systems
|
||||
#endif
|
||||
|
||||
/* 4. FAST INPUT/OUTPUT OPERATIONS.
|
||||
|
||||
On some machines it is possible to improve speed by transferring the
|
||||
bytes in the input and output arrays to and from the internal 32-bit
|
||||
variables by addressing these arrays as if they are arrays of 32-bit
|
||||
words. On some machines this will always be possible but there may
|
||||
be a large performance penalty if the byte arrays are not aligned on
|
||||
the normal word boundaries. On other machines this technique will
|
||||
lead to memory access errors when such 32-bit word accesses are not
|
||||
properly aligned. The option SAFE_IO avoids such problems but will
|
||||
often be slower on those machines that support misaligned access
|
||||
(especially so if care is taken to align the input and output byte
|
||||
arrays on 32-bit word boundaries). If SAFE_IO is not defined it is
|
||||
assumed that access to byte arrays as if they are arrays of 32-bit
|
||||
words will not cause problems when such accesses are misaligned.
|
||||
*/
|
||||
#if 1 && !defined( _MSC_VER )
|
||||
# define SAFE_IO
|
||||
#endif
|
||||
|
||||
/* 5. LOOP UNROLLING
|
||||
|
||||
The code for encryption and decrytpion cycles through a number of rounds
|
||||
that can be implemented either in a loop or by expanding the code into a
|
||||
long sequence of instructions, the latter producing a larger program but
|
||||
one that will often be much faster. The latter is called loop unrolling.
|
||||
There are also potential speed advantages in expanding two iterations in
|
||||
a loop with half the number of iterations, which is called partial loop
|
||||
unrolling. The following options allow partial or full loop unrolling
|
||||
to be set independently for encryption and decryption
|
||||
*/
|
||||
#if 1
|
||||
# define ENC_UNROLL FULL
|
||||
#elif 0
|
||||
# define ENC_UNROLL PARTIAL
|
||||
#else
|
||||
# define ENC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
# define DEC_UNROLL FULL
|
||||
#elif 0
|
||||
# define DEC_UNROLL PARTIAL
|
||||
#else
|
||||
# define DEC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
# define ENC_KS_UNROLL
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
# define DEC_KS_UNROLL
|
||||
#endif
|
||||
|
||||
/* 6. FAST FINITE FIELD OPERATIONS
|
||||
|
||||
If this section is included, tables are used to provide faster finite
|
||||
field arithmetic (this has no effect if FIXED_TABLES is defined).
|
||||
*/
|
||||
#if 1
|
||||
# define FF_TABLES
|
||||
#endif
|
||||
|
||||
/* 7. INTERNAL STATE VARIABLE FORMAT
|
||||
|
||||
The internal state of Rijndael is stored in a number of local 32-bit
|
||||
word varaibles which can be defined either as an array or as individual
|
||||
names variables. Include this section if you want to store these local
|
||||
varaibles in arrays. Otherwise individual local variables will be used.
|
||||
*/
|
||||
#if 1
|
||||
# define ARRAYS
|
||||
#endif
|
||||
|
||||
/* 8. FIXED OR DYNAMIC TABLES
|
||||
|
||||
When this section is included the tables used by the code are compiled
|
||||
statically into the binary file. Otherwise the subroutine aes_init()
|
||||
must be called to compute them before the code is first used.
|
||||
*/
|
||||
#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 ))
|
||||
# define FIXED_TABLES
|
||||
#endif
|
||||
|
||||
/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES
|
||||
|
||||
In some systems it is better to mask longer values to extract bytes
|
||||
rather than using a cast. This option allows this choice.
|
||||
*/
|
||||
#if 0
|
||||
# define to_byte(x) ((uint_8t)(x))
|
||||
#else
|
||||
# define to_byte(x) ((x) & 0xff)
|
||||
#endif
|
||||
|
||||
/* 10. TABLE ALIGNMENT
|
||||
|
||||
On some sytsems speed will be improved by aligning the AES large lookup
|
||||
tables on particular boundaries. This define should be set to a power of
|
||||
two giving the desired alignment. It can be left undefined if alignment
|
||||
is not needed. This option is specific to the Microsft VC++ compiler -
|
||||
it seems to sometimes cause trouble for the VC++ version 6 compiler.
|
||||
*/
|
||||
|
||||
#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
|
||||
# define TABLE_ALIGN 32
|
||||
#endif
|
||||
|
||||
/* 11. REDUCE CODE AND TABLE SIZE
|
||||
|
||||
This replaces some expanded macros with function calls if AES_ASM_V2 or
|
||||
AES_ASM_V2C are defined
|
||||
*/
|
||||
|
||||
#if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))
|
||||
# define REDUCE_CODE_SIZE
|
||||
#endif
|
||||
|
||||
/* 12. TABLE OPTIONS
|
||||
|
||||
This cipher proceeds by repeating in a number of cycles known as 'rounds'
|
||||
which are implemented by a round function which can optionally be speeded
|
||||
up using tables. The basic tables are each 256 32-bit words, with either
|
||||
one or four tables being required for each round function depending on
|
||||
how much speed is required. The encryption and decryption round functions
|
||||
are different and the last encryption and decrytpion round functions are
|
||||
different again making four different round functions in all.
|
||||
|
||||
This means that:
|
||||
1. Normal encryption and decryption rounds can each use either 0, 1
|
||||
or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
|
||||
2. The last encryption and decryption rounds can also use either 0, 1
|
||||
or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
|
||||
|
||||
Include or exclude the appropriate definitions below to set the number
|
||||
of tables used by this implementation.
|
||||
*/
|
||||
|
||||
#if 1 /* set tables for the normal encryption round */
|
||||
# define ENC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
# define ENC_ROUND ONE_TABLE
|
||||
#else
|
||||
# define ENC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the last encryption round */
|
||||
# define LAST_ENC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
# define LAST_ENC_ROUND ONE_TABLE
|
||||
#else
|
||||
# define LAST_ENC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the normal decryption round */
|
||||
# define DEC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
# define DEC_ROUND ONE_TABLE
|
||||
#else
|
||||
# define DEC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the last decryption round */
|
||||
# define LAST_DEC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
# define LAST_DEC_ROUND ONE_TABLE
|
||||
#else
|
||||
# define LAST_DEC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
/* The decryption key schedule can be speeded up with tables in the same
|
||||
way that the round functions can. Include or exclude the following
|
||||
defines to set this requirement.
|
||||
*/
|
||||
#if 1
|
||||
# define KEY_SCHED FOUR_TABLES
|
||||
#elif 0
|
||||
# define KEY_SCHED ONE_TABLE
|
||||
#else
|
||||
# define KEY_SCHED NO_TABLES
|
||||
#endif
|
||||
|
||||
/* ---- END OF USER CONFIGURED OPTIONS ---- */
|
||||
|
||||
/* VIA ACE support is only available for VC++ and GCC */
|
||||
|
||||
#if !defined( _MSC_VER ) && !defined( __GNUC__ )
|
||||
# if defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# undef ASSUME_VIA_ACE_PRESENT
|
||||
# endif
|
||||
# if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
# undef USE_VIA_ACE_IF_PRESENT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT )
|
||||
# define USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS )
|
||||
# define AES_REV_DKS
|
||||
#endif
|
||||
|
||||
/* ********** UNDEF - we don't use VIA stuff ****************** */
|
||||
#undef USE_VIA_ACE_IF_PRESENT
|
||||
|
||||
/* Assembler support requires the use of platform byte order */
|
||||
|
||||
#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \
|
||||
&& (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER)
|
||||
# undef ALGORITHM_BYTE_ORDER
|
||||
# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
|
||||
#endif
|
||||
|
||||
/* In this implementation the columns of the state array are each held in
|
||||
32-bit words. The state array can be held in various ways: in an array
|
||||
of words, in a number of individual word variables or in a number of
|
||||
processor registers. The following define maps a variable name x and
|
||||
a column number c to the way the state array variable is to be held.
|
||||
The first define below maps the state into an array x[c] whereas the
|
||||
second form maps the state into a number of individual variables x0,
|
||||
x1, etc. Another form could map individual state colums to machine
|
||||
register names.
|
||||
*/
|
||||
|
||||
#if defined( ARRAYS )
|
||||
# define s(x,c) x[c]
|
||||
#else
|
||||
# define s(x,c) x##c
|
||||
#endif
|
||||
|
||||
/* This implementation provides subroutines for encryption, decryption
|
||||
and for setting the three key lengths (separately) for encryption
|
||||
and decryption. Since not all functions are needed, masks are set
|
||||
up here to determine which will be implemented in C
|
||||
*/
|
||||
|
||||
#if !defined( AES_ENCRYPT )
|
||||
# define EFUNCS_IN_C 0
|
||||
#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \
|
||||
|| defined( ASM_X86_V2C ) || defined( ASM_AMD64_C )
|
||||
# define EFUNCS_IN_C ENC_KEYING_IN_C
|
||||
#elif !defined( ASM_X86_V2 )
|
||||
# define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C )
|
||||
#else
|
||||
# define EFUNCS_IN_C 0
|
||||
#endif
|
||||
|
||||
#if !defined( AES_DECRYPT )
|
||||
# define DFUNCS_IN_C 0
|
||||
#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \
|
||||
|| defined( ASM_X86_V2C ) || defined( ASM_AMD64_C )
|
||||
# define DFUNCS_IN_C DEC_KEYING_IN_C
|
||||
#elif !defined( ASM_X86_V2 )
|
||||
# define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C )
|
||||
#else
|
||||
# define DFUNCS_IN_C 0
|
||||
#endif
|
||||
|
||||
#define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C )
|
||||
|
||||
/* END OF CONFIGURATION OPTIONS */
|
||||
|
||||
#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2))
|
||||
|
||||
/* Disable or report errors on some combinations of options */
|
||||
|
||||
#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES
|
||||
# undef LAST_ENC_ROUND
|
||||
# define LAST_ENC_ROUND NO_TABLES
|
||||
#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES
|
||||
# undef LAST_ENC_ROUND
|
||||
# define LAST_ENC_ROUND ONE_TABLE
|
||||
#endif
|
||||
|
||||
#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE
|
||||
# undef ENC_UNROLL
|
||||
# define ENC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES
|
||||
# undef LAST_DEC_ROUND
|
||||
# define LAST_DEC_ROUND NO_TABLES
|
||||
#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES
|
||||
# undef LAST_DEC_ROUND
|
||||
# define LAST_DEC_ROUND ONE_TABLE
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE
|
||||
# undef DEC_UNROLL
|
||||
# define DEC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if defined( bswap32 )
|
||||
# define aes_sw32 bswap32
|
||||
#elif defined( bswap_32 )
|
||||
# define aes_sw32 bswap_32
|
||||
#else
|
||||
# define brot(x,n) (((uint_32t)(x) << n) | ((uint_32t)(x) >> (32 - n)))
|
||||
# define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00))
|
||||
#endif
|
||||
|
||||
/* upr(x,n): rotates bytes within words by n positions, moving bytes to
|
||||
higher index positions with wrap around into low positions
|
||||
ups(x,n): moves bytes by n positions to higher index positions in
|
||||
words but without wrap around
|
||||
bval(x,n): extracts a byte from a word
|
||||
|
||||
WARNING: The definitions given here are intended only for use with
|
||||
unsigned variables and with shift counts that are compile
|
||||
time constants
|
||||
*/
|
||||
|
||||
#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN )
|
||||
# define upr(x,n) (((uint_32t)(x) << (8 * (n))) | ((uint_32t)(x) >> (32 - 8 * (n))))
|
||||
# define ups(x,n) ((uint_32t) (x) << (8 * (n)))
|
||||
# define bval(x,n) to_byte((x) >> (8 * (n)))
|
||||
# define bytes2word(b0, b1, b2, b3) \
|
||||
(((uint_32t)(b3) << 24) | ((uint_32t)(b2) << 16) | ((uint_32t)(b1) << 8) | (b0))
|
||||
#endif
|
||||
|
||||
#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN )
|
||||
# define upr(x,n) (((uint_32t)(x) >> (8 * (n))) | ((uint_32t)(x) << (32 - 8 * (n))))
|
||||
# define ups(x,n) ((uint_32t) (x) >> (8 * (n)))
|
||||
# define bval(x,n) to_byte((x) >> (24 - 8 * (n)))
|
||||
# define bytes2word(b0, b1, b2, b3) \
|
||||
(((uint_32t)(b0) << 24) | ((uint_32t)(b1) << 16) | ((uint_32t)(b2) << 8) | (b3))
|
||||
#endif
|
||||
|
||||
#if defined( SAFE_IO )
|
||||
# define word_in(x,c) bytes2word(((const uint_8t*)(x)+4*c)[0], ((const uint_8t*)(x)+4*c)[1], \
|
||||
((const uint_8t*)(x)+4*c)[2], ((const uint_8t*)(x)+4*c)[3])
|
||||
# define word_out(x,c,v) { ((uint_8t*)(x)+4*c)[0] = bval(v,0); ((uint_8t*)(x)+4*c)[1] = bval(v,1); \
|
||||
((uint_8t*)(x)+4*c)[2] = bval(v,2); ((uint_8t*)(x)+4*c)[3] = bval(v,3); }
|
||||
#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER )
|
||||
# define word_in(x,c) (*((uint_32t*)(x)+(c)))
|
||||
# define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = (v))
|
||||
#else
|
||||
# define word_in(x,c) aes_sw32(*((uint_32t*)(x)+(c)))
|
||||
# define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = aes_sw32(v))
|
||||
#endif
|
||||
|
||||
/* the finite field modular polynomial and elements */
|
||||
|
||||
#define WPOLY 0x011b
|
||||
#define BPOLY 0x1b
|
||||
|
||||
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
|
||||
|
||||
#define gf_c1 0x80808080
|
||||
#define gf_c2 0x7f7f7f7f
|
||||
#define gf_mulx(x) ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY))
|
||||
|
||||
/* The following defines provide alternative definitions of gf_mulx that might
|
||||
give improved performance if a fast 32-bit multiply is not available. Note
|
||||
that a temporary variable u needs to be defined where gf_mulx is used.
|
||||
|
||||
#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6))
|
||||
#define gf_c4 (0x01010101 * BPOLY)
|
||||
#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4)
|
||||
*/
|
||||
|
||||
/* Work out which tables are needed for the different options */
|
||||
|
||||
#if defined( ASM_X86_V1C )
|
||||
# if defined( ENC_ROUND )
|
||||
# undef ENC_ROUND
|
||||
# endif
|
||||
# define ENC_ROUND FOUR_TABLES
|
||||
# if defined( LAST_ENC_ROUND )
|
||||
# undef LAST_ENC_ROUND
|
||||
# endif
|
||||
# define LAST_ENC_ROUND FOUR_TABLES
|
||||
# if defined( DEC_ROUND )
|
||||
# undef DEC_ROUND
|
||||
# endif
|
||||
# define DEC_ROUND FOUR_TABLES
|
||||
# if defined( LAST_DEC_ROUND )
|
||||
# undef LAST_DEC_ROUND
|
||||
# endif
|
||||
# define LAST_DEC_ROUND FOUR_TABLES
|
||||
# if defined( KEY_SCHED )
|
||||
# undef KEY_SCHED
|
||||
# define KEY_SCHED FOUR_TABLES
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C )
|
||||
# if ENC_ROUND == ONE_TABLE
|
||||
# define FT1_SET
|
||||
# elif ENC_ROUND == FOUR_TABLES
|
||||
# define FT4_SET
|
||||
# else
|
||||
# define SBX_SET
|
||||
# endif
|
||||
# if LAST_ENC_ROUND == ONE_TABLE
|
||||
# define FL1_SET
|
||||
# elif LAST_ENC_ROUND == FOUR_TABLES
|
||||
# define FL4_SET
|
||||
# elif !defined( SBX_SET )
|
||||
# define SBX_SET
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C )
|
||||
# if DEC_ROUND == ONE_TABLE
|
||||
# define IT1_SET
|
||||
# elif DEC_ROUND == FOUR_TABLES
|
||||
# define IT4_SET
|
||||
# else
|
||||
# define ISB_SET
|
||||
# endif
|
||||
# if LAST_DEC_ROUND == ONE_TABLE
|
||||
# define IL1_SET
|
||||
# elif LAST_DEC_ROUND == FOUR_TABLES
|
||||
# define IL4_SET
|
||||
# elif !defined(ISB_SET)
|
||||
# define ISB_SET
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )))
|
||||
# if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C))
|
||||
# if KEY_SCHED == ONE_TABLE
|
||||
# if !defined( FL1_SET ) && !defined( FL4_SET )
|
||||
# define LS1_SET
|
||||
# endif
|
||||
# elif KEY_SCHED == FOUR_TABLES
|
||||
# if !defined( FL4_SET )
|
||||
# define LS4_SET
|
||||
# endif
|
||||
# elif !defined( SBX_SET )
|
||||
# define SBX_SET
|
||||
# endif
|
||||
# endif
|
||||
# if (FUNCS_IN_C & DEC_KEYING_IN_C)
|
||||
# if KEY_SCHED == ONE_TABLE
|
||||
# define IM1_SET
|
||||
# elif KEY_SCHED == FOUR_TABLES
|
||||
# define IM4_SET
|
||||
# elif !defined( SBX_SET )
|
||||
# define SBX_SET
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* generic definitions of Rijndael macros that use tables */
|
||||
|
||||
#define no_table(x,box,vf,rf,c) bytes2word( \
|
||||
box[bval(vf(x,0,c),rf(0,c))], \
|
||||
box[bval(vf(x,1,c),rf(1,c))], \
|
||||
box[bval(vf(x,2,c),rf(2,c))], \
|
||||
box[bval(vf(x,3,c),rf(3,c))])
|
||||
|
||||
#define one_table(x,op,tab,vf,rf,c) \
|
||||
( tab[bval(vf(x,0,c),rf(0,c))] \
|
||||
^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
|
||||
^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
|
||||
^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
|
||||
|
||||
#define four_tables(x,tab,vf,rf,c) \
|
||||
( tab[0][bval(vf(x,0,c),rf(0,c))] \
|
||||
^ tab[1][bval(vf(x,1,c),rf(1,c))] \
|
||||
^ tab[2][bval(vf(x,2,c),rf(2,c))] \
|
||||
^ tab[3][bval(vf(x,3,c),rf(3,c))])
|
||||
|
||||
#define vf1(x,r,c) (x)
|
||||
#define rf1(r,c) (r)
|
||||
#define rf2(r,c) ((8+r-c)&3)
|
||||
|
||||
/* perform forward and inverse column mix operation on four bytes in long word x in */
|
||||
/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */
|
||||
|
||||
#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )))
|
||||
|
||||
#if defined( FM4_SET ) /* not currently used */
|
||||
# define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0)
|
||||
#elif defined( FM1_SET ) /* not currently used */
|
||||
# define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0)
|
||||
#else
|
||||
# define dec_fmvars uint_32t g2
|
||||
# define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1))
|
||||
#endif
|
||||
|
||||
#if defined( IM4_SET )
|
||||
# define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0)
|
||||
#elif defined( IM1_SET )
|
||||
# define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0)
|
||||
#else
|
||||
# define dec_imvars uint_32t g2, g4, g9
|
||||
# define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \
|
||||
(x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1))
|
||||
#endif
|
||||
|
||||
#if defined( FL4_SET )
|
||||
# define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c)
|
||||
#elif defined( LS4_SET )
|
||||
# define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c)
|
||||
#elif defined( FL1_SET )
|
||||
# define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c)
|
||||
#elif defined( LS1_SET )
|
||||
# define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c)
|
||||
#else
|
||||
# define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET )
|
||||
# define ISB_SET
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#define DO_TABLES
|
||||
|
||||
#include "aes.h"
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined(FIXED_TABLES)
|
||||
|
||||
#define sb_data(w) {\
|
||||
w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
|
||||
w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
|
||||
w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
|
||||
w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
|
||||
w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
|
||||
w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
|
||||
w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
|
||||
w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
|
||||
w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
|
||||
w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
|
||||
w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
|
||||
w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
|
||||
w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
|
||||
w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
|
||||
w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
|
||||
w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
|
||||
w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
|
||||
w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
|
||||
w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
|
||||
w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
|
||||
w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
|
||||
w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
|
||||
w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
|
||||
w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
|
||||
w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
|
||||
w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
|
||||
w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
|
||||
w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
|
||||
w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
|
||||
w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
|
||||
w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
|
||||
w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
|
||||
|
||||
#define isb_data(w) {\
|
||||
w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
|
||||
w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
|
||||
w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
|
||||
w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
|
||||
w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
|
||||
w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
|
||||
w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
|
||||
w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
|
||||
w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
|
||||
w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
|
||||
w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
|
||||
w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
|
||||
w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
|
||||
w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
|
||||
w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
|
||||
w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
|
||||
w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
|
||||
w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
|
||||
w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
|
||||
w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
|
||||
w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
|
||||
w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
|
||||
w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
|
||||
w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
|
||||
w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
|
||||
w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
|
||||
w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
|
||||
w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
|
||||
w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
|
||||
w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
|
||||
w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
|
||||
w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) }
|
||||
|
||||
#define mm_data(w) {\
|
||||
w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
|
||||
w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
|
||||
w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
|
||||
w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
|
||||
w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
|
||||
w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
|
||||
w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
|
||||
w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
|
||||
w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
|
||||
w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
|
||||
w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
|
||||
w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
|
||||
w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
|
||||
w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
|
||||
w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
|
||||
w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
|
||||
w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
|
||||
w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
|
||||
w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
|
||||
w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
|
||||
w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
|
||||
w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
|
||||
w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
|
||||
w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
|
||||
w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
|
||||
w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
|
||||
w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
|
||||
w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
|
||||
w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
|
||||
w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
|
||||
w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
|
||||
w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) }
|
||||
|
||||
#define rc_data(w) {\
|
||||
w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
|
||||
w(0x1b), w(0x36) }
|
||||
|
||||
#define h0(x) (x)
|
||||
|
||||
#define w0(p) bytes2word(p, 0, 0, 0)
|
||||
#define w1(p) bytes2word(0, p, 0, 0)
|
||||
#define w2(p) bytes2word(0, 0, p, 0)
|
||||
#define w3(p) bytes2word(0, 0, 0, p)
|
||||
|
||||
#define u0(p) bytes2word(f2(p), p, p, f3(p))
|
||||
#define u1(p) bytes2word(f3(p), f2(p), p, p)
|
||||
#define u2(p) bytes2word(p, f3(p), f2(p), p)
|
||||
#define u3(p) bytes2word(p, p, f3(p), f2(p))
|
||||
|
||||
#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p))
|
||||
#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p))
|
||||
#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p))
|
||||
#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p))
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(FIXED_TABLES) || !defined(FF_TABLES)
|
||||
|
||||
#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY))
|
||||
#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
|
||||
#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \
|
||||
^ (((x>>5) & 4) * WPOLY))
|
||||
#define f3(x) (f2(x) ^ x)
|
||||
#define f9(x) (f8(x) ^ x)
|
||||
#define fb(x) (f8(x) ^ f2(x) ^ x)
|
||||
#define fd(x) (f8(x) ^ f4(x) ^ x)
|
||||
#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
|
||||
|
||||
#else
|
||||
|
||||
#define f2(x) ((x) ? pow[log[x] + 0x19] : 0)
|
||||
#define f3(x) ((x) ? pow[log[x] + 0x01] : 0)
|
||||
#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0)
|
||||
#define fb(x) ((x) ? pow[log[x] + 0x68] : 0)
|
||||
#define fd(x) ((x) ? pow[log[x] + 0xee] : 0)
|
||||
#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0)
|
||||
|
||||
#endif
|
||||
|
||||
#include "aestab.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined(FIXED_TABLES)
|
||||
|
||||
/* implemented in case of wrong call for fixed tables */
|
||||
|
||||
AES_RETURN ks_aes_init(void)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#else /* Generate the tables for the dynamic table option */
|
||||
|
||||
#if defined(FF_TABLES)
|
||||
|
||||
#define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0)
|
||||
|
||||
#else
|
||||
|
||||
/* It will generally be sensible to use tables to compute finite
|
||||
field multiplies and inverses but where memory is scarse this
|
||||
code might sometimes be better. But it only has effect during
|
||||
initialisation so its pretty unimportant in overall terms.
|
||||
*/
|
||||
|
||||
/* return 2 ^ (n - 1) where n is the bit number of the highest bit
|
||||
set in x with x in the range 1 < x < 0x00000200. This form is
|
||||
used so that locals within fi can be bytes rather than words
|
||||
*/
|
||||
|
||||
static uint_8t hibit(const uint_32t x)
|
||||
{ uint_8t r = (uint_8t)((x >> 1) | (x >> 2));
|
||||
|
||||
r |= (r >> 2);
|
||||
r |= (r >> 4);
|
||||
return (r + 1) >> 1;
|
||||
}
|
||||
|
||||
/* return the inverse of the finite field element x */
|
||||
|
||||
static uint_8t gf_inv(const uint_8t x)
|
||||
{ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
|
||||
|
||||
if(x < 2)
|
||||
return x;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
if(n1)
|
||||
while(n2 >= n1) /* divide polynomial p2 by p1 */
|
||||
{
|
||||
n2 /= n1; /* shift smaller polynomial left */
|
||||
p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
|
||||
v2 ^= v1 * n2; /* shift accumulated value and */
|
||||
n2 = hibit(p2); /* add into result */
|
||||
}
|
||||
else
|
||||
return v1;
|
||||
|
||||
if(n2) /* repeat with values swapped */
|
||||
while(n1 >= n2)
|
||||
{
|
||||
n1 /= n2;
|
||||
p1 ^= p2 * n1;
|
||||
v1 ^= v2 * n1;
|
||||
n1 = hibit(p1);
|
||||
}
|
||||
else
|
||||
return v2;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* The forward and inverse affine transformations used in the S-box */
|
||||
uint_8t fwd_affine(const uint_8t x)
|
||||
{ uint_32t w = x;
|
||||
w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
|
||||
return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
|
||||
}
|
||||
|
||||
uint_8t inv_affine(const uint_8t x)
|
||||
{ uint_32t w = x;
|
||||
w = (w << 1) ^ (w << 3) ^ (w << 6);
|
||||
return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
|
||||
}
|
||||
|
||||
static int init = 0;
|
||||
|
||||
AES_RETURN ks_aes_init(void)
|
||||
{ uint_32t i, w;
|
||||
|
||||
#if defined(FF_TABLES)
|
||||
|
||||
uint_8t pow[512], log[256];
|
||||
|
||||
if(init)
|
||||
return EXIT_SUCCESS;
|
||||
/* log and power tables for GF(2^8) finite field with
|
||||
WPOLY as modular polynomial - the simplest primitive
|
||||
root is 0x03, used here to generate the tables
|
||||
*/
|
||||
|
||||
i = 0; w = 1;
|
||||
do
|
||||
{
|
||||
pow[i] = (uint_8t)w;
|
||||
pow[i + 255] = (uint_8t)w;
|
||||
log[w] = (uint_8t)i++;
|
||||
w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0);
|
||||
}
|
||||
while (w != 1);
|
||||
|
||||
#else
|
||||
if(init)
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
|
||||
for(i = 0, w = 1; i < RC_LENGTH; ++i)
|
||||
{
|
||||
t_set(r,c)[i] = bytes2word(w, 0, 0, 0);
|
||||
w = f2(w);
|
||||
}
|
||||
|
||||
for(i = 0; i < 256; ++i)
|
||||
{ uint_8t b;
|
||||
|
||||
b = fwd_affine(gf_inv((uint_8t)i));
|
||||
w = bytes2word(f2(b), b, b, f3(b));
|
||||
|
||||
#if defined( SBX_SET )
|
||||
t_set(s,box)[i] = b;
|
||||
#endif
|
||||
|
||||
#if defined( FT1_SET ) /* tables for a normal encryption round */
|
||||
t_set(f,n)[i] = w;
|
||||
#endif
|
||||
#if defined( FT4_SET )
|
||||
t_set(f,n)[0][i] = w;
|
||||
t_set(f,n)[1][i] = upr(w,1);
|
||||
t_set(f,n)[2][i] = upr(w,2);
|
||||
t_set(f,n)[3][i] = upr(w,3);
|
||||
#endif
|
||||
w = bytes2word(b, 0, 0, 0);
|
||||
|
||||
#if defined( FL1_SET ) /* tables for last encryption round (may also */
|
||||
t_set(f,l)[i] = w; /* be used in the key schedule) */
|
||||
#endif
|
||||
#if defined( FL4_SET )
|
||||
t_set(f,l)[0][i] = w;
|
||||
t_set(f,l)[1][i] = upr(w,1);
|
||||
t_set(f,l)[2][i] = upr(w,2);
|
||||
t_set(f,l)[3][i] = upr(w,3);
|
||||
#endif
|
||||
|
||||
#if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/
|
||||
t_set(l,s)[i] = w; /* not of the required form */
|
||||
#endif
|
||||
#if defined( LS4_SET )
|
||||
t_set(l,s)[0][i] = w;
|
||||
t_set(l,s)[1][i] = upr(w,1);
|
||||
t_set(l,s)[2][i] = upr(w,2);
|
||||
t_set(l,s)[3][i] = upr(w,3);
|
||||
#endif
|
||||
|
||||
b = gf_inv(inv_affine((uint_8t)i));
|
||||
w = bytes2word(fe(b), f9(b), fd(b), fb(b));
|
||||
|
||||
#if defined( IM1_SET ) /* tables for the inverse mix column operation */
|
||||
t_set(i,m)[b] = w;
|
||||
#endif
|
||||
#if defined( IM4_SET )
|
||||
t_set(i,m)[0][b] = w;
|
||||
t_set(i,m)[1][b] = upr(w,1);
|
||||
t_set(i,m)[2][b] = upr(w,2);
|
||||
t_set(i,m)[3][b] = upr(w,3);
|
||||
#endif
|
||||
|
||||
#if defined( ISB_SET )
|
||||
t_set(i,box)[i] = b;
|
||||
#endif
|
||||
#if defined( IT1_SET ) /* tables for a normal decryption round */
|
||||
t_set(i,n)[i] = w;
|
||||
#endif
|
||||
#if defined( IT4_SET )
|
||||
t_set(i,n)[0][i] = w;
|
||||
t_set(i,n)[1][i] = upr(w,1);
|
||||
t_set(i,n)[2][i] = upr(w,2);
|
||||
t_set(i,n)[3][i] = upr(w,3);
|
||||
#endif
|
||||
w = bytes2word(b, 0, 0, 0);
|
||||
#if defined( IL1_SET ) /* tables for last decryption round */
|
||||
t_set(i,l)[i] = w;
|
||||
#endif
|
||||
#if defined( IL4_SET )
|
||||
t_set(i,l)[0][i] = w;
|
||||
t_set(i,l)[1][i] = upr(w,1);
|
||||
t_set(i,l)[2][i] = upr(w,2);
|
||||
t_set(i,l)[3][i] = upr(w,3);
|
||||
#endif
|
||||
}
|
||||
init = 1;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
This file contains the code for declaring the tables needed to implement
|
||||
AES. The file aesopt.h is assumed to be included before this header file.
|
||||
If there are no global variables, the definitions here can be used to put
|
||||
the AES tables in a structure so that a pointer can then be added to the
|
||||
AES context to pass them to the AES routines that need them. If this
|
||||
facility is used, the calling program has to ensure that this pointer is
|
||||
managed appropriately. In particular, the value of the t_dec(in,it) item
|
||||
in the table structure must be set to zero in order to ensure that the
|
||||
tables are initialised. In practice the three code sequences in aeskey.c
|
||||
that control the calls to aes_init() and the aes_init() routine itself will
|
||||
have to be changed for a specific implementation. If global variables are
|
||||
available it will generally be preferable to use them with the precomputed
|
||||
FIXED_TABLES option that uses static global tables.
|
||||
|
||||
The following defines can be used to control the way the tables
|
||||
are defined, initialised and used in embedded environments that
|
||||
require special features for these purposes
|
||||
|
||||
the 't_dec' construction is used to declare fixed table arrays
|
||||
the 't_set' construction is used to set fixed table values
|
||||
the 't_use' construction is used to access fixed table values
|
||||
|
||||
256 byte tables:
|
||||
|
||||
t_xxx(s,box) => forward S box
|
||||
t_xxx(i,box) => inverse S box
|
||||
|
||||
256 32-bit word OR 4 x 256 32-bit word tables:
|
||||
|
||||
t_xxx(f,n) => forward normal round
|
||||
t_xxx(f,l) => forward last round
|
||||
t_xxx(i,n) => inverse normal round
|
||||
t_xxx(i,l) => inverse last round
|
||||
t_xxx(l,s) => key schedule table
|
||||
t_xxx(i,m) => key schedule table
|
||||
|
||||
Other variables and tables:
|
||||
|
||||
t_xxx(r,c) => the rcon table
|
||||
*/
|
||||
|
||||
#if !defined( _AESTAB_H )
|
||||
#define _AESTAB_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define t_dec(m,n) t_##m##n
|
||||
#define t_set(m,n) t_##m##n
|
||||
#define t_use(m,n) t_##m##n
|
||||
|
||||
#if defined(FIXED_TABLES)
|
||||
# if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ ))
|
||||
/* make tables far data to avoid using too much DGROUP space (PG) */
|
||||
# define CONST const far
|
||||
# else
|
||||
# define CONST const
|
||||
# endif
|
||||
#else
|
||||
# define CONST
|
||||
#endif
|
||||
|
||||
#if defined(DO_TABLES)
|
||||
# define EXTERN
|
||||
#else
|
||||
# define EXTERN extern
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && defined(TABLE_ALIGN)
|
||||
#define ALIGN __declspec(align(TABLE_ALIGN))
|
||||
#else
|
||||
#define ALIGN
|
||||
#endif
|
||||
|
||||
#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 )
|
||||
# define XP_DIR __cdecl
|
||||
#else
|
||||
# define XP_DIR
|
||||
#endif
|
||||
|
||||
#if defined(DO_TABLES) && defined(FIXED_TABLES)
|
||||
#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e)
|
||||
#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) }
|
||||
EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0);
|
||||
#else
|
||||
#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256]
|
||||
#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256]
|
||||
EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH];
|
||||
#endif
|
||||
|
||||
#if defined( SBX_SET )
|
||||
d_1(uint_8t, t_dec(s,box), sb_data, h0);
|
||||
#endif
|
||||
#if defined( ISB_SET )
|
||||
d_1(uint_8t, t_dec(i,box), isb_data, h0);
|
||||
#endif
|
||||
|
||||
#if defined( FT1_SET )
|
||||
d_1(uint_32t, t_dec(f,n), sb_data, u0);
|
||||
#endif
|
||||
#if defined( FT4_SET )
|
||||
d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3);
|
||||
#endif
|
||||
|
||||
#if defined( FL1_SET )
|
||||
d_1(uint_32t, t_dec(f,l), sb_data, w0);
|
||||
#endif
|
||||
#if defined( FL4_SET )
|
||||
d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
|
||||
#if defined( IT1_SET )
|
||||
d_1(uint_32t, t_dec(i,n), isb_data, v0);
|
||||
#endif
|
||||
#if defined( IT4_SET )
|
||||
d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3);
|
||||
#endif
|
||||
|
||||
#if defined( IL1_SET )
|
||||
d_1(uint_32t, t_dec(i,l), isb_data, w0);
|
||||
#endif
|
||||
#if defined( IL4_SET )
|
||||
d_4(uint_32t, t_dec(i,l), isb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
|
||||
#if defined( LS1_SET )
|
||||
#if defined( FL1_SET )
|
||||
#undef LS1_SET
|
||||
#else
|
||||
d_1(uint_32t, t_dec(l,s), sb_data, w0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined( LS4_SET )
|
||||
#if defined( FL4_SET )
|
||||
#undef LS4_SET
|
||||
#else
|
||||
d_4(uint_32t, t_dec(l,s), sb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined( IM1_SET )
|
||||
d_1(uint_32t, t_dec(i,m), mm_data, v0);
|
||||
#endif
|
||||
#if defined( IM4_SET )
|
||||
d_4(uint_32t, t_dec(i,m), mm_data, v0, v1, v2, v3);
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#ifndef _BRG_ENDIAN_H
|
||||
#define _BRG_ENDIAN_H
|
||||
|
||||
#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */
|
||||
#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */
|
||||
|
||||
/* Include files where endian defines and byteswap functions may reside */
|
||||
#if defined( __sun )
|
||||
# include <sys/isa_defs.h>
|
||||
#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ )
|
||||
# include <sys/endian.h>
|
||||
#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \
|
||||
defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ )
|
||||
# include <machine/endian.h>
|
||||
#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
|
||||
# if !defined( __MINGW32__ ) && !defined( _AIX )
|
||||
# include <endian.h>
|
||||
# if !defined( __BEOS__ )
|
||||
# include <byteswap.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Now attempt to set the define for platform byte order using any */
|
||||
/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */
|
||||
/* seem to encompass most endian symbol definitions */
|
||||
|
||||
#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN )
|
||||
# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( BIG_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( LITTLE_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN )
|
||||
# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( _BIG_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( _LITTLE_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN )
|
||||
# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( __BIG_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( __LITTLE_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ )
|
||||
# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( __BIG_ENDIAN__ )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( __LITTLE_ENDIAN__ )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
/* if the platform byte order could not be determined, then try to */
|
||||
/* set this define using common machine defines */
|
||||
#if !defined(PLATFORM_BYTE_ORDER)
|
||||
|
||||
#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \
|
||||
defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \
|
||||
defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \
|
||||
defined( vax ) || defined( vms ) || defined( VMS ) || \
|
||||
defined( __VMS ) || defined( _M_X64 )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
|
||||
#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \
|
||||
defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \
|
||||
defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \
|
||||
defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \
|
||||
defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \
|
||||
defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \
|
||||
defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
|
||||
#elif 0 /* **** EDIT HERE IF NECESSARY **** */
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#elif 0 /* **** EDIT HERE IF NECESSARY **** */
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#else
|
||||
# error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
The unsigned integer types defined here are of the form uint_<nn>t where
|
||||
<nn> is the length of the type; for example, the unsigned 32-bit type is
|
||||
'uint_32t'. These are NOT the same as the 'C99 integer types' that are
|
||||
defined in the inttypes.h and stdint.h headers since attempts to use these
|
||||
types have shown that support for them is still highly variable. However,
|
||||
since the latter are of the form uint<nn>_t, a regular expression search
|
||||
and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t')
|
||||
can be used to convert the types used here to the C99 standard types.
|
||||
*/
|
||||
|
||||
#ifndef _BRG_TYPES_H
|
||||
#define _BRG_TYPES_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
|
||||
# include <stddef.h>
|
||||
# define ptrint_t intptr_t
|
||||
#elif defined( __ECOS__ )
|
||||
# define intptr_t unsigned int
|
||||
# define ptrint_t intptr_t
|
||||
#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 )
|
||||
# include <stdint.h>
|
||||
# define ptrint_t intptr_t
|
||||
#else
|
||||
# define ptrint_t int
|
||||
#endif
|
||||
|
||||
#ifndef BRG_UI8
|
||||
# define BRG_UI8
|
||||
# if UCHAR_MAX == 255u
|
||||
typedef unsigned char uint_8t;
|
||||
# else
|
||||
# error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BRG_UI16
|
||||
# define BRG_UI16
|
||||
# if USHRT_MAX == 65535u
|
||||
typedef unsigned short uint_16t;
|
||||
# else
|
||||
# error Please define uint_16t as a 16-bit unsigned short type in brg_types.h
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BRG_UI32
|
||||
# define BRG_UI32
|
||||
# if UINT_MAX == 4294967295u
|
||||
# define li_32(h) 0x##h##u
|
||||
typedef unsigned int uint_32t;
|
||||
# elif ULONG_MAX == 4294967295u
|
||||
# define li_32(h) 0x##h##ul
|
||||
typedef unsigned long uint_32t;
|
||||
# elif defined( _CRAY )
|
||||
# error This code needs 32-bit data types, which Cray machines do not provide
|
||||
# else
|
||||
# error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BRG_UI64
|
||||
# if defined( __BORLANDC__ ) && !defined( __MSDOS__ )
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ui64
|
||||
typedef unsigned __int64 uint_64t;
|
||||
# elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ui64
|
||||
typedef unsigned __int64 uint_64t;
|
||||
# elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
typedef unsigned long long uint_64t;
|
||||
# elif defined( __MVS__ )
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
typedef unsigned int long long uint_64t;
|
||||
# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u
|
||||
# if UINT_MAX == 18446744073709551615u
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##u
|
||||
typedef unsigned int uint_64t;
|
||||
# endif
|
||||
# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u
|
||||
# if ULONG_MAX == 18446744073709551615ul
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ul
|
||||
typedef unsigned long uint_64t;
|
||||
# endif
|
||||
# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u
|
||||
# if ULLONG_MAX == 18446744073709551615ull
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
typedef unsigned long long uint_64t;
|
||||
# endif
|
||||
# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u
|
||||
# if ULONG_LONG_MAX == 18446744073709551615ull
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
typedef unsigned long long uint_64t;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined( BRG_UI64 )
|
||||
# if defined( NEED_UINT_64T )
|
||||
# error Please define uint_64t as an unsigned 64 bit type in brg_types.h
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef RETURN_VALUES
|
||||
# define RETURN_VALUES
|
||||
# if defined( DLL_EXPORT )
|
||||
# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
|
||||
# define VOID_RETURN __declspec( dllexport ) void __stdcall
|
||||
# define INT_RETURN __declspec( dllexport ) int __stdcall
|
||||
# elif defined( __GNUC__ )
|
||||
# define VOID_RETURN __declspec( __dllexport__ ) void
|
||||
# define INT_RETURN __declspec( __dllexport__ ) int
|
||||
# else
|
||||
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
|
||||
# endif
|
||||
# elif defined( DLL_IMPORT )
|
||||
# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
|
||||
# define VOID_RETURN __declspec( dllimport ) void __stdcall
|
||||
# define INT_RETURN __declspec( dllimport ) int __stdcall
|
||||
# elif defined( __GNUC__ )
|
||||
# define VOID_RETURN __declspec( __dllimport__ ) void
|
||||
# define INT_RETURN __declspec( __dllimport__ ) int
|
||||
# else
|
||||
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
|
||||
# endif
|
||||
# elif defined( __WATCOMC__ )
|
||||
# define VOID_RETURN void __cdecl
|
||||
# define INT_RETURN int __cdecl
|
||||
# else
|
||||
# define VOID_RETURN void
|
||||
# define INT_RETURN int
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* These defines are used to detect and set the memory alignment of pointers.
|
||||
Note that offsets are in bytes.
|
||||
|
||||
ALIGN_OFFSET(x,n) return the positive or zero offset of
|
||||
the memory addressed by the pointer 'x'
|
||||
from an address that is aligned on an
|
||||
'n' byte boundary ('n' is a power of 2)
|
||||
|
||||
ALIGN_FLOOR(x,n) return a pointer that points to memory
|
||||
that is aligned on an 'n' byte boundary
|
||||
and is not higher than the memory address
|
||||
pointed to by 'x' ('n' is a power of 2)
|
||||
|
||||
ALIGN_CEIL(x,n) return a pointer that points to memory
|
||||
that is aligned on an 'n' byte boundary
|
||||
and is not lower than the memory address
|
||||
pointed to by 'x' ('n' is a power of 2)
|
||||
*/
|
||||
|
||||
#define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1))
|
||||
#define ALIGN_FLOOR(x,n) ((uint_8t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1)))
|
||||
#define ALIGN_CEIL(x,n) ((uint_8t*)(x) + (-((ptrint_t)(x)) & ((n) - 1)))
|
||||
|
||||
/* These defines are used to declare buffers in a way that allows
|
||||
faster operations on longer variables to be used. In all these
|
||||
defines 'size' must be a power of 2 and >= 8. NOTE that the
|
||||
buffer size is in bytes but the type length is in bits
|
||||
|
||||
UNIT_TYPEDEF(x,size) declares a variable 'x' of length
|
||||
'size' bits
|
||||
|
||||
BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize'
|
||||
bytes defined as an array of variables
|
||||
each of 'size' bits (bsize must be a
|
||||
multiple of size / 8)
|
||||
|
||||
UNIT_CAST(x,size) casts a variable to a type of
|
||||
length 'size' bits
|
||||
|
||||
UPTR_CAST(x,size) casts a pointer to a pointer to a
|
||||
varaiable of length 'size' bits
|
||||
*/
|
||||
|
||||
#define UI_TYPE(size) uint_##size##t
|
||||
#define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x
|
||||
#define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)]
|
||||
#define UNIT_CAST(x,size) ((UI_TYPE(size) )(x))
|
||||
#define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x))
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,773 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 01/08/2005
|
||||
|
||||
This is a byte oriented version of SHA2 that operates on arrays of bytes
|
||||
stored in memory. This code implements sha256, sha384 and sha512 but the
|
||||
latter two functions rely on efficient 64-bit integer operations that
|
||||
may not be very efficient on 32-bit machines
|
||||
|
||||
The sha256 functions use a type 'sha256_ctx' to hold details of the
|
||||
current hash state and uses the following three calls:
|
||||
|
||||
void sha256_begin(sha256_ctx ctx[1])
|
||||
void sha256_hash(const unsigned char data[],
|
||||
unsigned long len, sha256_ctx ctx[1])
|
||||
void sha_end1(unsigned char hval[], sha256_ctx ctx[1])
|
||||
|
||||
The first subroutine initialises a hash computation by setting up the
|
||||
context in the sha256_ctx context. The second subroutine hashes 8-bit
|
||||
bytes from array data[] into the hash state withinh sha256_ctx context,
|
||||
the number of bytes to be hashed being given by the the unsigned long
|
||||
integer len. The third subroutine completes the hash calculation and
|
||||
places the resulting digest value in the array of 8-bit bytes hval[].
|
||||
|
||||
The sha384 and sha512 functions are similar and use the interfaces:
|
||||
|
||||
void sha384_begin(sha384_ctx ctx[1]);
|
||||
void sha384_hash(const unsigned char data[],
|
||||
unsigned long len, sha384_ctx ctx[1]);
|
||||
void sha384_end(unsigned char hval[], sha384_ctx ctx[1]);
|
||||
|
||||
void sha512_begin(sha512_ctx ctx[1]);
|
||||
void sha512_hash(const unsigned char data[],
|
||||
unsigned long len, sha512_ctx ctx[1]);
|
||||
void sha512_end(unsigned char hval[], sha512_ctx ctx[1]);
|
||||
|
||||
In addition there is a function sha2 that can be used to call all these
|
||||
functions using a call with a hash length parameter as follows:
|
||||
|
||||
int sha2_begin(unsigned long len, sha2_ctx ctx[1]);
|
||||
void sha2_hash(const unsigned char data[],
|
||||
unsigned long len, sha2_ctx ctx[1]);
|
||||
void sha2_end(unsigned char hval[], sha2_ctx ctx[1]);
|
||||
|
||||
My thanks to Erik Andersen <andersen@codepoet.org> for testing this code
|
||||
on big-endian systems and for his assistance with corrections
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#define UNROLL_SHA2 /* for SHA2 loop unroll */
|
||||
#endif
|
||||
|
||||
#include <string.h> /* for memcpy() etc. */
|
||||
|
||||
#include "sha2.h"
|
||||
|
||||
#include <crypt/brg_endian.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER ) && ( _MSC_VER > 800 )
|
||||
#pragma intrinsic(memcpy)
|
||||
#endif
|
||||
|
||||
#if 0 && defined(_MSC_VER)
|
||||
#define rotl32 _lrotl
|
||||
#define rotr32 _lrotr
|
||||
#else
|
||||
#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
|
||||
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
|
||||
#endif
|
||||
|
||||
#if !defined(bswap_32)
|
||||
#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00))
|
||||
#endif
|
||||
|
||||
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
|
||||
#define SWAP_BYTES
|
||||
#else
|
||||
#undef SWAP_BYTES
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
|
||||
#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
|
||||
#else /* Thanks to Rich Schroeppel and Colin Plumb for the following */
|
||||
|
||||
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
|
||||
|
||||
#endif
|
||||
|
||||
/* round transforms for SHA256 and SHA512 compression functions */
|
||||
|
||||
#define vf(n,i) v[(n - i) & 7]
|
||||
|
||||
#define hf(i) (p[i & 15] += \
|
||||
g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15]))
|
||||
|
||||
#define v_cycle(i,j) \
|
||||
vf(7,i) += (j ? hf(i) : p[i]) + k_0[i+j] \
|
||||
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
|
||||
vf(3,i) += vf(7,i); \
|
||||
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
|
||||
|
||||
#if defined(SHA_224) || defined(SHA_256)
|
||||
|
||||
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1)
|
||||
|
||||
#if defined(SWAP_BYTES)
|
||||
#define bsw_32(p,n) \
|
||||
{ int _i = (n); while(_i--) ((uint_32t*)p)[_i] = bswap_32(((uint_32t*)p)[_i]); }
|
||||
#else
|
||||
#define bsw_32(p,n)
|
||||
#endif
|
||||
|
||||
#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
|
||||
#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
|
||||
#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
|
||||
#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
|
||||
#define k_0 k256
|
||||
|
||||
/* rotated SHA256 round definition. Rather than swapping variables as in */
|
||||
/* FIPS-180, different variables are 'rotated' on each round, returning */
|
||||
/* to their starting positions every eight rounds */
|
||||
|
||||
#define q(n) v##n
|
||||
|
||||
#define one_cycle(a,b,c,d,e,f,g,h,k,w) \
|
||||
q(h) += s_1(q(e)) + ch(q(e), q(f), q(g)) + k + w; \
|
||||
q(d) += q(h); q(h) += s_0(q(a)) + maj(q(a), q(b), q(c))
|
||||
|
||||
/* SHA256 mixing data */
|
||||
|
||||
const uint_32t k256[64] =
|
||||
{ 0x428a2f98ul, 0x71374491ul, 0xb5c0fbcful, 0xe9b5dba5ul,
|
||||
0x3956c25bul, 0x59f111f1ul, 0x923f82a4ul, 0xab1c5ed5ul,
|
||||
0xd807aa98ul, 0x12835b01ul, 0x243185beul, 0x550c7dc3ul,
|
||||
0x72be5d74ul, 0x80deb1feul, 0x9bdc06a7ul, 0xc19bf174ul,
|
||||
0xe49b69c1ul, 0xefbe4786ul, 0x0fc19dc6ul, 0x240ca1ccul,
|
||||
0x2de92c6ful, 0x4a7484aaul, 0x5cb0a9dcul, 0x76f988daul,
|
||||
0x983e5152ul, 0xa831c66dul, 0xb00327c8ul, 0xbf597fc7ul,
|
||||
0xc6e00bf3ul, 0xd5a79147ul, 0x06ca6351ul, 0x14292967ul,
|
||||
0x27b70a85ul, 0x2e1b2138ul, 0x4d2c6dfcul, 0x53380d13ul,
|
||||
0x650a7354ul, 0x766a0abbul, 0x81c2c92eul, 0x92722c85ul,
|
||||
0xa2bfe8a1ul, 0xa81a664bul, 0xc24b8b70ul, 0xc76c51a3ul,
|
||||
0xd192e819ul, 0xd6990624ul, 0xf40e3585ul, 0x106aa070ul,
|
||||
0x19a4c116ul, 0x1e376c08ul, 0x2748774cul, 0x34b0bcb5ul,
|
||||
0x391c0cb3ul, 0x4ed8aa4aul, 0x5b9cca4ful, 0x682e6ff3ul,
|
||||
0x748f82eeul, 0x78a5636ful, 0x84c87814ul, 0x8cc70208ul,
|
||||
0x90befffaul, 0xa4506cebul, 0xbef9a3f7ul, 0xc67178f2ul,
|
||||
};
|
||||
|
||||
/* Compile 64 bytes of hash data into SHA256 digest value */
|
||||
/* NOTE: this routine assumes that the byte order in the */
|
||||
/* ctx->wbuf[] at this point is such that low address bytes */
|
||||
/* in the ORIGINAL byte stream will go into the high end of */
|
||||
/* words on BOTH big and little endian systems */
|
||||
|
||||
VOID_RETURN sha256_compile(sha256_ctx ctx[1])
|
||||
{
|
||||
#if !defined(UNROLL_SHA2)
|
||||
|
||||
uint_32t j, *p = ctx->wbuf, v[8];
|
||||
|
||||
memcpy(v, ctx->hash, 8 * sizeof(uint_32t));
|
||||
|
||||
for(j = 0; j < 64; j += 16)
|
||||
{
|
||||
v_cycle( 0, j); v_cycle( 1, j);
|
||||
v_cycle( 2, j); v_cycle( 3, j);
|
||||
v_cycle( 4, j); v_cycle( 5, j);
|
||||
v_cycle( 6, j); v_cycle( 7, j);
|
||||
v_cycle( 8, j); v_cycle( 9, j);
|
||||
v_cycle(10, j); v_cycle(11, j);
|
||||
v_cycle(12, j); v_cycle(13, j);
|
||||
v_cycle(14, j); v_cycle(15, j);
|
||||
}
|
||||
|
||||
ctx->hash[0] += v[0]; ctx->hash[1] += v[1];
|
||||
ctx->hash[2] += v[2]; ctx->hash[3] += v[3];
|
||||
ctx->hash[4] += v[4]; ctx->hash[5] += v[5];
|
||||
ctx->hash[6] += v[6]; ctx->hash[7] += v[7];
|
||||
|
||||
#else
|
||||
|
||||
uint_32t *p = ctx->wbuf,v0,v1,v2,v3,v4,v5,v6,v7;
|
||||
|
||||
v0 = ctx->hash[0]; v1 = ctx->hash[1];
|
||||
v2 = ctx->hash[2]; v3 = ctx->hash[3];
|
||||
v4 = ctx->hash[4]; v5 = ctx->hash[5];
|
||||
v6 = ctx->hash[6]; v7 = ctx->hash[7];
|
||||
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[ 0],p[ 0]);
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[ 1],p[ 1]);
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[ 2],p[ 2]);
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[ 3],p[ 3]);
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[ 4],p[ 4]);
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[ 5],p[ 5]);
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[ 6],p[ 6]);
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[ 7],p[ 7]);
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[ 8],p[ 8]);
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[ 9],p[ 9]);
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[10],p[10]);
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[11],p[11]);
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[12],p[12]);
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[13],p[13]);
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[14],p[14]);
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[15],p[15]);
|
||||
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[16],hf( 0));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[17],hf( 1));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[18],hf( 2));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[19],hf( 3));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[20],hf( 4));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[21],hf( 5));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[22],hf( 6));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[23],hf( 7));
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[24],hf( 8));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[25],hf( 9));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[26],hf(10));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[27],hf(11));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[28],hf(12));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[29],hf(13));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[30],hf(14));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[31],hf(15));
|
||||
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[32],hf( 0));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[33],hf( 1));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[34],hf( 2));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[35],hf( 3));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[36],hf( 4));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[37],hf( 5));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[38],hf( 6));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[39],hf( 7));
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[40],hf( 8));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[41],hf( 9));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[42],hf(10));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[43],hf(11));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[44],hf(12));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[45],hf(13));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[46],hf(14));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[47],hf(15));
|
||||
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[48],hf( 0));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[49],hf( 1));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[50],hf( 2));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[51],hf( 3));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[52],hf( 4));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[53],hf( 5));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[54],hf( 6));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[55],hf( 7));
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[56],hf( 8));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[57],hf( 9));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[58],hf(10));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[59],hf(11));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[60],hf(12));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[61],hf(13));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[62],hf(14));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[63],hf(15));
|
||||
|
||||
ctx->hash[0] += v0; ctx->hash[1] += v1;
|
||||
ctx->hash[2] += v2; ctx->hash[3] += v3;
|
||||
ctx->hash[4] += v4; ctx->hash[5] += v5;
|
||||
ctx->hash[6] += v6; ctx->hash[7] += v7;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* SHA256 hash data in an array of bytes into hash buffer */
|
||||
/* and call the hash_compile function as required. */
|
||||
|
||||
VOID_RETURN sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1])
|
||||
{ uint_32t pos = (uint_32t)(ctx->count[0] & SHA256_MASK),
|
||||
space = SHA256_BLOCK_SIZE - pos;
|
||||
const unsigned char *sp = data;
|
||||
|
||||
if((ctx->count[0] += len) < len)
|
||||
++(ctx->count[1]);
|
||||
|
||||
while(len >= space) /* tranfer whole blocks while possible */
|
||||
{
|
||||
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space);
|
||||
sp += space; len -= space; space = SHA256_BLOCK_SIZE; pos = 0;
|
||||
bsw_32(ctx->wbuf, SHA256_BLOCK_SIZE >> 2)
|
||||
sha256_compile(ctx);
|
||||
}
|
||||
|
||||
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len);
|
||||
}
|
||||
|
||||
/* SHA256 Final padding and digest calculation */
|
||||
|
||||
static void sha_end1(unsigned char hval[], sha256_ctx ctx[1], const unsigned int hlen)
|
||||
{ uint_32t i = (uint_32t)(ctx->count[0] & SHA256_MASK);
|
||||
|
||||
/* put bytes in the buffer in an order in which references to */
|
||||
/* 32-bit words will put bytes with lower addresses into the */
|
||||
/* top of 32 bit words on BOTH big and little endian machines */
|
||||
bsw_32(ctx->wbuf, (i + 3) >> 2)
|
||||
|
||||
/* we now need to mask valid bytes and add the padding which is */
|
||||
/* a single 1 bit and as many zero bits as necessary. Note that */
|
||||
/* we can always add the first padding byte here because the */
|
||||
/* buffer always has at least one empty slot */
|
||||
ctx->wbuf[i >> 2] &= 0xffffff80 << 8 * (~i & 3);
|
||||
ctx->wbuf[i >> 2] |= 0x00000080 << 8 * (~i & 3);
|
||||
|
||||
/* we need 9 or more empty positions, one for the padding byte */
|
||||
/* (above) and eight for the length count. If there is not */
|
||||
/* enough space pad and empty the buffer */
|
||||
if(i > SHA256_BLOCK_SIZE - 9)
|
||||
{
|
||||
if(i < 60) ctx->wbuf[15] = 0;
|
||||
sha256_compile(ctx);
|
||||
i = 0;
|
||||
}
|
||||
else /* compute a word index for the empty buffer positions */
|
||||
i = (i >> 2) + 1;
|
||||
|
||||
while(i < 14) /* and zero pad all but last two positions */
|
||||
ctx->wbuf[i++] = 0;
|
||||
|
||||
/* the following 32-bit length fields are assembled in the */
|
||||
/* wrong byte order on little endian machines but this is */
|
||||
/* corrected later since they are only ever used as 32-bit */
|
||||
/* word values. */
|
||||
ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29);
|
||||
ctx->wbuf[15] = ctx->count[0] << 3;
|
||||
sha256_compile(ctx);
|
||||
|
||||
/* extract the hash value as bytes in case the hash buffer is */
|
||||
/* mislaigned for 32-bit words */
|
||||
for(i = 0; i < hlen; ++i)
|
||||
hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_224)
|
||||
|
||||
const uint_32t i224[8] =
|
||||
{
|
||||
0xc1059ed8ul, 0x367cd507ul, 0x3070dd17ul, 0xf70e5939ul,
|
||||
0xffc00b31ul, 0x68581511ul, 0x64f98fa7ul, 0xbefa4fa4ul
|
||||
};
|
||||
|
||||
VOID_RETURN sha224_begin(sha224_ctx ctx[1])
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
memcpy(ctx->hash, i224, 8 * sizeof(uint_32t));
|
||||
}
|
||||
|
||||
VOID_RETURN sha224_end(unsigned char hval[], sha224_ctx ctx[1])
|
||||
{
|
||||
sha_end1(hval, ctx, SHA224_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
VOID_RETURN sha224_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len)
|
||||
{ sha224_ctx cx[1];
|
||||
|
||||
sha224_begin(cx);
|
||||
sha224_hash(data, len, cx);
|
||||
sha_end1(hval, cx, SHA224_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_256)
|
||||
|
||||
const uint_32t i256[8] =
|
||||
{
|
||||
0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul,
|
||||
0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul
|
||||
};
|
||||
|
||||
VOID_RETURN sha256_begin(sha256_ctx ctx[1])
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
memcpy(ctx->hash, i256, 8 * sizeof(uint_32t));
|
||||
}
|
||||
|
||||
VOID_RETURN sha256_end(unsigned char hval[], sha256_ctx ctx[1])
|
||||
{
|
||||
sha_end1(hval, ctx, SHA256_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
VOID_RETURN sha256_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len)
|
||||
{ sha256_ctx cx[1];
|
||||
|
||||
sha256_begin(cx);
|
||||
sha256_hash(data, len, cx);
|
||||
sha_end1(hval, cx, SHA256_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_384) || defined(SHA_512)
|
||||
|
||||
#define SHA512_MASK (SHA512_BLOCK_SIZE - 1)
|
||||
|
||||
#define rotr64(x,n) (((x) >> n) | ((x) << (64 - n)))
|
||||
|
||||
#if !defined(bswap_64)
|
||||
#define bswap_64(x) (((uint_64t)(bswap_32((uint_32t)(x)))) << 32 | bswap_32((uint_32t)((x) >> 32)))
|
||||
#endif
|
||||
|
||||
#if defined(SWAP_BYTES)
|
||||
#define bsw_64(p,n) \
|
||||
{ int _i = (n); while(_i--) ((uint_64t*)p)[_i] = bswap_64(((uint_64t*)p)[_i]); }
|
||||
#else
|
||||
#define bsw_64(p,n)
|
||||
#endif
|
||||
|
||||
/* SHA512 mixing function definitions */
|
||||
|
||||
#ifdef s_0
|
||||
# undef s_0
|
||||
# undef s_1
|
||||
# undef g_0
|
||||
# undef g_1
|
||||
# undef k_0
|
||||
#endif
|
||||
|
||||
#define s_0(x) (rotr64((x), 28) ^ rotr64((x), 34) ^ rotr64((x), 39))
|
||||
#define s_1(x) (rotr64((x), 14) ^ rotr64((x), 18) ^ rotr64((x), 41))
|
||||
#define g_0(x) (rotr64((x), 1) ^ rotr64((x), 8) ^ ((x) >> 7))
|
||||
#define g_1(x) (rotr64((x), 19) ^ rotr64((x), 61) ^ ((x) >> 6))
|
||||
#define k_0 k512
|
||||
|
||||
/* SHA384/SHA512 mixing data */
|
||||
|
||||
const uint_64t k512[80] =
|
||||
{
|
||||
li_64(428a2f98d728ae22), li_64(7137449123ef65cd),
|
||||
li_64(b5c0fbcfec4d3b2f), li_64(e9b5dba58189dbbc),
|
||||
li_64(3956c25bf348b538), li_64(59f111f1b605d019),
|
||||
li_64(923f82a4af194f9b), li_64(ab1c5ed5da6d8118),
|
||||
li_64(d807aa98a3030242), li_64(12835b0145706fbe),
|
||||
li_64(243185be4ee4b28c), li_64(550c7dc3d5ffb4e2),
|
||||
li_64(72be5d74f27b896f), li_64(80deb1fe3b1696b1),
|
||||
li_64(9bdc06a725c71235), li_64(c19bf174cf692694),
|
||||
li_64(e49b69c19ef14ad2), li_64(efbe4786384f25e3),
|
||||
li_64(0fc19dc68b8cd5b5), li_64(240ca1cc77ac9c65),
|
||||
li_64(2de92c6f592b0275), li_64(4a7484aa6ea6e483),
|
||||
li_64(5cb0a9dcbd41fbd4), li_64(76f988da831153b5),
|
||||
li_64(983e5152ee66dfab), li_64(a831c66d2db43210),
|
||||
li_64(b00327c898fb213f), li_64(bf597fc7beef0ee4),
|
||||
li_64(c6e00bf33da88fc2), li_64(d5a79147930aa725),
|
||||
li_64(06ca6351e003826f), li_64(142929670a0e6e70),
|
||||
li_64(27b70a8546d22ffc), li_64(2e1b21385c26c926),
|
||||
li_64(4d2c6dfc5ac42aed), li_64(53380d139d95b3df),
|
||||
li_64(650a73548baf63de), li_64(766a0abb3c77b2a8),
|
||||
li_64(81c2c92e47edaee6), li_64(92722c851482353b),
|
||||
li_64(a2bfe8a14cf10364), li_64(a81a664bbc423001),
|
||||
li_64(c24b8b70d0f89791), li_64(c76c51a30654be30),
|
||||
li_64(d192e819d6ef5218), li_64(d69906245565a910),
|
||||
li_64(f40e35855771202a), li_64(106aa07032bbd1b8),
|
||||
li_64(19a4c116b8d2d0c8), li_64(1e376c085141ab53),
|
||||
li_64(2748774cdf8eeb99), li_64(34b0bcb5e19b48a8),
|
||||
li_64(391c0cb3c5c95a63), li_64(4ed8aa4ae3418acb),
|
||||
li_64(5b9cca4f7763e373), li_64(682e6ff3d6b2b8a3),
|
||||
li_64(748f82ee5defb2fc), li_64(78a5636f43172f60),
|
||||
li_64(84c87814a1f0ab72), li_64(8cc702081a6439ec),
|
||||
li_64(90befffa23631e28), li_64(a4506cebde82bde9),
|
||||
li_64(bef9a3f7b2c67915), li_64(c67178f2e372532b),
|
||||
li_64(ca273eceea26619c), li_64(d186b8c721c0c207),
|
||||
li_64(eada7dd6cde0eb1e), li_64(f57d4f7fee6ed178),
|
||||
li_64(06f067aa72176fba), li_64(0a637dc5a2c898a6),
|
||||
li_64(113f9804bef90dae), li_64(1b710b35131c471b),
|
||||
li_64(28db77f523047d84), li_64(32caab7b40c72493),
|
||||
li_64(3c9ebe0a15c9bebc), li_64(431d67c49c100d4c),
|
||||
li_64(4cc5d4becb3e42b6), li_64(597f299cfc657e2a),
|
||||
li_64(5fcb6fab3ad6faec), li_64(6c44198c4a475817)
|
||||
};
|
||||
|
||||
/* Compile 128 bytes of hash data into SHA384/512 digest */
|
||||
/* NOTE: this routine assumes that the byte order in the */
|
||||
/* ctx->wbuf[] at this point is such that low address bytes */
|
||||
/* in the ORIGINAL byte stream will go into the high end of */
|
||||
/* words on BOTH big and little endian systems */
|
||||
|
||||
VOID_RETURN sha512_compile(sha512_ctx ctx[1])
|
||||
{ uint_64t v[8], *p = ctx->wbuf;
|
||||
uint_32t j;
|
||||
|
||||
memcpy(v, ctx->hash, 8 * sizeof(uint_64t));
|
||||
|
||||
for(j = 0; j < 80; j += 16)
|
||||
{
|
||||
v_cycle( 0, j); v_cycle( 1, j);
|
||||
v_cycle( 2, j); v_cycle( 3, j);
|
||||
v_cycle( 4, j); v_cycle( 5, j);
|
||||
v_cycle( 6, j); v_cycle( 7, j);
|
||||
v_cycle( 8, j); v_cycle( 9, j);
|
||||
v_cycle(10, j); v_cycle(11, j);
|
||||
v_cycle(12, j); v_cycle(13, j);
|
||||
v_cycle(14, j); v_cycle(15, j);
|
||||
}
|
||||
|
||||
ctx->hash[0] += v[0]; ctx->hash[1] += v[1];
|
||||
ctx->hash[2] += v[2]; ctx->hash[3] += v[3];
|
||||
ctx->hash[4] += v[4]; ctx->hash[5] += v[5];
|
||||
ctx->hash[6] += v[6]; ctx->hash[7] += v[7];
|
||||
}
|
||||
|
||||
/* Compile 128 bytes of hash data into SHA256 digest value */
|
||||
/* NOTE: this routine assumes that the byte order in the */
|
||||
/* ctx->wbuf[] at this point is in such an order that low */
|
||||
/* address bytes in the ORIGINAL byte stream placed in this */
|
||||
/* buffer will now go to the high end of words on BOTH big */
|
||||
/* and little endian systems */
|
||||
|
||||
VOID_RETURN sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1])
|
||||
{ uint_32t pos = (uint_32t)(ctx->count[0] & SHA512_MASK),
|
||||
space = SHA512_BLOCK_SIZE - pos;
|
||||
const unsigned char *sp = data;
|
||||
|
||||
if((ctx->count[0] += len) < len)
|
||||
++(ctx->count[1]);
|
||||
|
||||
while(len >= space) /* tranfer whole blocks while possible */
|
||||
{
|
||||
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space);
|
||||
sp += space; len -= space; space = SHA512_BLOCK_SIZE; pos = 0;
|
||||
bsw_64(ctx->wbuf, SHA512_BLOCK_SIZE >> 3);
|
||||
sha512_compile(ctx);
|
||||
}
|
||||
|
||||
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len);
|
||||
}
|
||||
|
||||
/* SHA384/512 Final padding and digest calculation */
|
||||
|
||||
static void sha_end2(unsigned char hval[], sha512_ctx ctx[1], const unsigned int hlen)
|
||||
{ uint_32t i = (uint_32t)(ctx->count[0] & SHA512_MASK);
|
||||
|
||||
/* put bytes in the buffer in an order in which references to */
|
||||
/* 32-bit words will put bytes with lower addresses into the */
|
||||
/* top of 32 bit words on BOTH big and little endian machines */
|
||||
bsw_64(ctx->wbuf, (i + 7) >> 3);
|
||||
|
||||
/* we now need to mask valid bytes and add the padding which is */
|
||||
/* a single 1 bit and as many zero bits as necessary. Note that */
|
||||
/* we can always add the first padding byte here because the */
|
||||
/* buffer always has at least one empty slot */
|
||||
ctx->wbuf[i >> 3] &= li_64(ffffffffffffff00) << 8 * (~i & 7);
|
||||
ctx->wbuf[i >> 3] |= li_64(0000000000000080) << 8 * (~i & 7);
|
||||
|
||||
/* we need 17 or more empty byte positions, one for the padding */
|
||||
/* byte (above) and sixteen for the length count. If there is */
|
||||
/* not enough space pad and empty the buffer */
|
||||
if(i > SHA512_BLOCK_SIZE - 17)
|
||||
{
|
||||
if(i < 120) ctx->wbuf[15] = 0;
|
||||
sha512_compile(ctx);
|
||||
i = 0;
|
||||
}
|
||||
else
|
||||
i = (i >> 3) + 1;
|
||||
|
||||
while(i < 14)
|
||||
ctx->wbuf[i++] = 0;
|
||||
|
||||
/* the following 64-bit length fields are assembled in the */
|
||||
/* wrong byte order on little endian machines but this is */
|
||||
/* corrected later since they are only ever used as 64-bit */
|
||||
/* word values. */
|
||||
ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 61);
|
||||
ctx->wbuf[15] = ctx->count[0] << 3;
|
||||
sha512_compile(ctx);
|
||||
|
||||
/* extract the hash value as bytes in case the hash buffer is */
|
||||
/* misaligned for 32-bit words */
|
||||
for(i = 0; i < hlen; ++i)
|
||||
hval[i] = (unsigned char)(ctx->hash[i >> 3] >> (8 * (~i & 7)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_384)
|
||||
|
||||
/* SHA384 initialisation data */
|
||||
|
||||
const uint_64t i384[80] =
|
||||
{
|
||||
li_64(cbbb9d5dc1059ed8), li_64(629a292a367cd507),
|
||||
li_64(9159015a3070dd17), li_64(152fecd8f70e5939),
|
||||
li_64(67332667ffc00b31), li_64(8eb44a8768581511),
|
||||
li_64(db0c2e0d64f98fa7), li_64(47b5481dbefa4fa4)
|
||||
};
|
||||
|
||||
VOID_RETURN sha384_begin(sha384_ctx ctx[1])
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
memcpy(ctx->hash, i384, 8 * sizeof(uint_64t));
|
||||
}
|
||||
|
||||
VOID_RETURN sha384_end(unsigned char hval[], sha384_ctx ctx[1])
|
||||
{
|
||||
sha_end2(hval, ctx, SHA384_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
VOID_RETURN sha384_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len)
|
||||
{ sha384_ctx cx[1];
|
||||
|
||||
sha384_begin(cx);
|
||||
sha384_hash(data, len, cx);
|
||||
sha_end2(hval, cx, SHA384_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_512)
|
||||
|
||||
/* SHA512 initialisation data */
|
||||
|
||||
const uint_64t i512[80] =
|
||||
{
|
||||
li_64(6a09e667f3bcc908), li_64(bb67ae8584caa73b),
|
||||
li_64(3c6ef372fe94f82b), li_64(a54ff53a5f1d36f1),
|
||||
li_64(510e527fade682d1), li_64(9b05688c2b3e6c1f),
|
||||
li_64(1f83d9abfb41bd6b), li_64(5be0cd19137e2179)
|
||||
};
|
||||
|
||||
VOID_RETURN sha512_begin(sha512_ctx ctx[1])
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
memcpy(ctx->hash, i512, 8 * sizeof(uint_64t));
|
||||
}
|
||||
|
||||
VOID_RETURN sha512_end(unsigned char hval[], sha512_ctx ctx[1])
|
||||
{
|
||||
sha_end2(hval, ctx, SHA512_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
VOID_RETURN sha512_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len)
|
||||
{ sha512_ctx cx[1];
|
||||
|
||||
sha512_begin(cx);
|
||||
sha512_hash(data, len, cx);
|
||||
sha_end2(hval, cx, SHA512_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_2)
|
||||
|
||||
#define CTX_224(x) ((x)->uu->ctx256)
|
||||
#define CTX_256(x) ((x)->uu->ctx256)
|
||||
#define CTX_384(x) ((x)->uu->ctx512)
|
||||
#define CTX_512(x) ((x)->uu->ctx512)
|
||||
|
||||
/* SHA2 initialisation */
|
||||
|
||||
INT_RETURN sha2_begin(unsigned long len, sha2_ctx ctx[1])
|
||||
{
|
||||
switch(len)
|
||||
{
|
||||
#if defined(SHA_224)
|
||||
case 224:
|
||||
case 28: CTX_256(ctx)->count[0] = CTX_256(ctx)->count[1] = 0;
|
||||
memcpy(CTX_256(ctx)->hash, i224, 32);
|
||||
ctx->sha2_len = 28; return EXIT_SUCCESS;
|
||||
#endif
|
||||
#if defined(SHA_256)
|
||||
case 256:
|
||||
case 32: CTX_256(ctx)->count[0] = CTX_256(ctx)->count[1] = 0;
|
||||
memcpy(CTX_256(ctx)->hash, i256, 32);
|
||||
ctx->sha2_len = 32; return EXIT_SUCCESS;
|
||||
#endif
|
||||
#if defined(SHA_384)
|
||||
case 384:
|
||||
case 48: CTX_384(ctx)->count[0] = CTX_384(ctx)->count[1] = 0;
|
||||
memcpy(CTX_384(ctx)->hash, i384, 64);
|
||||
ctx->sha2_len = 48; return EXIT_SUCCESS;
|
||||
#endif
|
||||
#if defined(SHA_512)
|
||||
case 512:
|
||||
case 64: CTX_512(ctx)->count[0] = CTX_512(ctx)->count[1] = 0;
|
||||
memcpy(CTX_512(ctx)->hash, i512, 64);
|
||||
ctx->sha2_len = 64; return EXIT_SUCCESS;
|
||||
#endif
|
||||
default: return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
VOID_RETURN sha2_hash(const unsigned char data[], unsigned long len, sha2_ctx ctx[1])
|
||||
{
|
||||
switch(ctx->sha2_len)
|
||||
{
|
||||
#if defined(SHA_224)
|
||||
case 28: sha224_hash(data, len, CTX_224(ctx)); return;
|
||||
#endif
|
||||
#if defined(SHA_256)
|
||||
case 32: sha256_hash(data, len, CTX_256(ctx)); return;
|
||||
#endif
|
||||
#if defined(SHA_384)
|
||||
case 48: sha384_hash(data, len, CTX_384(ctx)); return;
|
||||
#endif
|
||||
#if defined(SHA_512)
|
||||
case 64: sha512_hash(data, len, CTX_512(ctx)); return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
VOID_RETURN sha2_end(unsigned char hval[], sha2_ctx ctx[1])
|
||||
{
|
||||
switch(ctx->sha2_len)
|
||||
{
|
||||
#if defined(SHA_224)
|
||||
case 28: sha_end1(hval, CTX_224(ctx), SHA224_DIGEST_SIZE); return;
|
||||
#endif
|
||||
#if defined(SHA_256)
|
||||
case 32: sha_end1(hval, CTX_256(ctx), SHA256_DIGEST_SIZE); return;
|
||||
#endif
|
||||
#if defined(SHA_384)
|
||||
case 48: sha_end2(hval, CTX_384(ctx), SHA384_DIGEST_SIZE); return;
|
||||
#endif
|
||||
#if defined(SHA_512)
|
||||
case 64: sha_end2(hval, CTX_512(ctx), SHA512_DIGEST_SIZE); return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
INT_RETURN sha2_all(unsigned char hval[], unsigned long size,
|
||||
const unsigned char data[], unsigned long len)
|
||||
{ sha2_ctx cx[1];
|
||||
|
||||
if(sha2_begin(size, cx) == EXIT_SUCCESS)
|
||||
{
|
||||
sha2_hash(data, len, cx); sha2_end(hval, cx); return EXIT_SUCCESS;
|
||||
}
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 01/08/2005
|
||||
*/
|
||||
|
||||
#ifndef _SHA2_H
|
||||
#define _SHA2_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SHA_64BIT
|
||||
|
||||
/* define the hash functions that you need */
|
||||
#define SHA_2 /* for dynamic hash length */
|
||||
#define SHA_224
|
||||
#define SHA_256
|
||||
#ifdef SHA_64BIT
|
||||
# define SHA_384
|
||||
# define SHA_512
|
||||
# define NEED_UINT_64T
|
||||
#endif
|
||||
|
||||
#include <crypt/brg_types.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Note that the following function prototypes are the same */
|
||||
/* for both the bit and byte oriented implementations. But */
|
||||
/* the length fields are in bytes or bits as is appropriate */
|
||||
/* for the version used. Bit sequences are arrays of bytes */
|
||||
/* in which bit sequence indexes increase from the most to */
|
||||
/* the least significant end of each byte */
|
||||
|
||||
#define SHA224_DIGEST_SIZE 28
|
||||
#define SHA224_BLOCK_SIZE 64
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
#define SHA256_BLOCK_SIZE 64
|
||||
|
||||
/* type to hold the SHA256 (and SHA224) context */
|
||||
|
||||
typedef struct
|
||||
{ uint_32t count[2];
|
||||
uint_32t hash[8];
|
||||
uint_32t wbuf[16];
|
||||
} sha256_ctx;
|
||||
|
||||
typedef sha256_ctx sha224_ctx;
|
||||
|
||||
VOID_RETURN sha256_compile(sha256_ctx ctx[1]);
|
||||
|
||||
VOID_RETURN sha224_begin(sha224_ctx ctx[1]);
|
||||
#define sha224_hash sha256_hash
|
||||
VOID_RETURN sha224_end(unsigned char hval[], sha224_ctx ctx[1]);
|
||||
VOID_RETURN sha224_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len);
|
||||
|
||||
VOID_RETURN sha256_begin(sha256_ctx ctx[1]);
|
||||
VOID_RETURN sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1]);
|
||||
VOID_RETURN sha256_end(unsigned char hval[], sha256_ctx ctx[1]);
|
||||
VOID_RETURN sha256_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len);
|
||||
|
||||
#ifndef SHA_64BIT
|
||||
|
||||
typedef struct
|
||||
{ union
|
||||
{ sha256_ctx ctx256[1];
|
||||
} uu[1];
|
||||
uint_32t sha2_len;
|
||||
} sha2_ctx;
|
||||
|
||||
#define SHA2_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
|
||||
|
||||
#else
|
||||
|
||||
#define SHA384_DIGEST_SIZE 48
|
||||
#define SHA384_BLOCK_SIZE 128
|
||||
#define SHA512_DIGEST_SIZE 64
|
||||
#define SHA512_BLOCK_SIZE 128
|
||||
#define SHA2_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
|
||||
|
||||
/* type to hold the SHA384 (and SHA512) context */
|
||||
|
||||
typedef struct
|
||||
{ uint_64t count[2];
|
||||
uint_64t hash[8];
|
||||
uint_64t wbuf[16];
|
||||
} sha512_ctx;
|
||||
|
||||
typedef sha512_ctx sha384_ctx;
|
||||
|
||||
typedef struct
|
||||
{ union
|
||||
{ sha256_ctx ctx256[1];
|
||||
sha512_ctx ctx512[1];
|
||||
} uu[1];
|
||||
uint_32t sha2_len;
|
||||
} sha2_ctx;
|
||||
|
||||
VOID_RETURN sha512_compile(sha512_ctx ctx[1]);
|
||||
|
||||
VOID_RETURN sha384_begin(sha384_ctx ctx[1]);
|
||||
#define sha384_hash sha512_hash
|
||||
VOID_RETURN sha384_end(unsigned char hval[], sha384_ctx ctx[1]);
|
||||
VOID_RETURN sha384_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len);
|
||||
|
||||
VOID_RETURN sha512_begin(sha512_ctx ctx[1]);
|
||||
VOID_RETURN sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1]);
|
||||
VOID_RETURN sha512_end(unsigned char hval[], sha512_ctx ctx[1]);
|
||||
VOID_RETURN sha512_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len);
|
||||
|
||||
INT_RETURN sha2_begin(unsigned long size, sha2_ctx ctx[1]);
|
||||
VOID_RETURN sha2_hash(const unsigned char data[], unsigned long len, sha2_ctx ctx[1]);
|
||||
VOID_RETURN sha2_end(unsigned char hval[], sha2_ctx ctx[1]);
|
||||
INT_RETURN sha2_all(unsigned char hval[], unsigned long size, const unsigned char data[], unsigned long len);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Fast, portable, and easy-to-use Twofish implementation,
|
||||
* Version 0.3.
|
||||
* Copyright (c) 2002 by Niels Ferguson.
|
||||
*
|
||||
* See the twofish.c file for the details of the how and why of this code.
|
||||
*
|
||||
* The author hereby grants a perpetual license to everybody to
|
||||
* use this code for any purpose as long as the copyright message is included
|
||||
* in the source code of this or any derived work.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* PLATFORM FIXES
|
||||
* ==============
|
||||
*
|
||||
* The following definitions have to be fixed for each particular platform
|
||||
* you work on. If you have a multi-platform program, you no doubt have
|
||||
* portable definitions that you can substitute here without changing
|
||||
* the rest of the code.
|
||||
*
|
||||
* The defaults provided here should work on most PC compilers.
|
||||
*/
|
||||
|
||||
#ifndef TWOFISH_H
|
||||
#define TWOFISH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file twofish.h
|
||||
* @brief Function that provide basic Twofish crypto support
|
||||
*
|
||||
* @ingroup GNU_ZRTP
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* A Twofish_Byte must be an unsigned 8-bit integer.
|
||||
*
|
||||
* It must also be the elementary data size of your C platform,
|
||||
* i.e. sizeof( Twofish_Byte ) == 1.
|
||||
*/
|
||||
typedef unsigned char Twofish_Byte;
|
||||
|
||||
/**
|
||||
* A Twofish_UInt32 must be an unsigned integer of at least 32 bits.
|
||||
*
|
||||
* This type is used only internally in the implementation, so ideally it
|
||||
* would not appear in the header file, but it is used inside the
|
||||
* Twofish_key structure which means it has to be included here.
|
||||
*/
|
||||
typedef unsigned int Twofish_UInt32;
|
||||
|
||||
|
||||
/*
|
||||
* END OF PLATFORM FIXES
|
||||
* =====================
|
||||
*
|
||||
* You should not have to touch the rest of this file, but the code
|
||||
* in twofish.c has a few things you need to fix too.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return codes
|
||||
*/
|
||||
#define SUCCESS 1
|
||||
#define ERR_UINT32 -2
|
||||
#define ERR_BYTE -3
|
||||
#define ERR_GET32 -4
|
||||
#define ERR_PUT32 -5
|
||||
#define ERR_ROLR -6
|
||||
#define ERR_BSWAP -7
|
||||
#define ERR_SELECTB -8
|
||||
#define ERR_TEST_ENC -9
|
||||
#define ERR_TEST_DEC -10
|
||||
#define ERR_SEQ_ENC -11
|
||||
#define ERR_SEQ_DEC -12
|
||||
#define ERR_ODD_KEY -13
|
||||
#define ERR_INIT -14
|
||||
#define ERR_KEY_LEN -15
|
||||
#define ERR_ILL_ARG -16
|
||||
|
||||
|
||||
/**
|
||||
* Structure that contains a prepared Twofish key.
|
||||
*
|
||||
* A cipher key is used in two stages. In the first stage it is converted
|
||||
* form the original form to an internal representation.
|
||||
* This internal form is then used to encrypt and decrypt data.
|
||||
* This structure contains the internal form. It is rather large: 4256 bytes
|
||||
* on a platform with 32-bit unsigned values.
|
||||
*
|
||||
* Treat this as an opague structure, and don't try to manipulate the
|
||||
* elements in it. I wish I could hide the inside of the structure,
|
||||
* but C doesn't allow that.
|
||||
*/
|
||||
typedef
|
||||
struct
|
||||
{
|
||||
Twofish_UInt32 s[4][256]; /* pre-computed S-boxes */
|
||||
Twofish_UInt32 K[40]; /* Round key words */
|
||||
}
|
||||
Twofish_key;
|
||||
|
||||
|
||||
/**
|
||||
* Initialise and test the Twofish implementation.
|
||||
*
|
||||
* This function MUST be called before any other function in the
|
||||
* Twofish implementation is called.
|
||||
* It only needs to be called once.
|
||||
*
|
||||
* Apart from initialising the implementation it performs a self test.
|
||||
* If the Twofish_fatal function is not called, the code passed the test.
|
||||
* (See the twofish.c file for details on the Twofish_fatal function.)
|
||||
*
|
||||
* @returns a negative number if an error happend, +1 otherwise
|
||||
*/
|
||||
extern int Twofish_initialise();
|
||||
|
||||
|
||||
/**
|
||||
* Convert a cipher key to the internal form used for
|
||||
* encryption and decryption.
|
||||
*
|
||||
* The cipher key is an array of bytes; the Twofish_Byte type is
|
||||
* defined above to a type suitable on your platform.
|
||||
*
|
||||
* Any key must be converted to an internal form in the Twofisk_key structure
|
||||
* before it can be used.
|
||||
* The encryption and decryption functions only work with the internal form.
|
||||
* The conversion to internal form need only be done once for each key value.
|
||||
*
|
||||
* Be sure to wipe all key storage, including the Twofish_key structure,
|
||||
* once you are done with the key data.
|
||||
* A simple memset( TwofishKey, 0, sizeof( TwofishKey ) ) will do just fine.
|
||||
*
|
||||
* Unlike most implementations, this one allows any key size from 0 bytes
|
||||
* to 32 bytes. According to the Twofish specifications,
|
||||
* irregular key sizes are handled by padding the key with zeroes at the end
|
||||
* until the key size is 16, 24, or 32 bytes, whichever
|
||||
* comes first. Note that each key of irregular size is equivalent to exactly
|
||||
* one key of 16, 24, or 32 bytes.
|
||||
*
|
||||
* WARNING: Short keys have low entropy, and result in low security.
|
||||
* Anything less than 8 bytes is utterly insecure. For good security
|
||||
* use at least 16 bytes. I prefer to use 32-byte keys to prevent
|
||||
* any collision attacks on the key.
|
||||
*
|
||||
* The key length argument key_len must be in the proper range.
|
||||
* If key_len is not in the range 0,...,32 this routine attempts to generate
|
||||
* a fatal error (depending on the code environment),
|
||||
* and at best (or worst) returns without having done anything.
|
||||
*
|
||||
* @param key Array of key bytes
|
||||
* @param key_len Number of key bytes, must be in the range 0,1,...,32.
|
||||
* @param xkey Pointer to an Twofish_key structure that will be filled
|
||||
* with the internal form of the cipher key.
|
||||
* @returns a negative number if an error happend, +1 otherwise
|
||||
*/
|
||||
extern int Twofish_prepare_key(
|
||||
Twofish_Byte key[],
|
||||
int key_len,
|
||||
Twofish_key * xkey
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Encrypt a single block of data.
|
||||
*
|
||||
* This function encrypts a single block of 16 bytes of data.
|
||||
* If you want to encrypt a larger or variable-length message,
|
||||
* you will have to use a cipher mode, such as CBC or CTR.
|
||||
* These are outside the scope of this implementation.
|
||||
*
|
||||
* The xkey structure is not modified by this routine, and can be
|
||||
* used for further encryption and decryption operations.
|
||||
*
|
||||
* @param xkey pointer to Twofish_key, internal form of the key
|
||||
* produces by Twofish_prepare_key()
|
||||
* @param p Plaintext to be encrypted
|
||||
* @param c Place to store the ciphertext
|
||||
*/
|
||||
extern void Twofish_encrypt(
|
||||
Twofish_key * xkey,
|
||||
Twofish_Byte p[16],
|
||||
Twofish_Byte c[16]
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Decrypt a single block of data.
|
||||
*
|
||||
* This function decrypts a single block of 16 bytes of data.
|
||||
* If you want to decrypt a larger or variable-length message,
|
||||
* you will have to use a cipher mode, such as CBC or CTR.
|
||||
* These are outside the scope of this implementation.
|
||||
*
|
||||
* The xkey structure is not modified by this routine, and can be
|
||||
* used for further encryption and decryption operations.
|
||||
*
|
||||
* @param xkey pointer to Twofish_key, internal form of the key
|
||||
* produces by Twofish_prepare_key()
|
||||
* @param c Ciphertext to be decrypted
|
||||
* @param p Place to store the plaintext
|
||||
*/
|
||||
extern void Twofish_decrypt(
|
||||
Twofish_key * xkey,
|
||||
Twofish_Byte c[16],
|
||||
Twofish_Byte p[16]
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Encrypt data in CFB mode.
|
||||
*
|
||||
* This function encrypts data in CFB mode.
|
||||
*
|
||||
* The key structure is not modified by this routine, and can be
|
||||
* used for further encryption and decryption operations.
|
||||
*
|
||||
* @param keyCtx pointer to Twofish_key, internal form of the key
|
||||
* produced by Twofish_prepare_key()
|
||||
* @param in Plaintext to be encrypted
|
||||
* @param out Place to store the ciphertext
|
||||
* @param len number of bytes to encrypt.
|
||||
* @param ivec initialization vector for this CFB mode encryption.
|
||||
* @param num pointer to integer that holds number of available crypto bytes.
|
||||
*/
|
||||
void Twofish_cfb128_encrypt(Twofish_key* keyCtx, Twofish_Byte* in,
|
||||
Twofish_Byte* out, size_t len,
|
||||
Twofish_Byte* ivec, int *num);
|
||||
|
||||
/**
|
||||
* Decrypt data in CFB mode.
|
||||
*
|
||||
* This function decrypts data in CFB.
|
||||
*
|
||||
* The key structure is not modified by this routine, and can be
|
||||
* used for further encryption and decryption operations.
|
||||
*
|
||||
* @param keyCtx pointer to Twofish_key, internal form of the key
|
||||
* produced by Twofish_prepare_key()
|
||||
* @param in Ciphertext to be decrypted
|
||||
* @param out Place to store the plaintext
|
||||
* @param len number of bytes to decrypt.
|
||||
* @param ivec initialization vector for this CFB mode encryption.
|
||||
* @param num pointer to integer that holds number of available crypto bytes.
|
||||
*/
|
||||
void Twofish_cfb128_decrypt(Twofish_key* keyCtx, Twofish_Byte* in,
|
||||
Twofish_Byte* out, size_t len,
|
||||
Twofish_Byte* ivec, int *num);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,98 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "twofish.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
void Two_debugDummy(Twofish_Byte* in, Twofish_Byte* out, Twofish_Byte* ivec);
|
||||
#endif
|
||||
|
||||
void Twofish_cfb128_encrypt(Twofish_key* keyCtx, Twofish_Byte* in,
|
||||
Twofish_Byte* out, size_t len,
|
||||
Twofish_Byte* ivec, int32_t *num)
|
||||
{
|
||||
uint32_t n;
|
||||
|
||||
n = *num;
|
||||
|
||||
do {
|
||||
while (n && len) {
|
||||
*(out++) = ivec[n] ^= *(in++);
|
||||
--len;
|
||||
n = (n+1) % 16;
|
||||
}
|
||||
while (len>=16) {
|
||||
Twofish_encrypt(keyCtx, ivec, ivec);
|
||||
for (n=0; n<16; n+=sizeof(size_t)) {
|
||||
|
||||
/*
|
||||
* Some GCC version(s) of Android's NDK produce code that leads to a crash (SIGBUS). The
|
||||
* offending line if the line that produces the output by xor'ing the ivec. Somehow the
|
||||
* compiler/optimizer seems to incorrectly setup the pointers. Adding a call to an
|
||||
* external function that uses the pointer disabled or modifies this optimzing
|
||||
* behaviour. This debug functions as such does nothing, it just disables some
|
||||
* optimization. Don't use a local (static) function - the compiler sees that it does
|
||||
* nothing and optimizes again :-) .
|
||||
*/
|
||||
#ifdef ANDROID
|
||||
Two_debugDummy(in, out, ivec);
|
||||
#endif
|
||||
*(size_t*)(out+n) = *(size_t*)(ivec+n) ^= *(size_t*)(in+n);;
|
||||
}
|
||||
len -= 16;
|
||||
out += 16;
|
||||
in += 16;
|
||||
}
|
||||
n = 0;
|
||||
if (len) {
|
||||
Twofish_encrypt(keyCtx, ivec, ivec);
|
||||
while (len--) {
|
||||
out[n] = ivec[n] ^= in[n];
|
||||
++n;
|
||||
}
|
||||
}
|
||||
*num = n;
|
||||
return;
|
||||
} while (0);
|
||||
}
|
||||
|
||||
|
||||
void Twofish_cfb128_decrypt(Twofish_key* keyCtx, Twofish_Byte* in,
|
||||
Twofish_Byte* out, size_t len,
|
||||
Twofish_Byte* ivec, int32_t *num)
|
||||
{
|
||||
uint32_t n;
|
||||
|
||||
n = *num;
|
||||
|
||||
do {
|
||||
while (n && len) {
|
||||
unsigned char c;
|
||||
*(out++) = ivec[n] ^ (c = *(in++)); ivec[n] = c;
|
||||
--len;
|
||||
n = (n+1) % 16;
|
||||
}
|
||||
while (len>=16) {
|
||||
Twofish_encrypt(keyCtx, ivec, ivec);
|
||||
for (n=0; n<16; n+=sizeof(size_t)) {
|
||||
size_t t = *(size_t*)(in+n);
|
||||
*(size_t*)(out+n) = *(size_t*)(ivec+n) ^ t;
|
||||
*(size_t*)(ivec+n) = t;
|
||||
}
|
||||
len -= 16;
|
||||
out += 16;
|
||||
in += 16;
|
||||
}
|
||||
n = 0;
|
||||
if (len) {
|
||||
Twofish_encrypt(keyCtx, ivec, ivec);
|
||||
while (len--) {
|
||||
unsigned char c;
|
||||
out[n] = ivec[n] ^ (c = in[n]); ivec[n] = c;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
*num = n;
|
||||
return;
|
||||
} while (0);
|
||||
}
|
|
@ -0,0 +1,407 @@
|
|||
diff --git a/libs/libks/src/ks_dht.c b/libs/libks/src/ks_dht.c
|
||||
index 27bafd0..126686e 100644
|
||||
--- a/libs/libks/src/ks_dht.c
|
||||
+++ b/libs/libks/src/ks_dht.c
|
||||
@@ -2438,96 +2438,84 @@ static int dht_send(dht_handle_t *h, const void *buf, size_t len, int flags, con
|
||||
return sendto(s, buf, len, flags, sa, salen);
|
||||
}
|
||||
|
||||
+/* Sample ping packet '{"t":"aa", "y":"q", "q":"ping", "a":{"id":"abcdefghij0123456789"}}' */
|
||||
+/* http://www.bittorrent.org/beps/bep_0005.html */
|
||||
int send_ping(dht_handle_t *h, const struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
|
||||
{
|
||||
char buf[512];
|
||||
- int i = 0;//, rc;
|
||||
- struct bencode *bencode_p = NULL;
|
||||
- struct bencode *bencode_a_p = NULL;
|
||||
-
|
||||
- /* Sets some default values for message, then encodes 20 characters worth of local node id */
|
||||
- /* also adds the transaction id tid, then a few final key values. */
|
||||
-
|
||||
- /* Sample encoded ping 'd1:ad2:id20:Td2????#?)y1:q4:ping1:t4:pn' */
|
||||
- /* 'd1:ad2:id20:Td2????#?)y1:q4:ping1:t4:pn' */
|
||||
- /* https://en.wikipedia.org/wiki/Bencode */
|
||||
- /* Sample ping packet '{"t":"aa", "y":"q", "q":"ping", "a":{"id":"abcdefghij0123456789"}}' */
|
||||
- /* http://www.bittorrent.org/beps/bep_0005.html */
|
||||
+ int i = 0;
|
||||
+ struct bencode *bencode_p = ben_dict();
|
||||
+ struct bencode *bencode_a_p = ben_dict();
|
||||
|
||||
- bencode_a_p = ben_dict(); /* Initialize empty bencode dictionary */
|
||||
+ ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
|
||||
+ ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("q", 1));
|
||||
+ ben_dict_set(bencode_p, ben_blob("q", 1), ben_blob("ping", 4));
|
||||
ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
|
||||
-
|
||||
- bencode_p = ben_dict();
|
||||
ben_dict_set(bencode_p, ben_blob("a", 1), bencode_a_p);
|
||||
- ben_dict_set(bencode_p, ben_blob("q", 1), ben_blob("ping", 4));
|
||||
- ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
|
||||
- ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("q", 1));
|
||||
|
||||
- /*
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512);
|
||||
- COPY(buf, i, h->myid, 20, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "e1:q4:ping1:t%d:", tid_len);
|
||||
- INC(i, rc, 512);
|
||||
- COPY(buf, i, tid, tid_len, 512);
|
||||
- ADD_V(buf, i, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512);
|
||||
- */
|
||||
ben_encode2(buf, 512, bencode_p);
|
||||
ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
|
||||
|
||||
ks_log(KS_LOG_DEBUG, "Encoded PING: %s\n\n", buf);
|
||||
return dht_send(h, buf, i, 0, sa, salen);
|
||||
-
|
||||
- /*
|
||||
- // Need to fix, not just disable error handling.
|
||||
- fail:
|
||||
- errno = ENOSPC;
|
||||
- return -1; */
|
||||
}
|
||||
|
||||
+/* Sample pong packet '{"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}}' */
|
||||
+/* http://www.bittorrent.org/beps/bep_0005.html */
|
||||
int send_pong(dht_handle_t *h, const struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
|
||||
{
|
||||
char buf[512];
|
||||
- int i = 0, rc;
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "d1:rd2:id20:"); INC(i, rc, 512);
|
||||
- COPY(buf, i, h->myid, 20, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "e1:t%d:", tid_len); INC(i, rc, 512);
|
||||
- COPY(buf, i, tid, tid_len, 512);
|
||||
- ADD_V(buf, i, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "1:y1:re"); INC(i, rc, 512);
|
||||
- return dht_send(h, buf, i, 0, sa, salen);
|
||||
+ int i = 0;
|
||||
+ struct bencode *bencode_p = ben_dict();
|
||||
+ struct bencode *bencode_a_p = ben_dict();
|
||||
|
||||
- fail:
|
||||
- errno = ENOSPC;
|
||||
- return -1;
|
||||
+ ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
|
||||
+ ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("r", 1));
|
||||
+ ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
|
||||
+ ben_dict_set(bencode_p, ben_blob("r", 1), bencode_a_p);
|
||||
+
|
||||
+ ben_encode2(buf, 512, bencode_p);
|
||||
+ ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
|
||||
+
|
||||
+ ks_log(KS_LOG_DEBUG, "Encoded PONG: %s\n\n", buf);
|
||||
+ return dht_send(h, buf, i, 0, sa, salen);
|
||||
}
|
||||
|
||||
+/* Sample find_node packet '{"t":"aa", "y":"q", "q":"find_node", "a": {"id":"abcdefghij0123456789", "target":"mnopqrstuvwxyz123456"}}' */
|
||||
+/* Sample find_node packet w/ want '{"t":"aa", "y":"q", "q":"find_node", "a": {"id":"abcdefghij0123456789", "target":"mnopqrstuvwxyz123456", "want":"n4"}}' */
|
||||
+/* http://www.bittorrent.org/beps/bep_0005.html */
|
||||
+/* http://www.bittorrent.org/beps/bep_0032.html for want parameter */
|
||||
int send_find_node(dht_handle_t *h, const struct sockaddr *sa, int salen,
|
||||
const unsigned char *tid, int tid_len,
|
||||
const unsigned char *target, int want, int confirm)
|
||||
{
|
||||
char buf[512];
|
||||
- int i = 0, rc;
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512);
|
||||
- COPY(buf, i, h->myid, 20, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "6:target20:"); INC(i, rc, 512);
|
||||
- COPY(buf, i, target, 20, 512);
|
||||
- if (want > 0) {
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "4:wantl%s%se", (want & WANT4) ? "2:n4" : "", (want & WANT6) ? "2:n6" : "");
|
||||
- INC(i, rc, 512);
|
||||
- }
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "e1:q9:find_node1:t%d:", tid_len);
|
||||
- INC(i, rc, 512);
|
||||
- COPY(buf, i, tid, tid_len, 512);
|
||||
- ADD_V(buf, i, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512);
|
||||
- return dht_send(h, buf, i, confirm ? MSG_CONFIRM : 0, sa, salen);
|
||||
+ int i = 0;
|
||||
+ struct bencode *bencode_p = ben_dict();
|
||||
+ struct bencode *bencode_a_p = ben_dict();
|
||||
+ int target_len = target ? strlen((const char*)target) : 0;
|
||||
|
||||
- fail:
|
||||
- errno = ENOSPC;
|
||||
- return -1;
|
||||
-}
|
||||
+ ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
|
||||
+ ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("q", 1));
|
||||
+ ben_dict_set(bencode_p, ben_blob("q", 1), ben_blob("find_node", 9));
|
||||
+ ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
|
||||
+ if (target) ben_dict_set(bencode_a_p, ben_blob("target", 6), ben_blob(target, target_len));
|
||||
+ if (want > 0) {
|
||||
+ char *w = NULL;
|
||||
+ if (want & WANT4) w = "n4";
|
||||
+ if (want & WANT6) w = "n6";
|
||||
+ if (w) ben_dict_set(bencode_a_p, ben_blob("want", 4), ben_blob(w, 2));
|
||||
+ }
|
||||
+ ben_dict_set(bencode_p, ben_blob("a", 1), bencode_a_p);
|
||||
|
||||
+ ben_encode2(buf, 512, bencode_p);
|
||||
+ ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
|
||||
+
|
||||
+ ks_log(KS_LOG_DEBUG, "Encoded FIND_NODE: %s\n\n", buf);
|
||||
+ return dht_send(h, buf, i, confirm ? MSG_CONFIRM : 0, sa, salen);
|
||||
+}
|
||||
+/* sample find_node response '{"t":"aa", "y":"r", "r": {"id":"0123456789abcdefghij", "nodes": "def456..."}}'*/
|
||||
+/* http://www.bittorrent.org/beps/bep_0005.html */
|
||||
int send_nodes_peers(dht_handle_t *h, const struct sockaddr *sa, int salen,
|
||||
const unsigned char *tid, int tid_len,
|
||||
const unsigned char *nodes, int nodes_len,
|
||||
@@ -2536,30 +2524,28 @@ int send_nodes_peers(dht_handle_t *h, const struct sockaddr *sa, int salen,
|
||||
const unsigned char *token, int token_len)
|
||||
{
|
||||
char buf[2048];
|
||||
- int i = 0, rc, j0, j, k, len;
|
||||
+ int i = 0;//, rc, j0, j, k, len;
|
||||
+ struct bencode *bencode_p = ben_dict();
|
||||
+ struct bencode *bencode_a_p = ben_dict();
|
||||
+ struct bencode *ben_array = ben_list();
|
||||
|
||||
- rc = ks_snprintf(buf + i, 2048 - i, "d1:rd2:id20:"); INC(i, rc, 2048);
|
||||
- COPY(buf, i, h->myid, 20, 2048);
|
||||
- if (nodes_len > 0) {
|
||||
- rc = ks_snprintf(buf + i, 2048 - i, "5:nodes%d:", nodes_len);
|
||||
- INC(i, rc, 2048);
|
||||
- COPY(buf, i, nodes, nodes_len, 2048);
|
||||
- }
|
||||
- if (nodes6_len > 0) {
|
||||
- rc = ks_snprintf(buf + i, 2048 - i, "6:nodes6%d:", nodes6_len);
|
||||
- INC(i, rc, 2048);
|
||||
- COPY(buf, i, nodes6, nodes6_len, 2048);
|
||||
- }
|
||||
- if (token_len > 0) {
|
||||
- rc = ks_snprintf(buf + i, 2048 - i, "5:token%d:", token_len);
|
||||
- INC(i, rc, 2048);
|
||||
- COPY(buf, i, token, token_len, 2048);
|
||||
- }
|
||||
+ ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
|
||||
+ ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("r", 1));
|
||||
+ ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
|
||||
+ if (token_len) ben_dict_set(bencode_a_p, ben_blob("token", 5), ben_blob(token, token_len));
|
||||
+ if (nodes_len) ben_dict_set(bencode_a_p, ben_blob("nodes", 5), ben_blob(token, nodes_len));
|
||||
+ if (nodes6_len) ben_dict_set(bencode_a_p, ben_blob("nodes6", 6), ben_blob(token, nodes6_len));
|
||||
|
||||
+ /* its an array, how do i do this??
|
||||
+
|
||||
+Response with peers = {"t":"aa", "y":"r", "r": {"id":"abcdefghij0123456789", "token":"aoeusnth", "values": ["axje.u", "idhtnm"]}}
|
||||
+ */
|
||||
+
|
||||
+ /* TODO XXXXXX find docs and add "values" stuff into this encode
|
||||
if (st && st->numpeers > 0) {
|
||||
- /* We treat the storage as a circular list, and serve a randomly
|
||||
- chosen slice. In order to make sure we fit within 1024 octets,
|
||||
- we limit ourselves to 50 peers. */
|
||||
+ // We treat the storage as a circular list, and serve a randomly
|
||||
+ // chosen slice. In order to make sure we fit within 1024 octets,
|
||||
+ // we limit ourselves to 50 peers.
|
||||
|
||||
len = af == AF_INET ? 4 : 16;
|
||||
j0 = random() % st->numpeers;
|
||||
@@ -2582,19 +2568,13 @@ int send_nodes_peers(dht_handle_t *h, const struct sockaddr *sa, int salen,
|
||||
rc = ks_snprintf(buf + i, 2048 - i, "e");
|
||||
INC(i, rc, 2048);
|
||||
}
|
||||
-
|
||||
- rc = ks_snprintf(buf + i, 2048 - i, "e1:t%d:", tid_len);
|
||||
- INC(i, rc, 2048);
|
||||
- COPY(buf, i, tid, tid_len, 2048);
|
||||
- ADD_V(buf, i, 2048);
|
||||
- rc = ks_snprintf(buf + i, 2048 - i, "1:y1:re");
|
||||
- INC(i, rc, 2048);
|
||||
-
|
||||
- return dht_send(h, buf, i, 0, sa, salen);
|
||||
-
|
||||
- fail:
|
||||
- errno = ENOSPC;
|
||||
- return -1;
|
||||
+*/
|
||||
+ ben_dict_set(bencode_p, ben_blob("r", 1), bencode_a_p);
|
||||
+ ben_encode2(buf, 512, bencode_p);
|
||||
+ ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
|
||||
+
|
||||
+ ks_log(KS_LOG_DEBUG, "Encoded FIND_NODE: %s\n\n", buf);
|
||||
+ return dht_send(h, buf, i, 0, sa, salen);
|
||||
}
|
||||
|
||||
static int insert_closest_node(unsigned char *nodes, int numnodes,
|
||||
@@ -2706,104 +2686,107 @@ int send_closest_nodes(dht_handle_t *h, const struct sockaddr *sa, int salen,
|
||||
af, st, token, token_len);
|
||||
}
|
||||
|
||||
+/* sample get_peers request '{"t":"aa", "y":"q", "q":"get_peers", "a": {"id":"abcdefghij0123456789", "info_hash":"mnopqrstuvwxyz123456"}}'*/
|
||||
+/* sample get_peers w/ want '{"t":"aa", "y":"q", "q":"get_peers", "a": {"id":"abcdefghij0123456789", "info_hash":"mnopqrstuvwxyz123456": "want":"n4"}}'*/
|
||||
+/* http://www.bittorrent.org/beps/bep_0005.html */
|
||||
+/* http://www.bittorrent.org/beps/bep_0032.html for want parameter */
|
||||
int send_get_peers(dht_handle_t *h, const struct sockaddr *sa, int salen,
|
||||
unsigned char *tid, int tid_len, unsigned char *infohash,
|
||||
int want, int confirm)
|
||||
{
|
||||
char buf[512];
|
||||
- int i = 0, rc;
|
||||
-
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512);
|
||||
- COPY(buf, i, h->myid, 20, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "9:info_hash20:"); INC(i, rc, 512);
|
||||
- COPY(buf, i, infohash, 20, 512);
|
||||
- if (want > 0) {
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "4:wantl%s%se", (want & WANT4) ? "2:n4" : "", (want & WANT6) ? "2:n6" : "");
|
||||
- INC(i, rc, 512);
|
||||
- }
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "e1:q9:get_peers1:t%d:", tid_len);
|
||||
- INC(i, rc, 512);
|
||||
- COPY(buf, i, tid, tid_len, 512);
|
||||
- ADD_V(buf, i, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512);
|
||||
- return dht_send(h, buf, i, confirm ? MSG_CONFIRM : 0, sa, salen);
|
||||
+ int i = 0;
|
||||
+ struct bencode *bencode_p = ben_dict();
|
||||
+ struct bencode *bencode_a_p = ben_dict();
|
||||
+ int infohash_len = infohash ? strlen((const char*)infohash) : 0;
|
||||
|
||||
- fail:
|
||||
- errno = ENOSPC;
|
||||
- return -1;
|
||||
-}
|
||||
+ ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
|
||||
+ ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("q", 1));
|
||||
+ ben_dict_set(bencode_p, ben_blob("q", 1), ben_blob("get_peers", 9));
|
||||
+ ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
|
||||
+ if (want > 0) {
|
||||
+ char *w = NULL;
|
||||
+ if (want & WANT4) w = "n4";
|
||||
+ if (want & WANT6) w = "n6";
|
||||
+ if (w) ben_dict_set(bencode_a_p, ben_blob("want", 4), ben_blob(w, 2));
|
||||
+ }
|
||||
+ ben_dict_set(bencode_a_p, ben_blob("info_hash", 9), ben_blob(infohash, infohash_len));
|
||||
+ ben_dict_set(bencode_p, ben_blob("a", 1), bencode_a_p);
|
||||
|
||||
+ ben_encode2(buf, 512, bencode_p);
|
||||
+ ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
|
||||
+
|
||||
+ ks_log(KS_LOG_DEBUG, "Encoded GET_PEERS: %s\n\n", buf);
|
||||
+ return dht_send(h, buf, i, confirm ? MSG_CONFIRM : 0, sa, salen);
|
||||
+}
|
||||
+/* '{"t":"aa", "y":"q", "q":"announce_peer", "a": {"id":"abcdefghij0123456789", "implied_port": 1, "info_hash":"mnopqrstuvwxyz123456", "port": 6881, "token": "aoeusnth"}}'*/
|
||||
int send_announce_peer(dht_handle_t *h, const struct sockaddr *sa, int salen,
|
||||
unsigned char *tid, int tid_len,
|
||||
unsigned char *infohash, unsigned short port,
|
||||
unsigned char *token, int token_len, int confirm)
|
||||
{
|
||||
char buf[512];
|
||||
- int i = 0, rc;
|
||||
-
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512);
|
||||
- COPY(buf, i, h->myid, 20, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "9:info_hash20:"); INC(i, rc, 512);
|
||||
- COPY(buf, i, infohash, 20, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "4:porti%ue5:token%d:", (unsigned)port, token_len);
|
||||
- INC(i, rc, 512);
|
||||
- COPY(buf, i, token, token_len, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "e1:q13:announce_peer1:t%d:", tid_len);
|
||||
- INC(i, rc, 512);
|
||||
- COPY(buf, i, tid, tid_len, 512);
|
||||
- ADD_V(buf, i, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512);
|
||||
+ int i = 0;
|
||||
+ struct bencode *bencode_p = ben_dict();
|
||||
+ struct bencode *bencode_a_p = ben_dict();
|
||||
+ int infohash_len = infohash ? strlen((const char*)infohash) : 0;
|
||||
|
||||
- return dht_send(h, buf, i, confirm ? MSG_CONFIRM : 0, sa, salen);
|
||||
+ ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
|
||||
+ ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("q", 1));
|
||||
+ ben_dict_set(bencode_p, ben_blob("q", 1), ben_blob("announce_peer", 13));
|
||||
+ ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
|
||||
+ ben_dict_set(bencode_a_p, ben_blob("info_hash", 9), ben_blob(infohash, infohash_len));
|
||||
+ ben_dict_set(bencode_a_p, ben_blob("port", 5), ben_int(port));
|
||||
+ ben_dict_set(bencode_a_p, ben_blob("token", 5), ben_blob(token, token_len));
|
||||
+ ben_dict_set(bencode_p, ben_blob("a", 1), bencode_a_p);
|
||||
|
||||
- fail:
|
||||
- errno = ENOSPC;
|
||||
- return -1;
|
||||
+ ben_encode2(buf, 512, bencode_p);
|
||||
+ ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
|
||||
+
|
||||
+ ks_log(KS_LOG_DEBUG, "Encoded ANNOUNCE_PEERS: %s\n\n", buf);
|
||||
+ return dht_send(h, buf, i, confirm ? MSG_CONFIRM : 0, sa, salen);
|
||||
}
|
||||
-
|
||||
+/* '{"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}}'*/
|
||||
static int send_peer_announced(dht_handle_t *h, const struct sockaddr *sa, int salen, unsigned char *tid, int tid_len)
|
||||
{
|
||||
char buf[512];
|
||||
- int i = 0, rc;
|
||||
-
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "d1:rd2:id20:");
|
||||
- INC(i, rc, 512);
|
||||
- COPY(buf, i, h->myid, 20, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
|
||||
- INC(i, rc, 512);
|
||||
- COPY(buf, i, tid, tid_len, 512);
|
||||
- ADD_V(buf, i, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "1:y1:re");
|
||||
- INC(i, rc, 512);
|
||||
- return dht_send(h, buf, i, 0, sa, salen);
|
||||
+ int i = 0;
|
||||
+ struct bencode *bencode_p = ben_dict();
|
||||
+ struct bencode *bencode_a_p = ben_dict();
|
||||
|
||||
- fail:
|
||||
- errno = ENOSPC;
|
||||
- return -1;
|
||||
+ ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
|
||||
+ ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("r", 1));
|
||||
+ ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
|
||||
+ ben_dict_set(bencode_p, ben_blob("r", 1), bencode_a_p);
|
||||
+
|
||||
+ ben_encode2(buf, 512, bencode_p);
|
||||
+ ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
|
||||
+
|
||||
+ ks_log(KS_LOG_DEBUG, "Encoded peer_announced: %s\n\n", buf);
|
||||
+ return dht_send(h, buf, i, 0, sa, salen);
|
||||
}
|
||||
|
||||
+/* '{"t":"aa", "y":"e", "e":[201, "A Generic Error Ocurred"]}'*/
|
||||
static int send_error(dht_handle_t *h, const struct sockaddr *sa, int salen,
|
||||
unsigned char *tid, int tid_len,
|
||||
int code, const char *message)
|
||||
{
|
||||
char buf[512];
|
||||
- int i = 0, rc, message_len;
|
||||
-
|
||||
- message_len = strlen(message);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "d1:eli%de%d:", code, message_len);
|
||||
- INC(i, rc, 512);
|
||||
- COPY(buf, i, message, message_len, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
|
||||
- INC(i, rc, 512);
|
||||
- COPY(buf, i, tid, tid_len, 512);
|
||||
- ADD_V(buf, i, 512);
|
||||
- rc = ks_snprintf(buf + i, 512 - i, "1:y1:ee");
|
||||
- INC(i, rc, 512);
|
||||
- return dht_send(h, buf, i, 0, sa, salen);
|
||||
+ int i = 0;
|
||||
+ struct bencode *bencode_p = ben_dict();
|
||||
+ struct bencode *ben_array = ben_list();
|
||||
|
||||
- fail:
|
||||
- errno = ENOSPC;
|
||||
- return -1;
|
||||
+ ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
|
||||
+ ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("e", 1));
|
||||
+ ben_list_append(ben_array, ben_int(code));
|
||||
+ ben_list_append(ben_array, ben_blob(message, strlen(message)));
|
||||
+ ben_dict_set(bencode_p, ben_blob("e", 1), ben_array);
|
||||
+
|
||||
+ ben_encode2(buf, 512, bencode_p);
|
||||
+ ben_free(bencode_p);
|
||||
+
|
||||
+ ks_log(KS_LOG_DEBUG, "Encoded error: %s\n\n", buf);
|
||||
+ return dht_send(h, buf, i, 0, sa, salen);
|
||||
}
|
||||
|
||||
#undef CHECK
|
|
@ -0,0 +1,11 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: @PACKAGE_NAME@
|
||||
Version: @PACKAGE_VERSION@
|
||||
Description: A cross platform kitchen sink library.
|
||||
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lks
|
|
@ -5,9 +5,9 @@
|
|||
<PropertyGroup />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>SIMCLIST_NO_DUMPRESTORE;_CRT_SECURE_NO_WARNINGS;KS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>UNICODE;SIMCLIST_NO_DUMPRESTORE;_CRT_SECURE_NO_WARNINGS;KS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\src\include;$(ProjectDir)\src\win\sys;$(ProjectDir)\src\win;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4574;4100;4127;4668;4255;4706;4710;4820</DisableSpecificWarnings>
|
||||
<DisableSpecificWarnings>4711;4574;4100;4127;4668;4255;4706;4710;4820</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup />
|
||||
|
|
|
@ -5,10 +5,17 @@ VisualStudioVersion = 14.0.23107.0
|
|||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libks", "libks.vcxproj", "{70D178D8-1100-4152-86C0-809A91CFF832}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testpools", "test\testpools\testpools.vcxproj", "{766F7FF4-CF39-4CDF-ABDC-4E9C88568F1F}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{70D178D8-1100-4152-86C0-809A91CFF832} = {70D178D8-1100-4152-86C0-809A91CFF832}
|
||||
EndProjectSection
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testpools", "test\testpools.vcxproj", "{5825A3B2-31A0-475A-AF32-44FB0D8B52D4}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testthreadmutex", "test\testthreadmutex.vcxproj", "{AE572500-7266-4692-ACA4-5E37B7B4409A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testhash", "test\testhash.vcxproj", "{43724CF4-FCE1-44FE-AB36-C86E3979B350}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testq", "test\testq.vcxproj", "{3F8E0DF3-F402-40E0-8D78-44A094625D25}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsock", "test\testsock.vcxproj", "{5DC38E2B-0512-4140-8A1B-59952A5DC9CB}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testtime", "test\testtime.vcxproj", "{B74812A1-C67D-4568-AF84-26CE2004D8BF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -26,14 +33,54 @@ Global
|
|||
{70D178D8-1100-4152-86C0-809A91CFF832}.Release|x64.Build.0 = Release|x64
|
||||
{70D178D8-1100-4152-86C0-809A91CFF832}.Release|x86.ActiveCfg = Release|Win32
|
||||
{70D178D8-1100-4152-86C0-809A91CFF832}.Release|x86.Build.0 = Release|Win32
|
||||
{766F7FF4-CF39-4CDF-ABDC-4E9C88568F1F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{766F7FF4-CF39-4CDF-ABDC-4E9C88568F1F}.Debug|x64.Build.0 = Debug|x64
|
||||
{766F7FF4-CF39-4CDF-ABDC-4E9C88568F1F}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{766F7FF4-CF39-4CDF-ABDC-4E9C88568F1F}.Debug|x86.Build.0 = Debug|Win32
|
||||
{766F7FF4-CF39-4CDF-ABDC-4E9C88568F1F}.Release|x64.ActiveCfg = Release|x64
|
||||
{766F7FF4-CF39-4CDF-ABDC-4E9C88568F1F}.Release|x64.Build.0 = Release|x64
|
||||
{766F7FF4-CF39-4CDF-ABDC-4E9C88568F1F}.Release|x86.ActiveCfg = Release|Win32
|
||||
{766F7FF4-CF39-4CDF-ABDC-4E9C88568F1F}.Release|x86.Build.0 = Release|Win32
|
||||
{5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Debug|x64.Build.0 = Debug|x64
|
||||
{5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Debug|x86.Build.0 = Debug|Win32
|
||||
{5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Release|x64.ActiveCfg = Release|x64
|
||||
{5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Release|x64.Build.0 = Release|x64
|
||||
{5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Release|x86.ActiveCfg = Release|Win32
|
||||
{5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Release|x86.Build.0 = Release|Win32
|
||||
{AE572500-7266-4692-ACA4-5E37B7B4409A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AE572500-7266-4692-ACA4-5E37B7B4409A}.Debug|x64.Build.0 = Debug|x64
|
||||
{AE572500-7266-4692-ACA4-5E37B7B4409A}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{AE572500-7266-4692-ACA4-5E37B7B4409A}.Debug|x86.Build.0 = Debug|Win32
|
||||
{AE572500-7266-4692-ACA4-5E37B7B4409A}.Release|x64.ActiveCfg = Release|x64
|
||||
{AE572500-7266-4692-ACA4-5E37B7B4409A}.Release|x64.Build.0 = Release|x64
|
||||
{AE572500-7266-4692-ACA4-5E37B7B4409A}.Release|x86.ActiveCfg = Release|Win32
|
||||
{AE572500-7266-4692-ACA4-5E37B7B4409A}.Release|x86.Build.0 = Release|Win32
|
||||
{43724CF4-FCE1-44FE-AB36-C86E3979B350}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{43724CF4-FCE1-44FE-AB36-C86E3979B350}.Debug|x64.Build.0 = Debug|x64
|
||||
{43724CF4-FCE1-44FE-AB36-C86E3979B350}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{43724CF4-FCE1-44FE-AB36-C86E3979B350}.Debug|x86.Build.0 = Debug|Win32
|
||||
{43724CF4-FCE1-44FE-AB36-C86E3979B350}.Release|x64.ActiveCfg = Release|x64
|
||||
{43724CF4-FCE1-44FE-AB36-C86E3979B350}.Release|x64.Build.0 = Release|x64
|
||||
{43724CF4-FCE1-44FE-AB36-C86E3979B350}.Release|x86.ActiveCfg = Release|Win32
|
||||
{43724CF4-FCE1-44FE-AB36-C86E3979B350}.Release|x86.Build.0 = Release|Win32
|
||||
{3F8E0DF3-F402-40E0-8D78-44A094625D25}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3F8E0DF3-F402-40E0-8D78-44A094625D25}.Debug|x64.Build.0 = Debug|x64
|
||||
{3F8E0DF3-F402-40E0-8D78-44A094625D25}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{3F8E0DF3-F402-40E0-8D78-44A094625D25}.Debug|x86.Build.0 = Debug|Win32
|
||||
{3F8E0DF3-F402-40E0-8D78-44A094625D25}.Release|x64.ActiveCfg = Release|x64
|
||||
{3F8E0DF3-F402-40E0-8D78-44A094625D25}.Release|x64.Build.0 = Release|x64
|
||||
{3F8E0DF3-F402-40E0-8D78-44A094625D25}.Release|x86.ActiveCfg = Release|Win32
|
||||
{3F8E0DF3-F402-40E0-8D78-44A094625D25}.Release|x86.Build.0 = Release|Win32
|
||||
{5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Debug|x64.Build.0 = Debug|x64
|
||||
{5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Debug|x86.Build.0 = Debug|Win32
|
||||
{5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Release|x64.ActiveCfg = Release|x64
|
||||
{5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Release|x64.Build.0 = Release|x64
|
||||
{5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Release|x86.ActiveCfg = Release|Win32
|
||||
{5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Release|x86.Build.0 = Release|Win32
|
||||
{B74812A1-C67D-4568-AF84-26CE2004D8BF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B74812A1-C67D-4568-AF84-26CE2004D8BF}.Debug|x64.Build.0 = Debug|x64
|
||||
{B74812A1-C67D-4568-AF84-26CE2004D8BF}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{B74812A1-C67D-4568-AF84-26CE2004D8BF}.Debug|x86.Build.0 = Debug|Win32
|
||||
{B74812A1-C67D-4568-AF84-26CE2004D8BF}.Release|x64.ActiveCfg = Release|x64
|
||||
{B74812A1-C67D-4568-AF84-26CE2004D8BF}.Release|x64.Build.0 = Release|x64
|
||||
{B74812A1-C67D-4568-AF84-26CE2004D8BF}.Release|x86.ActiveCfg = Release|Win32
|
||||
{B74812A1-C67D-4568-AF84-26CE2004D8BF}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -27,22 +27,26 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -72,7 +76,8 @@
|
|||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<LinkIncremental>
|
||||
</LinkIncremental>
|
||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
|
@ -84,6 +89,8 @@
|
|||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
|
@ -98,6 +105,8 @@
|
|||
<WarningLevel>EnableAllWarnings</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
|
@ -111,31 +120,49 @@
|
|||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBKS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<WarningLevel>EnableAllWarnings</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>Debug</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBKS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>EnableAllWarnings</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\ks.c" />
|
||||
<ClCompile Include="src\ks_buffer.c" />
|
||||
<ClCompile Include="src\ks_config.c" />
|
||||
<ClCompile Include="src\ks_dso.c" />
|
||||
<ClCompile Include="src\ks_hash.c" />
|
||||
<ClCompile Include="src\ks_json.c" />
|
||||
<ClCompile Include="src\ks_threadmutex.c" />
|
||||
<ClCompile Include="src\mpool.c" />
|
||||
<ClCompile Include="src\ks_log.c" />
|
||||
<ClCompile Include="src\ks_pool.c" />
|
||||
<ClCompile Include="src\ks_printf.c" />
|
||||
<ClCompile Include="src\ks_q.c" />
|
||||
<ClCompile Include="src\ks_rng.c" />
|
||||
<ClCompile Include="src\ks_socket.c" />
|
||||
<ClCompile Include="src\ks_string.c" />
|
||||
<ClCompile Include="src\ks_thread.c" />
|
||||
<ClCompile Include="src\ks_mutex.c" />
|
||||
<ClCompile Include="src\ks_time.c" />
|
||||
<ClCompile Include="src\simclist.c" />
|
||||
<ClCompile Include="src\table.c" />
|
||||
<ClCompile Include="src\table_util.c" />
|
||||
<ClCompile Include="src\win\mman.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\include\cc.h" />
|
||||
<ClInclude Include="src\include\ks.h" />
|
||||
<ClInclude Include="src\include\ks_buffer.h" />
|
||||
<ClInclude Include="src\include\ks_config.h" />
|
||||
|
@ -143,14 +170,12 @@
|
|||
<ClInclude Include="src\include\ks_platform.h" />
|
||||
<ClInclude Include="src\include\ks_threadmutex.h" />
|
||||
<ClInclude Include="src\include\ks_types.h" />
|
||||
<ClInclude Include="src\include\mpool.h" />
|
||||
<ClInclude Include="src\include\mpool_loc.h" />
|
||||
<ClInclude Include="src\include\ks_pool.h" />
|
||||
<ClInclude Include="src\include\ks_rng.h" />
|
||||
<ClInclude Include="src\include\simclist.h" />
|
||||
<ClInclude Include="src\include\table.h" />
|
||||
<ClInclude Include="src\include\table_loc.h" />
|
||||
<ClInclude Include="src\win\mman.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
<ClCompile Include="src\ks.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_string.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_socket.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_buffer.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -27,29 +33,44 @@
|
|||
<ClCompile Include="src\ks_json.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_threadmutex.c">
|
||||
<ClCompile Include="src\ks_log.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\mpool.c">
|
||||
<ClCompile Include="src\ks_mutex.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\simclist.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\table.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\table_util.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\win\mman.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_pool.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_rng.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_thread.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_dso.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_hash.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_printf.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_q.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ks_time.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\include\cc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\include\ks.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -65,10 +86,10 @@
|
|||
<ClInclude Include="src\include\ks_threadmutex.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\include\mpool.h">
|
||||
<ClInclude Include="src\include\ks_pool.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\include\mpool_loc.h">
|
||||
<ClInclude Include="src\include\ks_rng.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\include\simclist.h">
|
||||
|
@ -90,4 +111,4 @@
|
|||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,44 +34,54 @@
|
|||
#ifndef _KS_H_
|
||||
#define _KS_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#ifdef __cplusplus
|
||||
#define KS_BEGIN_EXTERN_C extern "C" {
|
||||
#define KS_END_EXTERN_C }
|
||||
#else
|
||||
#define KS_BEGIN_EXTERN_C
|
||||
#define KS_END_EXTERN_C
|
||||
#endif
|
||||
|
||||
#include <ks_platform.h>
|
||||
#include <ks_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
#define ks_copy_string(_x, _y, _z) strncpy(_x, _y, _z - 1)
|
||||
#define ks_set_string(_x, _y) ks_copy_string(_x, _y, sizeof(_x))
|
||||
|
||||
|
||||
#if (_MSC_VER >= 1400) // VC8+
|
||||
#define ks_assert(expr) assert(expr);__analysis_assume( expr )
|
||||
#endif
|
||||
|
||||
#ifndef ks_assert
|
||||
#define ks_assert(_x) assert(_x)
|
||||
#endif
|
||||
|
||||
#define ks_safe_free(_x) if (_x) free(_x); _x = NULL
|
||||
#define ks_strlen_zero(s) (!s || *(s) == '\0')
|
||||
#define ks_strlen_zero_buf(s) (*(s) == '\0')
|
||||
#define end_of(_s) *(*_s == '\0' ? _s : _s + strlen(_s) - 1)
|
||||
|
||||
#include "math.h"
|
||||
#include "ks_json.h"
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
#define BUF_CHUNK 65536 * 50
|
||||
#define BUF_START 65536 * 100
|
||||
|
||||
#include <ks_threadmutex.h>
|
||||
#include <ks_buffer.h>
|
||||
|
||||
/*!
|
||||
\brief Test for NULL or zero length string
|
||||
\param s the string to test
|
||||
\return true value if the string is NULL or zero length
|
||||
*/
|
||||
_Check_return_ static __inline int _zstr(_In_opt_z_ const char *s)
|
||||
{
|
||||
return !s || *s == '\0';
|
||||
}
|
||||
#ifdef _PREFAST_
|
||||
#define zstr(x) (_zstr(x) ? 1 : __analysis_assume(x),0)
|
||||
#else
|
||||
#define zstr(x) _zstr(x)
|
||||
#endif
|
||||
#define ks_strlen_zero(x) zstr(x)
|
||||
#define ks_strlen_zero_buf(x) zstr_buf(x)
|
||||
#define zstr_buf(s) (*(s) == '\0')
|
||||
|
||||
#define ks_set_string(_x, _y) ks_copy_string(_x, _y, sizeof(_x))
|
||||
#define ks_safe_free(_x) if (_x) free(_x); _x = NULL
|
||||
#define end_of(_s) *(*_s == '\0' ? _s : _s + strlen(_s) - 1)
|
||||
#define ks_test_flag(obj, flag) ((obj)->flags & flag)
|
||||
#define ks_set_flag(obj, flag) (obj)->flags |= (flag)
|
||||
#define ks_clear_flag(obj, flag) (obj)->flags &= ~(flag)
|
||||
#define ks_recv(_h) ks_recv_event(_h, 0, NULL)
|
||||
#define ks_recv_timed(_h, _ms) ks_recv_event_timed(_h, _ms, 0, NULL)
|
||||
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_init(void);
|
||||
KS_DECLARE(ks_status_t) ks_shutdown(void);
|
||||
KS_DECLARE(ks_pool_t *) ks_global_pool(void);
|
||||
KS_DECLARE(ks_status_t) ks_global_set_cleanup(ks_pool_cleanup_fn_t fn, void *arg);
|
||||
KS_DECLARE(int) ks_vasprintf(char **ret, const char *fmt, va_list ap);
|
||||
|
||||
KS_DECLARE_DATA extern ks_logger_t ks_log;
|
||||
|
@ -81,42 +91,46 @@ KS_DECLARE(void) ks_global_set_logger(ks_logger_t logger);
|
|||
/*! Sets the default log level for libks */
|
||||
KS_DECLARE(void) ks_global_set_default_logger(int level);
|
||||
|
||||
|
||||
#include "ks_threadmutex.h"
|
||||
#include "ks_config.h"
|
||||
#include "ks_buffer.h"
|
||||
#include "mpool.h"
|
||||
#include "simclist.h"
|
||||
#include "table.h"
|
||||
|
||||
KS_DECLARE(size_t) ks_url_encode(const char *url, char *buf, size_t len);
|
||||
KS_DECLARE(char *)ks_url_decode(char *s);
|
||||
KS_DECLARE(const char *)ks_stristr(const char *instr, const char *str);
|
||||
KS_DECLARE(char *) ks_url_decode(char *s);
|
||||
KS_DECLARE(const char *) ks_stristr(const char *instr, const char *str);
|
||||
KS_DECLARE(int) ks_toupper(int c);
|
||||
KS_DECLARE(int) ks_tolower(int c);
|
||||
KS_DECLARE(char *) ks_copy_string(char *from_str, const char *to_str, ks_size_t from_str_len);
|
||||
KS_DECLARE(int) ks_snprintf(char *buffer, size_t count, const char *fmt, ...);
|
||||
KS_DECLARE(unsigned int) ks_separate_string(char *buf, const char *delim, char **array, unsigned int arraylen);
|
||||
KS_DECLARE(int) ks_cpu_count(void);
|
||||
static __inline__ int ks_safe_strcasecmp(const char *s1, const char *s2) {
|
||||
if (!(s1 && s2)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
KS_DECLARE(int) ks_wait_sock(ks_socket_t sock, uint32_t ms, ks_poll_t flags);
|
||||
|
||||
KS_DECLARE(unsigned int) ks_separate_string_string(char *buf, const char *delim, char **array, unsigned int arraylen);
|
||||
|
||||
#define ks_recv(_h) ks_recv_event(_h, 0, NULL)
|
||||
#define ks_recv_timed(_h, _ms) ks_recv_event_timed(_h, _ms, 0, NULL)
|
||||
|
||||
static __inline__ int ks_safe_strcasecmp(const char *s1, const char *s2)
|
||||
{
|
||||
if (!(s1 && s2)) {
|
||||
return 1;
|
||||
return strcasecmp(s1, s2);
|
||||
}
|
||||
|
||||
return strcasecmp(s1, s2);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* defined(__cplusplus) */
|
||||
KS_DECLARE(void) ks_random_string(char *buf, uint16_t len, char *set);
|
||||
|
||||
#include "ks_pool.h"
|
||||
#include "ks_printf.h"
|
||||
#include "ks_json.h"
|
||||
#include "ks_threadmutex.h"
|
||||
#include "ks_hash.h"
|
||||
#include "ks_config.h"
|
||||
#include "ks_q.h"
|
||||
#include "ks_buffer.h"
|
||||
#include "ks_time.h"
|
||||
#include "ks_socket.h"
|
||||
#include "ks_dso.h"
|
||||
#include "ks_dht.h"
|
||||
#include "ks_utp.h"
|
||||
#include "simclist.h"
|
||||
#include "ks_ssl.h"
|
||||
#include "kws.h"
|
||||
#include "ks_bencode.h"
|
||||
#include "ks_rng.h"
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* defined(_KS_H_) */
|
||||
|
||||
|
|
|
@ -0,0 +1,730 @@
|
|||
/*
|
||||
* libbencodetools
|
||||
*
|
||||
* Written by Heikki Orsila <heikki.orsila@iki.fi> and
|
||||
* Janne Kulmala <janne.t.kulmala@tut.fi> in 2011.
|
||||
*/
|
||||
|
||||
#ifndef TYPEVALIDATOR_BENCODE_H
|
||||
#define TYPEVALIDATOR_BENCODE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Used to verify format strings in compile time */
|
||||
#ifdef __GNUC__
|
||||
#define BEN_CHECK_FORMAT(...) __attribute__ ((format( __VA_ARGS__ )))
|
||||
#else
|
||||
#define BEN_CHECK_FORMAT(args)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
BENCODE_BOOL = 1,
|
||||
BENCODE_DICT,
|
||||
BENCODE_INT,
|
||||
BENCODE_LIST,
|
||||
BENCODE_STR,
|
||||
BENCODE_USER,
|
||||
};
|
||||
|
||||
enum {
|
||||
BEN_OK = 0, /* No errors. Set to zero. Non-zero implies an error. */
|
||||
BEN_INVALID, /* Invalid data was given to decoder */
|
||||
BEN_INSUFFICIENT, /* Insufficient amount of data for decoding */
|
||||
BEN_NO_MEMORY, /* Memory allocation failed */
|
||||
BEN_MISMATCH, /* A given structure did not match unpack format */
|
||||
};
|
||||
|
||||
struct bencode {
|
||||
char type;
|
||||
};
|
||||
|
||||
struct bencode_bool {
|
||||
char type;
|
||||
char b;
|
||||
};
|
||||
|
||||
struct bencode_dict_node {
|
||||
long long hash;
|
||||
struct bencode *key;
|
||||
struct bencode *value;
|
||||
size_t next;
|
||||
};
|
||||
|
||||
struct bencode_dict {
|
||||
char type;
|
||||
char shared; /* non-zero means that the internal data is shared with
|
||||
other instances and should not be freed */
|
||||
size_t n;
|
||||
size_t alloc;
|
||||
size_t *buckets;
|
||||
struct bencode_dict_node *nodes;
|
||||
};
|
||||
|
||||
struct bencode_int {
|
||||
char type;
|
||||
long long ll;
|
||||
};
|
||||
|
||||
struct bencode_list {
|
||||
char type;
|
||||
char shared; /* non-zero means that the internal data is shared with
|
||||
other instances and should not be freed */
|
||||
size_t n;
|
||||
size_t alloc;
|
||||
struct bencode **values;
|
||||
};
|
||||
|
||||
struct bencode_str {
|
||||
char type;
|
||||
size_t len;
|
||||
char *s;
|
||||
};
|
||||
|
||||
struct ben_decode_ctx;
|
||||
struct ben_encode_ctx;
|
||||
|
||||
struct bencode_type {
|
||||
size_t size;
|
||||
struct bencode *(*decode) (struct ben_decode_ctx *ctx);
|
||||
int (*encode) (struct ben_encode_ctx *ctx, const struct bencode *b);
|
||||
size_t (*get_size) (const struct bencode *b);
|
||||
void (*free) (struct bencode *b);
|
||||
int (*cmp) (const struct bencode *a, const struct bencode *b);
|
||||
};
|
||||
|
||||
struct bencode_user {
|
||||
char type;
|
||||
struct bencode_type *info;
|
||||
};
|
||||
|
||||
struct bencode_error {
|
||||
int error; /* 0 if no errors */
|
||||
int line; /* Error line: 0 is the first line */
|
||||
size_t off; /* Error offset in bytes from the start */
|
||||
};
|
||||
|
||||
/* Allocate an instance of a user-defined type */
|
||||
void *ben_alloc_user(struct bencode_type *type);
|
||||
|
||||
/*
|
||||
* Try to set capacity of a list or a dict to 'n' objects.
|
||||
* The function does nothing if 'n' is less than or equal to the number of
|
||||
* objects in 'b'. That is, nothing happens if n <= ben_{dict|list}_len(b).
|
||||
*
|
||||
* This function is used only for advice. The implementation need not obey it.
|
||||
*
|
||||
* The function returns 0 if the new capacity is used, otherwise -1.
|
||||
*
|
||||
* Note: This can be used to make construction of lists and dicts
|
||||
* more efficient when the number of inserted items is known in advance.
|
||||
*/
|
||||
int ben_allocate(struct bencode *b, size_t n);
|
||||
|
||||
/*
|
||||
* Returns an identical but a separate copy of structure b. Returns NULL if
|
||||
* there is no memory to make a copy. The copy is made recursively.
|
||||
*/
|
||||
struct bencode *ben_clone(const struct bencode *b);
|
||||
|
||||
/*
|
||||
* Returns a weak reference copy of structure b. Only a minimum amount of
|
||||
* data is copied because the returned structure references to the same
|
||||
* internal data as the original structure. As a result, the original
|
||||
* structure must remain valid until the copy is destroyed.
|
||||
*
|
||||
* This function is used for optimization for special cases.
|
||||
*/
|
||||
struct bencode *ben_shared_clone(const struct bencode *b);
|
||||
|
||||
/*
|
||||
* ben_cmp() is similar to strcmp(). It compares integers, strings and lists
|
||||
* similar to Python. User-defined types can be also compared.
|
||||
* Note: an integer is always less than a string.
|
||||
*
|
||||
* ben_cmp(a, b) returns a negative value if "a < b", 0 if "a == b",
|
||||
* or a positive value if "a > b".
|
||||
*
|
||||
* Algorithm for comparing dictionaries is:
|
||||
* If 'a' and 'b' have different number of keys or keys have different values,
|
||||
* a non-zero value is returned. Otherwise, they have the exact same keys
|
||||
* and comparison is done in ben_cmp() order of keys. The value for each key
|
||||
* is compared, and the first inequal value (ben_cmp() != 0) defines the
|
||||
* return value of the comparison.
|
||||
*
|
||||
* Note: recursive dictionaries in depth have the same issues.
|
||||
*/
|
||||
int ben_cmp(const struct bencode *a, const struct bencode *b);
|
||||
|
||||
/* Same as ben_cmp(), but the second argument is a C string */
|
||||
int ben_cmp_with_str(const struct bencode *a, const char *s);
|
||||
|
||||
/*
|
||||
* Comparison function suitable for qsort(). Uses ben_cmp(), so this can be
|
||||
* used to order both integer and string arrays.
|
||||
*/
|
||||
int ben_cmp_qsort(const void *a, const void *b);
|
||||
|
||||
/*
|
||||
* Decode 'data' with 'len' bytes of data. Returns NULL on error.
|
||||
* The encoded data must be exactly 'len' bytes (not less), otherwise NULL
|
||||
* is returned. ben_decode2() function supports partial decoding ('len' is
|
||||
* larger than actual decoded message) and gives more accurate error reports.
|
||||
*/
|
||||
struct bencode *ben_decode(const void *data, size_t len);
|
||||
|
||||
/*
|
||||
* Same as ben_decode(), but allows one to set start offset for decoding with
|
||||
* 'off' and reports errors more accurately.
|
||||
*
|
||||
* '*off' must point to decoding start offset inside 'data'.
|
||||
* If decoding is successful, '*off' is updated to point to the next byte
|
||||
* after the decoded message.
|
||||
*
|
||||
* If 'error != NULL', it is updated according to the success and error of
|
||||
* the decoding. BEN_OK is success, BEN_INVALID means invalid data.
|
||||
* BEN_INSUFFICIENT means data is invalid but could be valid if more data
|
||||
* was given for decoding. BEN_NO_MEMORY means decoding ran out of memory.
|
||||
*/
|
||||
struct bencode *ben_decode2(const void *data, size_t len, size_t *off, int *error);
|
||||
|
||||
/*
|
||||
* Same as ben_decode2(), but allows one to define user types.
|
||||
*/
|
||||
struct bencode *ben_decode3(const void *data, size_t len, size_t *off, int *error, struct bencode_type *types[128]);
|
||||
|
||||
/*
|
||||
* Same as ben_decode(), but decodes data encoded with ben_print(). This is
|
||||
* whitespace tolerant, so intended Python syntax can also be read.
|
||||
* The decoder skips comments that begin with a '#' character.
|
||||
* The comment starts from '#' character and ends at the end of the same line.
|
||||
*
|
||||
* For example, this can be used to read in config files written as a Python
|
||||
* dictionary.
|
||||
*
|
||||
* ben_decode_printed2() fills information about the error in
|
||||
* struct bencode_error.
|
||||
* error->error is 0 on success, otherwise it is an error code
|
||||
* (see ben_decode2()).
|
||||
* error->line is the line number where error occured.
|
||||
* error->off is the byte offset of error (approximation).
|
||||
*/
|
||||
struct bencode *ben_decode_printed(const void *data, size_t len);
|
||||
struct bencode *ben_decode_printed2(const void *data, size_t len, size_t *off, struct bencode_error *error);
|
||||
|
||||
/* Get the serialization size of bencode structure 'b' */
|
||||
size_t ben_encoded_size(const struct bencode *b);
|
||||
|
||||
/* encode 'b'. Return encoded data with a pointer, and length in '*len' */
|
||||
void *ben_encode(size_t *len, const struct bencode *b);
|
||||
|
||||
/*
|
||||
* encode 'b' into 'data' buffer with at most 'maxlen' bytes.
|
||||
* Returns the size of encoded data.
|
||||
*/
|
||||
size_t ben_encode2(char *data, size_t maxlen, const struct bencode *b);
|
||||
|
||||
/*
|
||||
* You must use ben_free() for all allocated bencode structures after use.
|
||||
* If b == NULL, ben_free does nothing.
|
||||
*
|
||||
* ben_free() frees all the objects contained within the bencoded structure.
|
||||
* It recursively iterates over lists and dictionaries and frees objects.
|
||||
*/
|
||||
void ben_free(struct bencode *b);
|
||||
|
||||
long long ben_str_hash(const struct bencode *b);
|
||||
long long ben_int_hash(const struct bencode *b);
|
||||
long long ben_hash(const struct bencode *b);
|
||||
|
||||
/* Create a string from binary data with len bytes */
|
||||
struct bencode *ben_blob(const void *data, size_t len);
|
||||
|
||||
/* Create a boolean from integer */
|
||||
struct bencode *ben_bool(int b);
|
||||
|
||||
/* Create an empty dictionary */
|
||||
struct bencode *ben_dict(void);
|
||||
|
||||
/*
|
||||
* Try to locate 'key' in dictionary. Returns the associated value, if found.
|
||||
* Returns NULL if the key does not exist.
|
||||
*/
|
||||
struct bencode *ben_dict_get(const struct bencode *d, const struct bencode *key);
|
||||
|
||||
struct bencode *ben_dict_get_by_str(const struct bencode *d, const char *key);
|
||||
struct bencode *ben_dict_get_by_int(const struct bencode *d, long long key);
|
||||
|
||||
struct bencode_keyvalue {
|
||||
struct bencode *key;
|
||||
struct bencode *value;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns an array of key-value pairs in key order as defined by ben_cmp().
|
||||
* Array elements are struct bencode_keyvalue members. Returns NULL if
|
||||
* the array can not be allocated or the bencode object is not a dictionary.
|
||||
* The returned array must be freed by using free(). The length of the
|
||||
* array can be determined with ben_dict_len(d).
|
||||
*
|
||||
* Warning: key and value pointers in the array are pointers to exact same
|
||||
* objects in the dictionary. Therefore, the dictionary and its key-values
|
||||
* must exist while the same keys and values are accessed from the array.
|
||||
*/
|
||||
struct bencode_keyvalue *ben_dict_ordered_items(const struct bencode *d);
|
||||
|
||||
/*
|
||||
* Try to locate 'key' in dictionary. Returns the associated value, if found.
|
||||
* The value must be later freed with ben_free(). Returns NULL if the key
|
||||
* does not exist.
|
||||
*/
|
||||
struct bencode *ben_dict_pop(struct bencode *d, const struct bencode *key);
|
||||
|
||||
struct bencode *ben_dict_pop_by_str(struct bencode *d, const char *key);
|
||||
struct bencode *ben_dict_pop_by_int(struct bencode *d, long long key);
|
||||
|
||||
/*
|
||||
* Set 'key' in dictionary to be 'value'. An old value exists for the key
|
||||
* is freed if it exists. 'key' and 'value' are owned by the dictionary
|
||||
* after a successful call (one may not call ben_free() for 'key' or
|
||||
* 'value'). One may free 'key' and 'value' if the call is unsuccessful.
|
||||
*
|
||||
* Returns 0 on success, -1 on failure (no memory).
|
||||
*/
|
||||
int ben_dict_set(struct bencode *d, struct bencode *key, struct bencode *value);
|
||||
|
||||
/* Same as ben_dict_set(), but the key is a C string */
|
||||
int ben_dict_set_by_str(struct bencode *d, const char *key, struct bencode *value);
|
||||
|
||||
/* Same as ben_dict_set(), but the key and value are C strings */
|
||||
int ben_dict_set_str_by_str(struct bencode *d, const char *key, const char *value);
|
||||
|
||||
struct bencode *ben_int(long long ll);
|
||||
|
||||
/* Create an empty list */
|
||||
struct bencode *ben_list(void);
|
||||
|
||||
/*
|
||||
* Append 'b' to 'list'. Returns 0 on success, -1 on failure (no memory).
|
||||
* One may not call ben_free(b) after a successful call, because the list owns
|
||||
* the object 'b'.
|
||||
*/
|
||||
int ben_list_append(struct bencode *list, struct bencode *b);
|
||||
|
||||
int ben_list_append_str(struct bencode *list, const char *s);
|
||||
int ben_list_append_int(struct bencode *list, long long ll);
|
||||
|
||||
/* Remove and return value at position 'pos' in list */
|
||||
struct bencode *ben_list_pop(struct bencode *list, size_t pos);
|
||||
|
||||
/*
|
||||
* Returns a Python formatted C string representation of 'b' on success,
|
||||
* NULL on failure. The returned string should be freed with free().
|
||||
*
|
||||
* Note: The string is terminated with '\0'. All instances of '\0' bytes in
|
||||
* the bencoded data are escaped so that there is only one '\0' byte
|
||||
* in the generated string at the end.
|
||||
*/
|
||||
char *ben_print(const struct bencode *b);
|
||||
|
||||
/* Create a string from C string (note bencode string may contain '\0'. */
|
||||
struct bencode *ben_str(const char *s);
|
||||
|
||||
/* Return a human readable explanation of error returned with ben_decode2() */
|
||||
const char *ben_strerror(int error);
|
||||
|
||||
/*
|
||||
* Unpack a Bencoded structure similar to scanf(). Takes a format string and
|
||||
* a list of pointers as variable arguments. The given b structure is checked
|
||||
* against the format and values are unpacked using the given specifiers.
|
||||
* A specifier begins with a percent (%) that follows a string of specifier
|
||||
* characters documented below.
|
||||
* The syntax is similar to Python format for recursive data structures, and
|
||||
* consists of tokens {, }, [, ] with any number of spaces between them.
|
||||
* The keys of a dictionary are given as literal strings or integers and
|
||||
* matched against the keys of the Bencoded structure.
|
||||
*
|
||||
* Unpack modifiers:
|
||||
* l The integer is of type long or unsigned long, and the type of the
|
||||
* argument is expected to be long * or unsigned long *.
|
||||
* ll The integer is a long long or an unsigned long long, and the
|
||||
* argument is long long * or unsigned long long *.
|
||||
* L Same as ll.
|
||||
* q Same as ll.
|
||||
*
|
||||
* Unpack specifiers:
|
||||
* %ps The Bencode value must be a string and a pointer to a string
|
||||
* (char **) is expected to be given as arguments. Note, returns a
|
||||
* reference to the internal string buffer. The returned memory should
|
||||
* not be freed and it has the same life time as the Bencode string.
|
||||
*
|
||||
* %pb Takes any structure and writes a pointer given as an argument.
|
||||
* The argument is expected to be "struct bencode **". Note, returns a
|
||||
* reference to the value inside the structure passed to ben_unpack().
|
||||
* The returned memory should not be freed and it has the same life
|
||||
* time as the original structure.
|
||||
*
|
||||
* %d The bencode value is expected to be a (signed) integer. The
|
||||
* preceeding conversion modifiers define the type of the given
|
||||
* pointer.
|
||||
|
||||
* %u The bencode value is expected to be an unsigned integer. The
|
||||
* preceeding conversion modifiers define the type of the given
|
||||
* pointer.
|
||||
*/
|
||||
int ben_unpack(const struct bencode *b, const char *fmt, ...)
|
||||
BEN_CHECK_FORMAT(scanf, 2, 3);
|
||||
|
||||
int ben_unpack2(const struct bencode *b, size_t *off, struct bencode_error *error, const char *fmt, ...)
|
||||
BEN_CHECK_FORMAT(scanf, 4, 5);
|
||||
|
||||
/*
|
||||
* Pack a Bencoded structure similar to printf(). Takes a format string and
|
||||
* a list of values as variable arguments.
|
||||
* Works similarly to ben_decode_printed(), but allows the string to values
|
||||
* specifiers which are replaced with values given as arguments.
|
||||
* A specifier begins with a percent (%) that follows a string of specifier
|
||||
* characters documented below.
|
||||
*
|
||||
* Value modifiers:
|
||||
* l The integer is of type long or unsigned long.
|
||||
* ll The integer is a long long or an unsigned long long.
|
||||
* L Same as ll.
|
||||
* q Same as ll.
|
||||
*
|
||||
* Value specifiers:
|
||||
* %s A string pointer (char *) expected to be given as argument. A new
|
||||
* Bencode string is constructed from the given string.
|
||||
*
|
||||
* %pb A Bencode structure (struct bencode *) is expected to be given as
|
||||
* argument. Note, takes ownership of the structure, even when an
|
||||
* error is returned.
|
||||
*
|
||||
* %d Constructs a new integer from the given (signed) integer. The
|
||||
* preceeding conversion modifiers define the type of the value.
|
||||
*
|
||||
* %u Constructs a new integer from the given unsigned integer. The
|
||||
* preceeding conversion modifiers define the type of the value.
|
||||
*/
|
||||
struct bencode *ben_pack(const char *fmt, ...)
|
||||
BEN_CHECK_FORMAT(printf, 1, 2);
|
||||
|
||||
/* ben_is_bool() returns 1 iff b is a boolean, 0 otherwise */
|
||||
static inline int ben_is_bool(const struct bencode *b)
|
||||
{
|
||||
return b->type == BENCODE_BOOL;
|
||||
}
|
||||
static inline int ben_is_dict(const struct bencode *b)
|
||||
{
|
||||
return b->type == BENCODE_DICT;
|
||||
}
|
||||
static inline int ben_is_int(const struct bencode *b)
|
||||
{
|
||||
return b->type == BENCODE_INT;
|
||||
}
|
||||
static inline int ben_is_list(const struct bencode *b)
|
||||
{
|
||||
return b->type == BENCODE_LIST;
|
||||
}
|
||||
static inline int ben_is_str(const struct bencode *b)
|
||||
{
|
||||
return b->type == BENCODE_STR;
|
||||
}
|
||||
static inline int ben_is_user(const struct bencode *b)
|
||||
{
|
||||
return b->type == BENCODE_USER;
|
||||
}
|
||||
|
||||
/*
|
||||
* ben_bool_const_cast(b) returns "(const struct bencode_bool *) b" if the
|
||||
* underlying object is a boolean, NULL otherwise.
|
||||
*/
|
||||
static inline const struct bencode_bool *ben_bool_const_cast(const struct bencode *b)
|
||||
{
|
||||
return b->type == BENCODE_BOOL ? ((const struct bencode_bool *) b) : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ben_bool_cast(b) returns "(struct bencode_bool *) b" if the
|
||||
* underlying object is a boolean, NULL otherwise.
|
||||
*/
|
||||
static inline struct bencode_bool *ben_bool_cast(struct bencode *b)
|
||||
{
|
||||
return b->type == BENCODE_BOOL ? ((struct bencode_bool *) b) : NULL;
|
||||
}
|
||||
|
||||
static inline const struct bencode_dict *ben_dict_const_cast(const struct bencode *b)
|
||||
{
|
||||
return b->type == BENCODE_DICT ? ((const struct bencode_dict *) b) : NULL;
|
||||
}
|
||||
static inline struct bencode_dict *ben_dict_cast(struct bencode *b)
|
||||
{
|
||||
return b->type == BENCODE_DICT ? ((struct bencode_dict *) b) : NULL;
|
||||
}
|
||||
|
||||
static inline const struct bencode_int *ben_int_const_cast(const struct bencode *i)
|
||||
{
|
||||
return i->type == BENCODE_INT ? ((const struct bencode_int *) i) : NULL;
|
||||
}
|
||||
static inline struct bencode_int *ben_int_cast(struct bencode *i)
|
||||
{
|
||||
return i->type == BENCODE_INT ? ((struct bencode_int *) i) : NULL;
|
||||
}
|
||||
|
||||
static inline const struct bencode_list *ben_list_const_cast(const struct bencode *list)
|
||||
{
|
||||
return list->type == BENCODE_LIST ? ((const struct bencode_list *) list) : NULL;
|
||||
}
|
||||
static inline struct bencode_list *ben_list_cast(struct bencode *list)
|
||||
{
|
||||
return list->type == BENCODE_LIST ? ((struct bencode_list *) list) : NULL;
|
||||
}
|
||||
|
||||
static inline const struct bencode_str *ben_str_const_cast(const struct bencode *str)
|
||||
{
|
||||
return str->type == BENCODE_STR ? ((const struct bencode_str *) str) : NULL;
|
||||
}
|
||||
static inline struct bencode_str *ben_str_cast(struct bencode *str)
|
||||
{
|
||||
return str->type == BENCODE_STR ? ((struct bencode_str *) str) : NULL;
|
||||
}
|
||||
|
||||
static inline const struct bencode_user *ben_user_const_cast(const struct bencode *user)
|
||||
{
|
||||
return user->type == BENCODE_USER ? ((const struct bencode_user *) user) : NULL;
|
||||
}
|
||||
static inline struct bencode_user *ben_user_cast(struct bencode *user)
|
||||
{
|
||||
return user->type == BENCODE_USER ? ((struct bencode_user *) user) : NULL;
|
||||
}
|
||||
|
||||
static inline int ben_is_user_type(const struct bencode *b, struct bencode_type *type)
|
||||
{
|
||||
return b->type == BENCODE_USER ? ((const struct bencode_user *) b)->info == type : 0;
|
||||
}
|
||||
|
||||
static inline const void *ben_user_type_const_cast(const struct bencode *b, struct bencode_type *type)
|
||||
{
|
||||
return (b->type == BENCODE_USER && ((const struct bencode_user *) b)->info == type) ? b : NULL;
|
||||
}
|
||||
static inline void *ben_user_type_cast(struct bencode *b, struct bencode_type *type)
|
||||
{
|
||||
return (b->type == BENCODE_USER && ((const struct bencode_user *) b)->info == type) ? b : NULL;
|
||||
}
|
||||
|
||||
/* Return the number of keys in a dictionary 'b' */
|
||||
static inline size_t ben_dict_len(const struct bencode *b)
|
||||
{
|
||||
return ben_dict_const_cast(b)->n;
|
||||
}
|
||||
|
||||
/* Return the number of items in a list 'b' */
|
||||
static inline size_t ben_list_len(const struct bencode *b)
|
||||
{
|
||||
return ben_list_const_cast(b)->n;
|
||||
}
|
||||
|
||||
/* ben_list_get(list, i) returns object at position i in list */
|
||||
static inline struct bencode *ben_list_get(const struct bencode *list, size_t i)
|
||||
{
|
||||
const struct bencode_list *l = ben_list_const_cast(list);
|
||||
if (i >= l->n) {
|
||||
fprintf(stderr, "bencode: List index out of bounds\n");
|
||||
abort();
|
||||
}
|
||||
return l->values[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* ben_list_set(list, i, b) sets object b to list at position i.
|
||||
* The old value at position i is freed.
|
||||
* The program aborts if position i is out of bounds.
|
||||
*/
|
||||
void ben_list_set(struct bencode *list, size_t i, struct bencode *b);
|
||||
|
||||
/* Return the number of bytes in a string 'b' */
|
||||
static inline size_t ben_str_len(const struct bencode *b)
|
||||
{
|
||||
return ben_str_const_cast(b)->len;
|
||||
}
|
||||
|
||||
/* Return boolean value (0 or 1) of 'b' */
|
||||
static inline int ben_bool_val(const struct bencode *b)
|
||||
{
|
||||
return ben_bool_const_cast(b)->b ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Return integer value of 'b' */
|
||||
static inline long long ben_int_val(const struct bencode *b)
|
||||
{
|
||||
return ben_int_const_cast(b)->ll;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: the string is always zero terminated. Also, the string may
|
||||
* contain more than one zero.
|
||||
* bencode strings are not compatible with C strings.
|
||||
*/
|
||||
static inline const char *ben_str_val(const struct bencode *b)
|
||||
{
|
||||
return ben_str_const_cast(b)->s;
|
||||
}
|
||||
|
||||
/*
|
||||
* ben_list_for_each() is an iterator macro for bencoded lists.
|
||||
*
|
||||
* Note, it is not allowed to change the list while iterating except by
|
||||
* using ben_list_pop_current().
|
||||
*
|
||||
* pos is a size_t.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* size_t pos;
|
||||
* struct bencode *list = xxx;
|
||||
* struct bencode *value;
|
||||
* ben_list_for_each(value, pos, list) {
|
||||
* inspect(value);
|
||||
* }
|
||||
*/
|
||||
#define ben_list_for_each(value, pos, l) \
|
||||
for ((pos) = (size_t) 0; \
|
||||
(pos) < (ben_list_const_cast(l))->n && \
|
||||
((value) = ((const struct bencode_list *) (l))->values[(pos)]) != NULL ; \
|
||||
(pos)++)
|
||||
|
||||
/*
|
||||
* ben_list_pop_current() returns and removes the current item at 'pos'
|
||||
* while iterating the list with ben_list_for_each().
|
||||
* It can be used more than once per walk, but only once per item.
|
||||
* Example below:
|
||||
*
|
||||
* Filter out all items from list whose string value does not begin with "foo".
|
||||
*
|
||||
* ben_list_for_each(value, pos, list) {
|
||||
* if (strncmp(ben_str_val(value), "foo", 3) != 0)
|
||||
* ben_free(ben_list_pop_current(&pos, list));
|
||||
* }
|
||||
*/
|
||||
static inline struct bencode *ben_list_pop_current(struct bencode *list,
|
||||
size_t *pos)
|
||||
{
|
||||
struct bencode *value = ben_list_pop(list, *pos);
|
||||
(*pos)--;
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* ben_dict_for_each() is an iterator macro for bencoded dictionaries.
|
||||
*
|
||||
* Note, it is not allowed to change the dictionary while iterating except
|
||||
* by using ben_dict_pop_current().
|
||||
*
|
||||
* struct bencode *dict = ben_dict();
|
||||
* size_t pos;
|
||||
* struct bencode *key;
|
||||
* struct bencode *value;
|
||||
* ben_dict_set_str_by_str(dict, "foo", "bar");
|
||||
*
|
||||
* ben_dict_for_each(key, value, pos, dict) {
|
||||
* use(key, value);
|
||||
* }
|
||||
*
|
||||
* pos is a size_t.
|
||||
*/
|
||||
#define ben_dict_for_each(bkey, bvalue, pos, d) \
|
||||
for ((pos) = 0; \
|
||||
(pos) < (ben_dict_const_cast(d))->n && \
|
||||
((bkey) = ((const struct bencode_dict *) (d))->nodes[(pos)].key) != NULL && \
|
||||
((bvalue) = ((const struct bencode_dict *) (d))->nodes[(pos)].value) != NULL; \
|
||||
(pos)++)
|
||||
|
||||
/*
|
||||
* ben_dict_pop_current() deletes the current item at 'pos' while iterating
|
||||
* the dictionary with ben_dict_for_each(). It can be used more than once
|
||||
* per walk, but only once per item. Example below:
|
||||
*
|
||||
* Filter out all items from dictionary whose key does not begin with "foo".
|
||||
*
|
||||
* ben_dict_for_each(key, value, pos, dict) {
|
||||
* if (strncmp(ben_str_val(key), "foo", 3) != 0)
|
||||
* ben_free(ben_dict_pop_current(dict, &pos));
|
||||
* }
|
||||
*/
|
||||
struct bencode *ben_dict_pop_current(struct bencode *dict, size_t *pos);
|
||||
|
||||
/* Report an error while decoding. Returns NULL. */
|
||||
void *ben_insufficient_ptr(struct ben_decode_ctx *ctx);
|
||||
void *ben_invalid_ptr(struct ben_decode_ctx *ctx);
|
||||
void *ben_oom_ptr(struct ben_decode_ctx *ctx);
|
||||
|
||||
/*
|
||||
* Decode from the current position of 'ctx'.
|
||||
*
|
||||
* This function is used to implement decoders for user-defined types.
|
||||
*/
|
||||
struct bencode *ben_ctx_decode(struct ben_decode_ctx *ctx);
|
||||
|
||||
/*
|
||||
* Test whether the input of 'ctx' has at least n bytes left.
|
||||
* Returns 0 when there is enough bytes left and -1 when there isn't.
|
||||
*
|
||||
* This function is used to implement decoders for user-defined types.
|
||||
*/
|
||||
int ben_need_bytes(const struct ben_decode_ctx *ctx, size_t n);
|
||||
|
||||
/*
|
||||
* Returns the character in current position of 'ctx'.
|
||||
*
|
||||
* This function is used to implement decoders for user-defined types.
|
||||
*/
|
||||
char ben_current_char(const struct ben_decode_ctx *ctx);
|
||||
|
||||
/*
|
||||
* Get the next n bytes from input.
|
||||
* Returns pointer to the data or NULL when there aren't enough bytes left.
|
||||
*
|
||||
* This function is used to implement decoders for user-defined types.
|
||||
*/
|
||||
const char *ben_current_buf(const struct ben_decode_ctx *ctx, size_t n);
|
||||
|
||||
/*
|
||||
* Increments current position by n.
|
||||
*
|
||||
* This function is used to implement decoders for user-defined types.
|
||||
*/
|
||||
void ben_skip(struct ben_decode_ctx *ctx, size_t n);
|
||||
|
||||
/*
|
||||
* Encode to the output of 'ctx'. The size of the encoded data can be obtained
|
||||
* with ben_encoded_size().
|
||||
*
|
||||
* This function is used to implement encoders for user-defined types.
|
||||
*/
|
||||
int ben_ctx_encode(struct ben_encode_ctx *ctx, const struct bencode *b);
|
||||
|
||||
/*
|
||||
* Append one character to output of 'ctx'. The amount of bytes written to the
|
||||
* output must be the same as returned by get_size().
|
||||
*
|
||||
* This function is used to implement encoders for user-defined types.
|
||||
*/
|
||||
int ben_put_char(struct ben_encode_ctx *ctx, char c);
|
||||
|
||||
/*
|
||||
* Append data to output of 'ctx'. The amount of bytes written to the output
|
||||
* must be the same as returned by get_size().
|
||||
*
|
||||
* This function is used to implement encoders for user-defined types.
|
||||
*/
|
||||
int ben_put_buffer(struct ben_encode_ctx *ctx, const void *buf, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2012, Anthony Minessale II
|
||||
* Copyright (c) 2010-2015, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -30,9 +30,14 @@
|
|||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "ks.h"
|
||||
|
||||
#ifndef KS_BUFFER_H
|
||||
#define KS_BUFFER_H
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
/**
|
||||
* @defgroup ks_buffer Buffer Routines
|
||||
* @ingroup buffer
|
||||
|
@ -133,6 +138,7 @@ KS_DECLARE(ks_size_t) ks_buffer_seek(ks_buffer_t *buffer, ks_size_t datalen);
|
|||
|
||||
KS_DECLARE(ks_size_t) ks_buffer_zwrite(ks_buffer_t *buffer, const void *data, ks_size_t datalen);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
#endif
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2014, Anthony Minessale II
|
||||
* Copyright (c) 2007-2015, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -52,16 +52,12 @@
|
|||
#ifndef KS_CONFIG_H
|
||||
#define KS_CONFIG_H
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
|
||||
#define KS_URL_SEPARATOR "://"
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#define KS_PATH_SEPARATOR "\\"
|
||||
#ifndef KS_CONFIG_DIR
|
||||
|
@ -107,26 +103,26 @@ atoi(expr))) ? 1 : 0
|
|||
typedef struct ks_config ks_config_t;
|
||||
|
||||
/*! \brief A simple file handle representing an open configuration file **/
|
||||
struct ks_config {
|
||||
/*! FILE stream buffer to the opened file */
|
||||
FILE *file;
|
||||
/*! path to the file */
|
||||
char path[512];
|
||||
/*! current category */
|
||||
char category[256];
|
||||
/*! current section */
|
||||
char section[256];
|
||||
/*! buffer of current line being read */
|
||||
char buf[1024];
|
||||
/*! current line number in file */
|
||||
int lineno;
|
||||
/*! current category number in file */
|
||||
int catno;
|
||||
/*! current section number in file */
|
||||
int sectno;
|
||||
struct ks_config {
|
||||
/*! FILE stream buffer to the opened file */
|
||||
FILE *file;
|
||||
/*! path to the file */
|
||||
char path[512];
|
||||
/*! current category */
|
||||
char category[256];
|
||||
/*! current section */
|
||||
char section[256];
|
||||
/*! buffer of current line being read */
|
||||
char buf[1024];
|
||||
/*! current line number in file */
|
||||
int lineno;
|
||||
/*! current category number in file */
|
||||
int catno;
|
||||
/*! current section number in file */
|
||||
int sectno;
|
||||
|
||||
int lockto;
|
||||
};
|
||||
int lockto;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Open a configuration file
|
||||
|
@ -134,13 +130,13 @@ struct ks_config {
|
|||
\param file_path path to the file
|
||||
\return 1 (true) on success 0 (false) on failure
|
||||
*/
|
||||
KS_DECLARE(int) ks_config_open_file(ks_config_t * cfg, const char *file_path);
|
||||
KS_DECLARE(int) ks_config_open_file(ks_config_t *cfg, const char *file_path);
|
||||
|
||||
/*!
|
||||
\brief Close a previously opened configuration file
|
||||
\param cfg (ks_config_t *) config handle to use
|
||||
*/
|
||||
KS_DECLARE(void) ks_config_close_file(ks_config_t * cfg);
|
||||
KS_DECLARE(void) ks_config_close_file(ks_config_t *cfg);
|
||||
|
||||
/*!
|
||||
\brief Retrieve next name/value pair from configuration file
|
||||
|
@ -148,24 +144,20 @@ KS_DECLARE(void) ks_config_close_file(ks_config_t * cfg);
|
|||
\param var pointer to aim at the new variable name
|
||||
\param val pointer to aim at the new value
|
||||
*/
|
||||
KS_DECLARE(int) ks_config_next_pair(ks_config_t * cfg, char **var, char **val);
|
||||
KS_DECLARE(int) ks_config_next_pair(ks_config_t *cfg, char **var, char **val);
|
||||
|
||||
/*!
|
||||
\brief Retrieve the CAS bits from a configuration string value
|
||||
\param strvalue pointer to the configuration string value (expected to be in format whatever:xxxx)
|
||||
\param outbits pointer to aim at the CAS bits
|
||||
*/
|
||||
KS_DECLARE(int) ks_config_get_cas_bits(char *strvalue, unsigned char *outbits);
|
||||
KS_DECLARE(int) ks_config_get_cas_bits(char *strvalue, unsigned char *outbits);
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
#endif /* defined(KS_CONFIG_H) */
|
||||
|
||||
KS_END_EXTERN_C
|
||||
#endif /* defined(KS_CONFIG_H) */
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Copyright (c) 2009-2011 by Juliusz Chroboczek
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _KS_DHT_H
|
||||
#define _KS_DHT_H
|
||||
|
||||
#include "ks.h"
|
||||
#include "ks_bencode.h"
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
typedef enum {
|
||||
KS_DHT_EVENT_NONE = 0,
|
||||
KS_DHT_EVENT_VALUES = 1,
|
||||
KS_DHT_EVENT_VALUES6 = 2,
|
||||
KS_DHT_EVENT_SEARCH_DONE = 3,
|
||||
KS_DHT_EVENT_SEARCH_DONE6 = 4
|
||||
} ks_dht_event_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
DHT_PARAM_AUTOROUTE = 1
|
||||
} ks_dht_param_t;
|
||||
|
||||
typedef enum {
|
||||
KS_DHT_AF_INET4 = (1 << 0),
|
||||
KS_DHT_AF_INET6 = (1 << 1)
|
||||
} ks_dht_af_flag_t;
|
||||
|
||||
|
||||
typedef void (*dht_callback_t)(void *closure, ks_dht_event_t event, const unsigned char *info_hash, const void *data, size_t data_len);
|
||||
|
||||
typedef struct dht_handle_s dht_handle_t;
|
||||
|
||||
KS_DECLARE(int) dht_periodic(dht_handle_t *h, const void *buf, size_t buflen, ks_sockaddr_t *from);
|
||||
KS_DECLARE(ks_status_t) ks_dht_init(dht_handle_t **handle, ks_dht_af_flag_t af_flags, const unsigned char *id, unsigned int port);
|
||||
KS_DECLARE(void) ks_dht_set_param(dht_handle_t *h, ks_dht_param_t param, ks_bool_t val);
|
||||
KS_DECLARE(ks_status_t) ks_dht_add_ip(dht_handle_t *h, char *ip, int port);
|
||||
KS_DECLARE(void) ks_dht_start(dht_handle_t *h);
|
||||
KS_DECLARE(int) dht_insert_node(dht_handle_t *h, const unsigned char *id, ks_sockaddr_t *sa);
|
||||
KS_DECLARE(int) dht_ping_node(dht_handle_t *h, ks_sockaddr_t *sa);
|
||||
KS_DECLARE(int) dht_search(dht_handle_t *h, const unsigned char *id, int port, int af, dht_callback_t callback, void *closure);
|
||||
KS_DECLARE(int) dht_nodes(dht_handle_t *h, int af, int *good_return, int *dubious_return, int *cached_return, int *incoming_return);
|
||||
KS_DECLARE(ks_status_t) ks_dht_one_loop(dht_handle_t *h, int timeout);
|
||||
KS_DECLARE(ks_status_t) ks_dht_get_bind_addrs(dht_handle_t *h, const ks_sockaddr_t ***addrs, ks_size_t *addrlen);
|
||||
KS_DECLARE(void) ks_dht_set_callback(dht_handle_t *h, dht_callback_t callback, void *closure);
|
||||
KS_DECLARE(void) ks_dht_set_port(dht_handle_t *h, unsigned int port);
|
||||
KS_DECLARE(void) dht_dump_tables(dht_handle_t *h, FILE *f);
|
||||
KS_DECLARE(int) dht_get_nodes(dht_handle_t *h, struct sockaddr_in *sin, int *num, struct sockaddr_in6 *sin6, int *num6);
|
||||
KS_DECLARE(int) dht_uninit(dht_handle_t **h);
|
||||
KS_DECLARE(void) ks_dht_set_v(dht_handle_t *h, const unsigned char *v);
|
||||
KS_DECLARE(int) ks_dht_calculate_mutable_storage_target(unsigned char *pk, unsigned char *salt, int salt_length, unsigned char *target, int target_length);
|
||||
KS_DECLARE(int) ks_dht_generate_mutable_storage_args(struct bencode *data, int64_t sequence, int cas,
|
||||
unsigned char *id, int id_len, /* querying nodes id */
|
||||
const unsigned char *sk, const unsigned char *pk,
|
||||
unsigned char *salt, unsigned long long salt_length,
|
||||
unsigned char *token, unsigned long long token_length,
|
||||
unsigned char *signature, unsigned long long *signature_length,
|
||||
struct bencode **arguments);
|
||||
|
||||
/* This must be provided by the user. */
|
||||
KS_DECLARE(int) dht_blacklisted(const ks_sockaddr_t *sa);
|
||||
KS_DECLARE(void) dht_hash(void *hash_return, int hash_size, const void *v1, int len1, const void *v2, int len2, const void *v3, int len3);
|
||||
KS_DECLARE(int) dht_random_bytes(void *buf, size_t size);
|
||||
|
||||
KS_DECLARE(int) ks_dht_send_message_mutable(dht_handle_t *h, unsigned char *sk, unsigned char *pk, char **node_id,
|
||||
char *message_id, int sequence, char *message, ks_time_t life);
|
||||
|
||||
KS_DECLARE(int) ks_dht_send_message_mutable_cjson(dht_handle_t *h, unsigned char *sk, unsigned char *pk, char **node_id,
|
||||
char *message_id, int sequence, cJSON *message, ks_time_t life);
|
||||
|
||||
typedef void (ks_dht_store_entry_json_cb)(struct dht_handle_s *h, const cJSON *msg, void *obj);
|
||||
KS_DECLARE(void) ks_dht_store_entry_json_cb_set(struct dht_handle_s *h, ks_dht_store_entry_json_cb *store_json_cb, void *arg);
|
||||
|
||||
KS_DECLARE(int) ks_dht_api_find_node(dht_handle_t *h, char *node_id_hex, char *target_hex, ks_bool_t ipv6);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* _KS_DHT_H */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Cross Platform dso/dll load abstraction
|
||||
* Copyright(C) 2008 Michael Jerris
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so.
|
||||
*
|
||||
* This work is provided under this license on an "as is" basis, without warranty of any kind,
|
||||
* either expressed or implied, including, without limitation, warranties that the covered code
|
||||
* is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
|
||||
* risk as to the quality and performance of the covered code is with you. Should any covered
|
||||
* code prove defective in any respect, you (not the initial developer or any other contributor)
|
||||
* assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
|
||||
* constitutes an essential part of this license. No use of any covered code is authorized hereunder
|
||||
* except under this disclaimer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
#ifndef _KS_DSO_H
|
||||
#define _KS_DSO_H
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
typedef void (*ks_func_ptr_t) (void);
|
||||
typedef void * ks_dso_lib_t;
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_dso_destroy(ks_dso_lib_t *lib);
|
||||
KS_DECLARE(ks_dso_lib_t) ks_dso_open(const char *path, char **err);
|
||||
KS_DECLARE(void *) ks_dso_func_sym(ks_dso_lib_t lib, const char *sym, char **err);
|
||||
KS_DECLARE(char *) ks_build_dso_path(const char *name, char *path, ks_size_t len);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* ks_hash.h -- Ks_Hash
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* ks_hash.h Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
|
||||
|
||||
#ifndef __KS_HASH_CWC22_H__
|
||||
#define __KS_HASH_CWC22_H__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef __inline__
|
||||
#define __inline__ __inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ks_hash ks_hash_t;
|
||||
typedef struct ks_hash_iterator ks_hash_iterator_t;
|
||||
|
||||
typedef enum {
|
||||
KS_UNLOCKED,
|
||||
KS_READLOCKED
|
||||
} ks_locked_t;
|
||||
|
||||
|
||||
/* Example of use:
|
||||
*
|
||||
* ks_hash_t *h;
|
||||
* struct some_key *k;
|
||||
* struct some_value *v;
|
||||
*
|
||||
* static unsigned int hash_from_key_fn( void *k );
|
||||
* static int keys_equal_fn ( void *key1, void *key2 );
|
||||
*
|
||||
* h = ks_hash_create(16, hash_from_key_fn, keys_equal_fn);
|
||||
* k = (struct some_key *) malloc(sizeof(struct some_key));
|
||||
* v = (struct some_value *) malloc(sizeof(struct some_value));
|
||||
*
|
||||
* (initialise k and v to suitable values)
|
||||
*
|
||||
* if (! ks_hash_insert(h,k,v) )
|
||||
* { exit(-1); }
|
||||
*
|
||||
* if (NULL == (found = ks_hash_search(h,k) ))
|
||||
* { printf("not found!"); }
|
||||
*
|
||||
* if (NULL == (found = ks_hash_remove(h,k) ))
|
||||
* { printf("Not found\n"); }
|
||||
*
|
||||
*/
|
||||
|
||||
/* Macros may be used to define type-safe(r) ks_hash access functions, with
|
||||
* methods specialized to take known key and value types as parameters.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Insert this at the start of your file:
|
||||
*
|
||||
* DEFINE_KS_HASH_INSERT(insert_some, struct some_key, struct some_value);
|
||||
* DEFINE_KS_HASH_SEARCH(search_some, struct some_key, struct some_value);
|
||||
* DEFINE_KS_HASH_REMOVE(remove_some, struct some_key, struct some_value);
|
||||
*
|
||||
* This defines the functions 'insert_some', 'search_some' and 'remove_some'.
|
||||
* These operate just like ks_hash_insert etc., with the same parameters,
|
||||
* but their function signatures have 'struct some_key *' rather than
|
||||
* 'void *', and hence can generate compile time errors if your program is
|
||||
* supplying incorrect data as a key (and similarly for value).
|
||||
*
|
||||
* Note that the hash and key equality functions passed to ks_hash_create
|
||||
* still take 'void *' parameters instead of 'some key *'. This shouldn't be
|
||||
* a difficult issue as they're only defined and passed once, and the other
|
||||
* functions will ensure that only valid keys are supplied to them.
|
||||
*
|
||||
* The cost for this checking is increased code size and runtime overhead
|
||||
* - if performance is important, it may be worth switching back to the
|
||||
* unsafe methods once your program has been debugged with the safe methods.
|
||||
* This just requires switching to some simple alternative defines - eg:
|
||||
* #define insert_some ks_hash_insert
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
typedef enum {
|
||||
KS_HASH_FLAG_NONE = 0,
|
||||
KS_HASH_FLAG_DEFAULT = (1 << 0),
|
||||
KS_HASH_FLAG_FREE_KEY = (1 << 1),
|
||||
KS_HASH_FLAG_FREE_VALUE = (1 << 2),
|
||||
KS_HASH_FLAG_RWLOCK = (1 << 3),
|
||||
KS_HASH_FLAG_DUP_CHECK = (1 << 4)
|
||||
} ks_hash_flag_t;
|
||||
|
||||
#define KS_HASH_FREE_BOTH KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE
|
||||
|
||||
typedef enum {
|
||||
KS_HASH_MODE_DEFAULT = 0,
|
||||
KS_HASH_MODE_CASE_SENSITIVE,
|
||||
KS_HASH_MODE_CASE_INSENSITIVE,
|
||||
KS_HASH_MODE_INT,
|
||||
KS_HASH_MODE_INT64,
|
||||
KS_HASH_MODE_PTR
|
||||
} ks_hash_mode_t;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* ks_hash_create
|
||||
|
||||
* @name ks_hash_create
|
||||
* @param minsize minimum initial size of ks_hash
|
||||
* @param hashfunction function for hashing keys
|
||||
* @param key_eq_fn function for determining key equality
|
||||
* @return newly created ks_hash or NULL on failure
|
||||
*/
|
||||
|
||||
KS_DECLARE(ks_status_t)
|
||||
ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize,
|
||||
unsigned int (*hashfunction) (void*),
|
||||
int (*key_eq_fn) (void*,void*), ks_hash_mode_t mode, ks_hash_flag_t flags, ks_hash_destructor_t destructor, ks_pool_t *pool);
|
||||
|
||||
/*****************************************************************************
|
||||
* ks_hash_insert
|
||||
|
||||
* @name ks_hash_insert
|
||||
* @param h the ks_hash to insert into
|
||||
* @param k the key - ks_hash claims ownership and will free on removal
|
||||
* @param v the value - does not claim ownership
|
||||
* @return non-zero for successful insertion
|
||||
*
|
||||
* This function will cause the table to expand if the insertion would take
|
||||
* the ratio of entries to table size over the maximum load factor.
|
||||
*
|
||||
* This function does not check for repeated insertions with a duplicate key.
|
||||
* The value returned when using a duplicate key is undefined -- when
|
||||
* the ks_hash changes size, the order of retrieval of duplicate key
|
||||
* entries is reversed.
|
||||
* If in doubt, remove before insert.
|
||||
*/
|
||||
|
||||
|
||||
KS_DECLARE(int) ks_hash_insert_ex(ks_hash_t *h, void *k, void *v, ks_hash_flag_t flags, ks_hash_destructor_t destructor);
|
||||
#define ks_hash_insert(_h, _k, _v) ks_hash_insert_ex(_h, _k, _v, 0, NULL)
|
||||
|
||||
#define DEFINE_KS_HASH_INSERT(fnname, keytype, valuetype) \
|
||||
int fnname (ks_hash_t *h, keytype *k, valuetype *v) \
|
||||
{ \
|
||||
return ks_hash_insert(h,k,v); \
|
||||
}
|
||||
|
||||
|
||||
KS_DECLARE(void) ks_hash_set_flags(ks_hash_t *h, ks_hash_flag_t flags);
|
||||
KS_DECLARE(void) ks_hash_set_destructor(ks_hash_t *h, ks_hash_destructor_t destructor);
|
||||
|
||||
/*****************************************************************************
|
||||
* ks_hash_search
|
||||
|
||||
* @name ks_hash_search
|
||||
* @param h the ks_hash to search
|
||||
* @param k the key to search for - does not claim ownership
|
||||
* @return the value associated with the key, or NULL if none found
|
||||
*/
|
||||
|
||||
KS_DECLARE(void *)
|
||||
ks_hash_search(ks_hash_t *h, void *k, ks_locked_t locked);
|
||||
|
||||
#define DEFINE_KS_HASH_SEARCH(fnname, keytype, valuetype) \
|
||||
valuetype * fnname (ks_hash_t *h, keytype *k) \
|
||||
{ \
|
||||
return (valuetype *) (ks_hash_search(h,k)); \
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* ks_hash_remove
|
||||
|
||||
* @name ks_hash_remove
|
||||
* @param h the ks_hash to remove the item from
|
||||
* @param k the key to search for - does not claim ownership
|
||||
* @return the value associated with the key, or NULL if none found
|
||||
*/
|
||||
|
||||
KS_DECLARE(void *) /* returns value */
|
||||
ks_hash_remove(ks_hash_t *h, void *k);
|
||||
|
||||
#define DEFINE_KS_HASH_REMOVE(fnname, keytype, valuetype) \
|
||||
valuetype * fnname (ks_hash_t *h, keytype *k) \
|
||||
{ \
|
||||
return (valuetype *) (ks_hash_remove(h,k)); \
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* ks_hash_count
|
||||
|
||||
* @name ks_hash_count
|
||||
* @param h the ks_hash
|
||||
* @return the number of items stored in the ks_hash
|
||||
*/
|
||||
KS_DECLARE(unsigned int)
|
||||
ks_hash_count(ks_hash_t *h);
|
||||
|
||||
/*****************************************************************************
|
||||
* ks_hash_destroy
|
||||
|
||||
* @name ks_hash_destroy
|
||||
* @param h the ks_hash
|
||||
* @param free_values whether to call 'free' on the remaining values
|
||||
*/
|
||||
|
||||
KS_DECLARE(void)
|
||||
ks_hash_destroy(ks_hash_t **h);
|
||||
|
||||
KS_DECLARE(ks_hash_iterator_t*) ks_hash_first(ks_hash_t *h, ks_locked_t locked);
|
||||
KS_DECLARE(void) ks_hash_last(ks_hash_iterator_t **iP);
|
||||
KS_DECLARE(ks_hash_iterator_t*) ks_hash_next(ks_hash_iterator_t **iP);
|
||||
KS_DECLARE(void) ks_hash_this(ks_hash_iterator_t *i, const void **key, ks_ssize_t *klen, void **val);
|
||||
KS_DECLARE(void) ks_hash_this_val(ks_hash_iterator_t *i, void *val);
|
||||
KS_DECLARE(ks_status_t) ks_hash_create(ks_hash_t **hp, ks_hash_mode_t mode, ks_hash_flag_t flags, ks_pool_t *pool);
|
||||
|
||||
KS_DECLARE(void) ks_hash_write_lock(ks_hash_t *h);
|
||||
KS_DECLARE(void) ks_hash_write_unlock(ks_hash_t *h);
|
||||
KS_DECLARE(ks_status_t) ks_hash_read_lock(ks_hash_t *h);
|
||||
KS_DECLARE(ks_status_t) ks_hash_read_unlock(ks_hash_t *h);
|
||||
|
||||
|
||||
static __inline uint32_t ks_hash_default_int64(void *ky)
|
||||
{
|
||||
int64_t key = *((int64_t *)ky);
|
||||
key = (~key) + (key << 18);
|
||||
key = key ^ (key >> 31);
|
||||
key = key * 21;
|
||||
key = key ^ (key >> 11);
|
||||
key = key + (key << 6);
|
||||
key = key ^ (key >> 22);
|
||||
return (uint32_t) key;
|
||||
}
|
||||
|
||||
static __inline int ks_hash_equalkeys_int64(void *k1, void *k2)
|
||||
{
|
||||
return *(uint64_t *)k1 == *(uint64_t *)k2;
|
||||
}
|
||||
|
||||
static __inline uint32_t ks_hash_default_int(void *ky) {
|
||||
uint32_t x = *((uint32_t *)ky);
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = ((x >> 16) ^ x);
|
||||
return x;
|
||||
}
|
||||
|
||||
static __inline int ks_hash_equalkeys_int(void *k1, void *k2)
|
||||
{
|
||||
return *(uint32_t *)k1 == *(uint32_t *)k2;
|
||||
}
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
|
||||
static __inline uint32_t ks_hash_default_ptr(void *ky)
|
||||
{
|
||||
#ifdef KS_64BIT
|
||||
return ks_hash_default_int64(ky);
|
||||
#endif
|
||||
return ks_hash_default_int(ky);
|
||||
}
|
||||
|
||||
static __inline int ks_hash_equalkeys_ptr(void *k1, void *k2)
|
||||
{
|
||||
#ifdef KS_64BIT
|
||||
return ks_hash_equalkeys_int64(k1, k2);
|
||||
#endif
|
||||
return ks_hash_equalkeys_int(k1, k2);
|
||||
}
|
||||
|
||||
|
||||
static __inline int ks_hash_equalkeys(void *k1, void *k2)
|
||||
{
|
||||
return strcmp((char *) k1, (char *) k2) ? 0 : 1;
|
||||
}
|
||||
|
||||
static __inline int ks_hash_equalkeys_ci(void *k1, void *k2)
|
||||
{
|
||||
return strcasecmp((char *) k1, (char *) k2) ? 0 : 1;
|
||||
}
|
||||
|
||||
static __inline uint32_t ks_hash_default(void *ky)
|
||||
{
|
||||
unsigned char *str = (unsigned char *) ky;
|
||||
uint32_t hash = 0;
|
||||
int c;
|
||||
|
||||
while ((c = *str)) {
|
||||
str++;
|
||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static __inline uint32_t ks_hash_default_ci(void *ky)
|
||||
{
|
||||
unsigned char *str = (unsigned char *) ky;
|
||||
uint32_t hash = 0;
|
||||
int c;
|
||||
|
||||
while ((c = ks_tolower(*str))) {
|
||||
str++;
|
||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif /* __KS_HASH_CWC22_H__ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002, Christopher Clark
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -76,20 +76,21 @@ KS_DECLARE(int) cJSON_GetArraySize(cJSON *array);
|
|||
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||
KS_DECLARE(cJSON *)cJSON_GetArrayItem(cJSON *array,int item);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
KS_DECLARE(cJSON *)cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||
KS_DECLARE(cJSON *)cJSON_GetObjectItem(const cJSON *object,const char *string);
|
||||
KS_DECLARE(const char *)cJSON_GetObjectCstr(const cJSON *object, const char *string);
|
||||
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
KS_DECLARE(const char *)cJSON_GetErrorPtr();
|
||||
KS_DECLARE(const char *)cJSON_GetErrorPtr(void);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
KS_DECLARE(cJSON *)cJSON_CreateNull();
|
||||
KS_DECLARE(cJSON *)cJSON_CreateTrue();
|
||||
KS_DECLARE(cJSON *)cJSON_CreateFalse();
|
||||
KS_DECLARE(cJSON *)cJSON_CreateNull(void);
|
||||
KS_DECLARE(cJSON *)cJSON_CreateTrue(void);
|
||||
KS_DECLARE(cJSON *)cJSON_CreateFalse(void);
|
||||
KS_DECLARE(cJSON *)cJSON_CreateBool(int b);
|
||||
KS_DECLARE(cJSON *)cJSON_CreateNumber(double num);
|
||||
KS_DECLARE(cJSON *)cJSON_CreateString(const char *string);
|
||||
KS_DECLARE(cJSON *)cJSON_CreateArray();
|
||||
KS_DECLARE(cJSON *)cJSON_CreateObject();
|
||||
KS_DECLARE(cJSON *)cJSON_CreateArray(void);
|
||||
KS_DECLARE(cJSON *)cJSON_CreateObject(void);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
KS_DECLARE(cJSON *)cJSON_CreateIntArray(int *numbers,int count);
|
||||
|
@ -114,12 +115,68 @@ KS_DECLARE(void) cJSON_DeleteItemFromObject(cJSON *object,const char *string);
|
|||
KS_DECLARE(void) cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
|
||||
KS_DECLARE(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
KS_DECLARE(cJSON *) cJSON_Duplicate(cJSON *item,int recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
|
||||
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
|
||||
KS_DECLARE(cJSON *) cJSON_CreateStringPrintf(const char *fmt, ...);
|
||||
|
||||
static inline cJSON *json_add_child_obj(cJSON *json, const char *name, cJSON *obj)
|
||||
{
|
||||
cJSON *new_json = NULL;
|
||||
|
||||
ks_assert(json);
|
||||
|
||||
if (obj) {
|
||||
new_json = obj;
|
||||
} else {
|
||||
new_json = cJSON_CreateObject();
|
||||
}
|
||||
|
||||
ks_assert(new_json);
|
||||
|
||||
cJSON_AddItemToObject(json, name, new_json);
|
||||
|
||||
return new_json;
|
||||
}
|
||||
|
||||
static inline cJSON *json_add_child_array(cJSON *json, const char *name)
|
||||
{
|
||||
cJSON *new_json = NULL;
|
||||
|
||||
ks_assert(json);
|
||||
|
||||
new_json = cJSON_CreateArray();
|
||||
ks_assert(new_json);
|
||||
|
||||
cJSON_AddItemToObject(json, name, new_json);
|
||||
|
||||
return new_json;
|
||||
}
|
||||
|
||||
static inline cJSON *json_add_child_string(cJSON *json, const char *name, const char *val)
|
||||
{
|
||||
cJSON *new_json = NULL;
|
||||
|
||||
ks_assert(json);
|
||||
|
||||
new_json = cJSON_CreateString(val);
|
||||
ks_assert(new_json);
|
||||
|
||||
cJSON_AddItemToObject(json, name, new_json);
|
||||
|
||||
return new_json;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2014, Anthony Minessale II
|
||||
* Copyright (c) 2007-2015, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -34,33 +34,94 @@
|
|||
#ifndef _KS_PLATFORM_H_
|
||||
#define _KS_PLATFORM_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
|
||||
#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__APPLE__)
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRINGS_H
|
||||
#define HAVE_STRINGS_H 1
|
||||
#endif
|
||||
#ifndef HAVE_SYS_SOCKET_H
|
||||
#define HAVE_SYS_SOCKET_H 1
|
||||
#if defined(__linux__) && !defined(_DEFAULT_SOURCE)
|
||||
#define _DEFAULT_SOURCE 1
|
||||
#endif
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#if UINTPTR_MAX == 0xffffffffffffffff
|
||||
#define KS_64BIT 1
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/signal.h>
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
#include <io.h>
|
||||
/*#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <Synchapi.h>
|
||||
*/
|
||||
#ifndef open
|
||||
#define open _open
|
||||
#endif
|
||||
|
||||
#ifndef close
|
||||
#define close _close
|
||||
#endif
|
||||
|
||||
#ifndef read
|
||||
#define read _read
|
||||
#endif
|
||||
|
||||
#ifndef write
|
||||
#define write _write
|
||||
#endif
|
||||
|
||||
#ifndef __inline__
|
||||
#define __inline__ __inline
|
||||
#endif
|
||||
|
||||
#ifndef strdup
|
||||
#define strdup _strdup
|
||||
#endif
|
||||
|
||||
#if (_MSC_VER >= 1400) /* VC8+ */
|
||||
#ifndef _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
@ -69,67 +130,62 @@ extern "C" {
|
|||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef strcasecmp
|
||||
#define strcasecmp(s1, s2) _stricmp(s1, s2)
|
||||
#endif
|
||||
|
||||
#ifndef strncasecmp
|
||||
#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
|
||||
#endif
|
||||
|
||||
#if (_MSC_VER < 1900) /* VC 2015 */
|
||||
#ifndef snprintf
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef S_IRUSR
|
||||
#define S_IRUSR _S_IREAD
|
||||
#endif
|
||||
|
||||
#ifndef S_IWUSR
|
||||
#define S_IWUSR _S_IWRITE
|
||||
#endif
|
||||
#undef HAVE_STRINGS_H
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#if (_MSC_VER >= 1400) // VC8+
|
||||
#define ks_assert(expr) assert(expr);__analysis_assume( expr )
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#ifndef WIN32
|
||||
#include <sys/time.h>
|
||||
#ifndef ks_assert
|
||||
#define ks_assert(_x) assert(_x)
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/signal.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
#ifdef __WINDOWS__
|
||||
typedef SOCKET ks_socket_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int8 int8_t;
|
||||
typedef intptr_t ks_ssize_t;
|
||||
typedef int ks_filehandle_t;
|
||||
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
typedef SOCKET ks_socket_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int8 int8_t;
|
||||
typedef intptr_t ks_ssize_t;
|
||||
typedef int ks_filehandle_t;
|
||||
#define KS_SOCK_INVALID INVALID_SOCKET
|
||||
#define strerror_r(num, buf, size) strerror_s(buf, size, num)
|
||||
#else
|
||||
#define KS_SOCK_INVALID -1
|
||||
typedef int ks_socket_t;
|
||||
typedef ssize_t ks_ssize_t;
|
||||
typedef int ks_filehandle_t;
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#if defined(KS_DECLARE_STATIC)
|
||||
#define KS_DECLARE(type) type __stdcall
|
||||
#define KS_DECLARE_NONSTD(type) type __cdecl
|
||||
|
@ -143,30 +199,68 @@ typedef int ks_filehandle_t;
|
|||
#define KS_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl
|
||||
#define KS_DECLARE_DATA __declspec(dllimport)
|
||||
#endif
|
||||
#else // !WIN32
|
||||
#else // !WIN32
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(KS_API_VISIBILITY)
|
||||
#define KS_DECLARE(type) __attribute__((visibility("default"))) type
|
||||
#define KS_DECLARE_NONSTD(type) __attribute__((visibility("default"))) type
|
||||
#define KS_DECLARE_DATA __attribute__((visibility("default")))
|
||||
#else
|
||||
#define KS_DECLARE(type) type
|
||||
#define KS_DECLARE_NONSTD(type) type
|
||||
#define KS_DECLARE_DATA
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#define KS_SOCK_INVALID -1
|
||||
typedef int ks_socket_t;
|
||||
typedef ssize_t ks_ssize_t;
|
||||
typedef int ks_filehandle_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* malloc or DIE macros */
|
||||
#ifdef NDEBUG
|
||||
#define ks_malloc(ptr, len) (void)( (!!(ptr = malloc(len))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr )
|
||||
#define ks_zmalloc(ptr, len) (void)( (!!(ptr = calloc(1, (len)))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr)
|
||||
#if (_MSC_VER >= 1500) // VC9+
|
||||
#define ks_strdup(ptr, s) (void)( (!!(ptr = _strdup(s))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr)
|
||||
#else
|
||||
#define ks_strdup(ptr, s) (void)( (!!(ptr = strdup(s))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr)
|
||||
#endif
|
||||
#else
|
||||
#if (_MSC_VER >= 1500) // VC9+
|
||||
#define ks_malloc(ptr, len) (void)(assert(((ptr) = malloc((len)))),ptr);__analysis_assume( ptr )
|
||||
#define ks_zmalloc(ptr, len) (void)(assert((ptr = calloc(1, (len)))),ptr);__analysis_assume( ptr )
|
||||
#define ks_strdup(ptr, s) (void)(assert(((ptr) = _strdup(s))),ptr);__analysis_assume( ptr )
|
||||
#else
|
||||
#define ks_malloc(ptr, len) (void)(assert(((ptr) = malloc((len)))),ptr)
|
||||
#define ks_zmalloc(ptr, len) (void)(assert((ptr = calloc(1, (len)))),ptr)
|
||||
#define ks_strdup(ptr, s) (void)(assert(((ptr) = strdup((s)))),ptr)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __ATTR_SAL
|
||||
/* used for msvc code analysis */
|
||||
/* http://msdn2.microsoft.com/en-us/library/ms235402.aspx */
|
||||
#define _In_
|
||||
#define _In_z_
|
||||
#define _In_opt_z_
|
||||
#define _In_opt_
|
||||
#define _Printf_format_string_
|
||||
#define _Ret_opt_z_
|
||||
#define _Ret_z_
|
||||
#define _Out_opt_
|
||||
#define _Out_
|
||||
#define _Check_return_
|
||||
#define _Inout_
|
||||
#define _Inout_opt_
|
||||
#define _In_bytecount_(x)
|
||||
#define _Out_opt_bytecapcount_(x)
|
||||
#define _Out_bytecapcount_(x)
|
||||
#define _Ret_
|
||||
#define _Post_z_
|
||||
#define _Out_cap_(x)
|
||||
#define _Out_z_cap_(x)
|
||||
#define _Out_ptrdiff_cap_(x)
|
||||
#define _Out_opt_ptrdiff_cap_(x)
|
||||
#define _Post_count_(x)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* defined(__cplusplus) */
|
||||
#endif /* defined(_KS_PLATFORM_H_) */
|
||||
|
||||
KS_END_EXTERN_C
|
||||
#endif /* defined(_KS_PLATFORM_H_) */
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
|
|
|
@ -0,0 +1,478 @@
|
|||
/*
|
||||
* Memory pool defines.
|
||||
*
|
||||
* Copyright 1996 by Gray Watson.
|
||||
*
|
||||
* This file is part of the ks_mpool package.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for
|
||||
* any purpose and without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
* copies, and that the name of Gray Watson not be used in advertising
|
||||
* or publicity pertaining to distribution of the document or software
|
||||
* without specific, written prior permission.
|
||||
*
|
||||
* Gray Watson makes no representations about the suitability of the
|
||||
* software described herein for any purpose. It is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*
|
||||
* The author may be reached via http://256.com/gray/
|
||||
*
|
||||
* $Id: ks_mpool.h,v 1.4 2006/05/31 20:26:11 gray Exp $
|
||||
*/
|
||||
|
||||
#ifndef __KS_POOL_H__
|
||||
#define __KS_POOL_H__
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* ks_pool flags to ks_pool_alloc or ks_pool_set_attr
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
KS_POOL_FLAG_DEFAULT = 0,
|
||||
|
||||
KS_POOL_FLAG_BEST_FIT = (1 << 0),
|
||||
/*
|
||||
* Choose a best fit algorithm not first fit. This takes more CPU
|
||||
* time but will result in a tighter heap.
|
||||
*/
|
||||
|
||||
KS_POOL_FLAG_HEAVY_PACKING = (1 << 1)
|
||||
/*
|
||||
* This enables very heavy packing at the possible expense of CPU.
|
||||
* This affects a number of parts of the library.
|
||||
*
|
||||
* By default the 1st page of memory is reserved for the main ks_pool
|
||||
* structure. This flag will cause the rest of the 1st block to be
|
||||
* available for use as user memory.
|
||||
*
|
||||
* By default the library looks through the memory when freed looking
|
||||
* for a magic value. There is an internal max size that it will look
|
||||
* and then it will give up. This flag forces it to look until it
|
||||
* finds it.
|
||||
*/
|
||||
} ks_pool_flag_t;
|
||||
|
||||
/*
|
||||
* Ks_Pool function IDs for the ks_pool_log_func callback function.
|
||||
*/
|
||||
#define KS_POOL_FUNC_CLOSE 1 /* ks_pool_close function called */
|
||||
#define KS_POOL_FUNC_CLEAR 2 /* ks_pool_clear function called */
|
||||
#define KS_POOL_FUNC_ALLOC 3 /* ks_pool_alloc function called */
|
||||
#define KS_POOL_FUNC_CALLOC 4 /* ks_pool_calloc function called */
|
||||
#define KS_POOL_FUNC_FREE 5 /* ks_pool_free function called */
|
||||
#define KS_POOL_FUNC_RESIZE 6 /* ks_pool_resize function called */
|
||||
|
||||
/*
|
||||
* void ks_pool_log_func_t
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Ks_Pool transaction log function.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* None.
|
||||
*
|
||||
* ARGUMENT:
|
||||
*
|
||||
* mp_p -> Associated ks_pool address.
|
||||
*
|
||||
* func_id -> Integer function ID which identifies which ks_pool
|
||||
* function is being called.
|
||||
*
|
||||
* byte_size -> Optionally specified byte size.
|
||||
*
|
||||
* ele_n -> Optionally specified element number. For ks_pool_calloc
|
||||
* only.
|
||||
*
|
||||
* new_addr -> Optionally specified new address. For ks_pool_alloc,
|
||||
* ks_pool_calloc, and ks_pool_resize only.
|
||||
*
|
||||
* old_addr -> Optionally specified old address. For ks_pool_resize and
|
||||
* ks_pool_free only.
|
||||
*
|
||||
* old_byte_size -> Optionally specified old byte size. For
|
||||
* ks_pool_resize only.
|
||||
*/
|
||||
typedef void (*ks_pool_log_func_t) (const void *mp_p,
|
||||
const int func_id,
|
||||
const unsigned long byte_size,
|
||||
const unsigned long ele_n, const void *old_addr, const void *new_addr, const unsigned long old_byte_size);
|
||||
|
||||
/*
|
||||
* ks_pool_t *ks_pool_open
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Open/allocate a new memory pool.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - KS_STATUS_SUCCESS
|
||||
*
|
||||
* Failure - ks_status_t error code
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* poolP <- pointer to new pool that will be set on success
|
||||
*
|
||||
*/
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_pool_open(ks_pool_t **poolP);
|
||||
|
||||
/*
|
||||
* ks_status_t ks_pool_close
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Close/free a memory allocation pool previously opened with
|
||||
* ks_pool_open.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - KS_STATUS_SUCCESS
|
||||
*
|
||||
* Failure - ks_status_t error code
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_pp <-> Pointer to pointer of our memory pool.
|
||||
*/
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_pool_close(ks_pool_t **mp_pP);
|
||||
|
||||
/*
|
||||
* int ks_pool_clear
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Wipe an opened memory pool clean so we can start again.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - KS_STATUS_SUCCESS
|
||||
*
|
||||
* Failure - ks_status_t error code
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p <-> Pointer to our memory pool.
|
||||
*/
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_pool_clear(ks_pool_t *mp_p);
|
||||
|
||||
/*
|
||||
* void *ks_pool_alloc
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Allocate space for bytes inside of an already open memory pool.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - Pointer to the address to use.
|
||||
*
|
||||
* Failure - NULL
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p <-> Pointer to the memory pool. If NULL then it will do a
|
||||
* normal malloc.
|
||||
*
|
||||
* byte_size -> Number of bytes to allocate in the pool. Must be >0.
|
||||
*
|
||||
*/
|
||||
KS_DECLARE(void *) ks_pool_alloc(ks_pool_t *mp_p, const unsigned long byte_size);
|
||||
|
||||
/*
|
||||
* void *ks_pool_alloc_ex
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Allocate space for bytes inside of an already open memory pool.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - Pointer to the address to use.
|
||||
*
|
||||
* Failure - NULL
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p <-> Pointer to the memory pool. If NULL then it will do a
|
||||
* normal malloc.
|
||||
*
|
||||
* byte_size -> Number of bytes to allocate in the pool. Must be >0.
|
||||
*
|
||||
* error_p <- Pointer to integer which, if not NULL, will be set with
|
||||
* a ks_pool error code.
|
||||
*/
|
||||
KS_DECLARE(void *) ks_pool_alloc_ex(ks_pool_t *mp_p, const unsigned long byte_size, ks_status_t *error_p);
|
||||
|
||||
/*
|
||||
* void *ks_pool_calloc
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Allocate space for elements of bytes in the memory pool and zero
|
||||
* the space afterwards.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - Pointer to the address to use.
|
||||
*
|
||||
* Failure - NULL
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p <-> Pointer to the memory pool. If NULL then it will do a
|
||||
* normal calloc.
|
||||
*
|
||||
* ele_n -> Number of elements to allocate.
|
||||
*
|
||||
* ele_size -> Number of bytes per element being allocated.
|
||||
*
|
||||
*/
|
||||
KS_DECLARE(void *) ks_pool_calloc(ks_pool_t *mp_p, const unsigned long ele_n, const unsigned long ele_size);
|
||||
|
||||
/*
|
||||
* void *ks_pool_calloc_ex
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Allocate space for elements of bytes in the memory pool and zero
|
||||
* the space afterwards.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - Pointer to the address to use.
|
||||
*
|
||||
* Failure - NULL
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p <-> Pointer to the memory pool. If NULL then it will do a
|
||||
* normal calloc.
|
||||
*
|
||||
* ele_n -> Number of elements to allocate.
|
||||
*
|
||||
* ele_size -> Number of bytes per element being allocated.
|
||||
*
|
||||
* error_p <- Pointer to integer which, if not NULL, will be set with
|
||||
* a ks_pool error code.
|
||||
*/
|
||||
KS_DECLARE(void *) ks_pool_calloc_ex(ks_pool_t *mp_p, const unsigned long ele_n, const unsigned long ele_size, ks_status_t *error_p);
|
||||
|
||||
/*
|
||||
* int ks_pool_free
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Free an address from a memory pool.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - KS_STATUS_SUCCESS
|
||||
*
|
||||
* Failure - ks_status_t error code
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p <-> Pointer to the memory pool. If NULL then it will do a
|
||||
* normal free.
|
||||
*
|
||||
* addr <-> Address to free.
|
||||
*
|
||||
*/
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_pool_free(ks_pool_t *mp_p, void *addr);
|
||||
|
||||
/*
|
||||
* void *ks_pool_resize
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Reallocate an address in a mmeory pool to a new size.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - Pointer to the address to use.
|
||||
*
|
||||
* Failure - NULL
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p <-> Pointer to the memory pool. If NULL then it will do a
|
||||
* normal realloc.
|
||||
*
|
||||
* old_addr -> Previously allocated address.
|
||||
*
|
||||
* new_byte_size -> New size of the allocation.
|
||||
*
|
||||
*/
|
||||
KS_DECLARE(void *) ks_pool_resize(ks_pool_t *mp_p, void *old_addr, const unsigned long new_byte_size);
|
||||
|
||||
/*
|
||||
* void *ks_pool_resize_ex
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Reallocate an address in a mmeory pool to a new size.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - Pointer to the address to use.
|
||||
*
|
||||
* Failure - NULL
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p <-> Pointer to the memory pool. If NULL then it will do a
|
||||
* normal realloc.
|
||||
*
|
||||
* old_addr -> Previously allocated address.
|
||||
*
|
||||
* new_byte_size -> New size of the allocation.
|
||||
*
|
||||
* error_p <- Pointer to integer which, if not NULL, will be set with
|
||||
* a ks_pool error code.
|
||||
*/
|
||||
KS_DECLARE(void *) ks_pool_resize_ex(ks_pool_t *mp_p, void *old_addr, const unsigned long new_byte_size, ks_status_t *error_p);
|
||||
|
||||
/*
|
||||
* int ks_pool_stats
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Return stats from the memory pool.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - KS_STATUS_SUCCESS
|
||||
*
|
||||
* Failure - ks_status_t error code
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p -> Pointer to the memory pool.
|
||||
*
|
||||
* page_size_p <- Pointer to an unsigned integer which, if not NULL,
|
||||
* will be set to the page-size of the pool.
|
||||
*
|
||||
* num_alloced_p <- Pointer to an unsigned long which, if not NULL,
|
||||
* will be set to the number of pointers currently allocated in pool.
|
||||
*
|
||||
* user_alloced_p <- Pointer to an unsigned long which, if not NULL,
|
||||
* will be set to the number of user bytes allocated in this pool.
|
||||
*
|
||||
* max_alloced_p <- Pointer to an unsigned long which, if not NULL,
|
||||
* will be set to the maximum number of user bytes that have been
|
||||
* allocated in this pool.
|
||||
*
|
||||
* tot_alloced_p <- Pointer to an unsigned long which, if not NULL,
|
||||
* will be set to the total amount of space (including administrative
|
||||
* overhead) used by the pool.
|
||||
*/
|
||||
KS_DECLARE(ks_status_t) ks_pool_stats(const ks_pool_t *mp_p, unsigned int *page_size_p,
|
||||
unsigned long *num_alloced_p, unsigned long *user_alloced_p, unsigned long *max_alloced_p, unsigned long *tot_alloced_p);
|
||||
|
||||
/*
|
||||
* int ks_pool_set_log_func
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Set a logging callback function to be called whenever there was a
|
||||
* memory transaction. See ks_pool_log_func_t.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - KS_STATUS_SUCCESS
|
||||
*
|
||||
* Failure - ks_status_t error code
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p <-> Pointer to the memory pool.
|
||||
*
|
||||
* log_func -> Log function (defined in ks_pool.h) which will be called
|
||||
* with each ks_pool transaction.
|
||||
*/
|
||||
KS_DECLARE(ks_status_t) ks_pool_set_log_func(ks_pool_t *mp_p, ks_pool_log_func_t log_func);
|
||||
|
||||
/*
|
||||
* int ks_pool_set_max_pages
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Set the maximum number of pages that the library will use. Once it
|
||||
* hits the limit it will return KS_STATUS_NO_PAGES.
|
||||
*
|
||||
* NOTE: if the KS_POOL_FLAG_HEAVY_PACKING is set then this max-pages
|
||||
* value will include the page with the ks_pool header structure in it.
|
||||
* If the flag is _not_ set then the max-pages will not include this
|
||||
* first page.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - KS_STATUS_SUCCESS
|
||||
*
|
||||
* Failure - ks_status_t error code
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* mp_p <-> Pointer to the memory pool.
|
||||
*
|
||||
* max_pages -> Maximum number of pages used by the library.
|
||||
*/
|
||||
KS_DECLARE(ks_status_t) ks_pool_set_max_pages(ks_pool_t *mp_p, const unsigned int max_pages);
|
||||
|
||||
/*
|
||||
* const char *ks_pool_strerror
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* Return the corresponding string for the error number.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Success - String equivalient of the error.
|
||||
*
|
||||
* Failure - String "invalid error code"
|
||||
*
|
||||
* ARGUMENTS:
|
||||
*
|
||||
* error -> Error number that we are converting.
|
||||
*/
|
||||
KS_DECLARE(const char *) ks_pool_strerror(const ks_status_t error);
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_pool_set_cleanup(ks_pool_t *mp_p, void *ptr, void *arg, int type, ks_pool_cleanup_fn_t fn);
|
||||
|
||||
#define ks_pool_safe_free(_p, _a) ks_pool_free(_p, _a); (_a) = NULL
|
||||
|
||||
/*<<<<<<<<<< This is end of the auto-generated output from fillproto. */
|
||||
|
||||
KS_DECLARE(char *) ks_pstrdup(ks_pool_t *pool, const char *str);
|
||||
KS_DECLARE(char *) ks_pstrndup(ks_pool_t *pool, const char *str, size_t len);
|
||||
KS_DECLARE(char *) ks_pstrmemdup(ks_pool_t *pool, const char *str, size_t len);
|
||||
KS_DECLARE(void *) ks_pmemdup(ks_pool_t *pool, const void *buf, size_t len);
|
||||
KS_DECLARE(char *) ks_pstrcat(ks_pool_t *pool, ...);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* ! __KS_POOL_H__ */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
#ifndef KS_PRINTF_H
|
||||
#define KS_PRINTF_H
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
/**
|
||||
* This routine is a variant of the "sprintf()" from the
|
||||
* standard C library. The resulting string is written into memory
|
||||
* obtained from malloc() so that there is never a possiblity of buffer
|
||||
* overflow. This routine also implement some additional formatting
|
||||
* options that are useful for constructing SQL statements.
|
||||
*
|
||||
* The strings returned by this routine should be freed by calling
|
||||
* free().
|
||||
*
|
||||
* All of the usual printf formatting options apply. In addition, there
|
||||
* is a "%q" option. %q works like %s in that it substitutes a null-terminated
|
||||
* string from the argument list. But %q also doubles every '\'' character.
|
||||
* %q is designed for use inside a string literal. By doubling each '\''
|
||||
* character it escapes that character and allows it to be inserted into
|
||||
* the string.
|
||||
*
|
||||
* For example, so some string variable contains text as follows:
|
||||
*
|
||||
* char *zText = "It's a happy day!";
|
||||
*
|
||||
* We can use this text in an SQL statement as follows:
|
||||
*
|
||||
* char *z = ks_mprintf("INSERT INTO TABLES('%q')", zText);
|
||||
* ks_core_db_exec(db, z, callback1, 0, 0);
|
||||
* free(z);
|
||||
*
|
||||
* Because the %q format string is used, the '\'' character in zText
|
||||
* is escaped and the SQL generated is as follows:
|
||||
*
|
||||
* INSERT INTO table1 VALUES('It''s a happy day!')
|
||||
*
|
||||
* This is correct. Had we used %s instead of %q, the generated SQL
|
||||
* would have looked like this:
|
||||
*
|
||||
* INSERT INTO table1 VALUES('It's a happy day!');
|
||||
*
|
||||
* This second example is an SQL syntax error. As a general rule you
|
||||
* should always use %q instead of %s when inserting text into a string
|
||||
* literal.
|
||||
*/
|
||||
KS_DECLARE(char *) ks_mprintf(const char *zFormat, ...);
|
||||
KS_DECLARE(char *) ks_vmprintf(const char *zFormat, va_list ap);
|
||||
KS_DECLARE(char *) ks_snprintfv(char *zBuf, int n, const char *zFormat, ...);
|
||||
KS_DECLARE(char *) ks_vsnprintf(char *zbuf, int n, const char *zFormat, va_list ap);
|
||||
KS_DECLARE(char *) ks_vpprintf(ks_pool_t *pool, const char *zFormat, va_list ap);
|
||||
KS_DECLARE(char *) ks_pprintf(ks_pool_t *pool, const char *zFormat, ...);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* KS_PRINTF_H */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2015, Anthony Minessale II
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 _KS_Q_H_
|
||||
#define _KS_Q_H_
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_pop_timeout(ks_q_t *q, void **ptr, uint32_t timeout);
|
||||
KS_DECLARE(ks_status_t) ks_q_wake(ks_q_t *q);
|
||||
KS_DECLARE(ks_status_t) ks_q_flush(ks_q_t *q);
|
||||
KS_DECLARE(ks_status_t) ks_q_set_flush_fn(ks_q_t *q, ks_flush_fn_t fn, void *flush_data);
|
||||
KS_DECLARE(ks_status_t) ks_q_wait(ks_q_t *q);
|
||||
KS_DECLARE(ks_size_t) ks_q_term(ks_q_t *q);
|
||||
KS_DECLARE(ks_size_t) ks_q_size(ks_q_t *q);
|
||||
KS_DECLARE(ks_status_t) ks_q_destroy(ks_q_t **qP);
|
||||
KS_DECLARE(ks_status_t) ks_q_create(ks_q_t **qP, ks_pool_t *pool, ks_size_t maxlen);
|
||||
KS_DECLARE(ks_status_t) ks_q_push(ks_q_t *q, void *ptr);
|
||||
KS_DECLARE(ks_status_t) ks_q_trypush(ks_q_t *q, void *ptr);
|
||||
KS_DECLARE(ks_status_t) ks_q_pop(ks_q_t *q, void **ptr);
|
||||
KS_DECLARE(ks_status_t) ks_q_trypop(ks_q_t *q, void **ptr);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* defined(_KS_Q_H_) */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Cross Platform random/uuid abstraction
|
||||
* Copyright(C) 2015 Michael Jerris
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so.
|
||||
*
|
||||
* This work is provided under this license on an "as is" basis, without warranty of any kind,
|
||||
* either expressed or implied, including, without limitation, warranties that the covered code
|
||||
* is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
|
||||
* risk as to the quality and performance of the covered code is with you. Should any covered
|
||||
* code prove defective in any respect, you (not the initial developer or any other contributor)
|
||||
* assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
|
||||
* constitutes an essential part of this license. No use of any covered code is authorized hereunder
|
||||
* except under this disclaimer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
#ifndef _KS_RNG_H
|
||||
#define _KS_RNG_H
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Rpc.h>
|
||||
typedef UUID uuid_t;
|
||||
#else
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
|
||||
KS_DECLARE(uuid_t *) ks_uuid(uuid_t *uuid);
|
||||
KS_DECLARE(char *) ks_uuid_str(ks_pool_t *pool, uuid_t *uuid);
|
||||
KS_DECLARE(ks_status_t) ks_rng_init(void);
|
||||
KS_DECLARE(ks_status_t) ks_rng_shutdown(void);
|
||||
KS_DECLARE(size_t) ks_rng_get_data(uint8_t* buffer, size_t length);
|
||||
KS_DECLARE(size_t) ks_rng_add_entropy(const uint8_t *buffer, size_t length);
|
||||
KS_DECLARE(size_t) ks_rng_seed_data(uint8_t *seed, size_t length);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2014, Anthony Minessale II
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 _KS_SOCKET_H_
|
||||
#define _KS_SOCKET_H_
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
#define KS_SO_NONBLOCK 2999
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
static __inline int ks_errno(void)
|
||||
{
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
static __inline int ks_errno_is_blocking(int errcode)
|
||||
{
|
||||
return errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS || errcode == 35 || errcode == 730035;
|
||||
}
|
||||
|
||||
static __inline int ks_errno_is_interupt(int errcode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int ks_errno(void)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
static inline int ks_errno_is_blocking(int errcode)
|
||||
{
|
||||
return errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS || errcode == EINTR || errcode == ETIMEDOUT || errcode == 35 || errcode == 730035;
|
||||
}
|
||||
|
||||
static inline int ks_errno_is_interupt(int errcode)
|
||||
{
|
||||
return errcode == EINTR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static __inline int ks_socket_valid(ks_socket_t s) {
|
||||
return s != KS_SOCK_INVALID;
|
||||
}
|
||||
|
||||
#define KS_SA_INIT {AF_INET};
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_socket_send(ks_socket_t sock, void *data, ks_size_t *datalen);
|
||||
KS_DECLARE(ks_status_t) ks_socket_recv(ks_socket_t sock, void *data, ks_size_t *datalen);
|
||||
KS_DECLARE(ks_status_t) ks_socket_sendto(ks_socket_t sock, void *data, ks_size_t *datalen, ks_sockaddr_t *addr);
|
||||
KS_DECLARE(ks_status_t) ks_socket_recvfrom(ks_socket_t sock, void *data, ks_size_t *datalen, ks_sockaddr_t *addr);
|
||||
|
||||
typedef struct pollfd *ks_ppollfd_t;
|
||||
KS_DECLARE(int) ks_poll(ks_ppollfd_t fds, uint32_t nfds, int timeout);
|
||||
KS_DECLARE(ks_status_t) ks_socket_option(ks_socket_t socket, int option_name, ks_bool_t enabled);
|
||||
KS_DECLARE(ks_status_t) ks_socket_sndbuf(ks_socket_t socket, int bufsize);
|
||||
KS_DECLARE(ks_status_t) ks_socket_rcvbuf(ks_socket_t socket, int bufsize);
|
||||
KS_DECLARE(int) ks_wait_sock(ks_socket_t sock, uint32_t ms, ks_poll_t flags);
|
||||
|
||||
KS_DECLARE(ks_socket_t) ks_socket_connect(int type, int protocol, ks_sockaddr_t *addr);
|
||||
KS_DECLARE(ks_status_t) ks_addr_bind(ks_socket_t server_sock, ks_sockaddr_t *addr);
|
||||
KS_DECLARE(const char *) ks_addr_get_host(ks_sockaddr_t *addr);
|
||||
KS_DECLARE(ks_port_t) ks_addr_get_port(ks_sockaddr_t *addr);
|
||||
KS_DECLARE(int) ks_addr_cmp(const ks_sockaddr_t *sa1, const ks_sockaddr_t *sa2);
|
||||
KS_DECLARE(ks_status_t) ks_addr_copy(ks_sockaddr_t *addr, const ks_sockaddr_t *src_addr);
|
||||
KS_DECLARE(ks_status_t) ks_addr_set(ks_sockaddr_t *addr, const char *host, ks_port_t port, int family);
|
||||
KS_DECLARE(ks_status_t) ks_addr_set_raw(ks_sockaddr_t *addr, void *data, ks_port_t port, int family);
|
||||
KS_DECLARE(ks_status_t) ks_addr_raw_data(const ks_sockaddr_t *addr, void **data, ks_size_t *datalen);
|
||||
KS_DECLARE(ks_status_t) ks_listen(const char *host, ks_port_t port, int family, int backlog, ks_listen_callback_t callback, void *user_data);
|
||||
KS_DECLARE(ks_status_t) ks_socket_shutdown(ks_socket_t sock, int how);
|
||||
KS_DECLARE(ks_status_t) ks_socket_close(ks_socket_t *sock);
|
||||
KS_DECLARE(ks_status_t) ks_ip_route(char *buf, int len, const char *route_ip);
|
||||
KS_DECLARE(ks_status_t) ks_find_local_ip(char *buf, int len, int *mask, int family, const char *route_ip);
|
||||
KS_DECLARE(ks_status_t) ks_listen_sock(ks_socket_t server_sock, ks_sockaddr_t *addr, int backlog, ks_listen_callback_t callback, void *user_data);
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* defined(_KS_SOCKET_H_) */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef _KS_SSL_H
|
||||
#define _KS_SSL_H
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/engine.h>
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
KS_DECLARE(void) ks_ssl_init_ssl_locks(void);
|
||||
KS_DECLARE(void) ks_ssl_destroy_ssl_locks(void);
|
||||
KS_DECLARE(int) ks_gen_cert(const char *dir, const char *file);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* defined(_KS_SSL_H) */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
/*
|
||||
* Cross Platform Thread/Mutex abstraction
|
||||
* Copyright(C) 2007 Michael Jerris
|
||||
* Copyright(C) 2015 Michael Jerris
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
|
@ -13,38 +13,122 @@
|
|||
* code prove defective in any respect, you (not the initial developer or any other contributor)
|
||||
* assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
|
||||
* constitutes an essential part of this license. No use of any covered code is authorized hereunder
|
||||
* except under this disclaimer.
|
||||
* except under this disclaimer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _KS_THREADMUTEX_H
|
||||
#define _KS_THREADMUTEX_H
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* defined(__cplusplus) */
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
typedef struct ks_mutex ks_mutex_t;
|
||||
typedef struct ks_thread ks_thread_t;
|
||||
typedef void *(*ks_thread_function_t) (ks_thread_t *, void *);
|
||||
#ifdef WIN32
|
||||
#include <process.h>
|
||||
#define KS_THREAD_CALLING_CONVENTION __stdcall
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#define KS_THREAD_CALLING_CONVENTION
|
||||
#endif
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_thread_create_detached(ks_thread_function_t func, void *data);
|
||||
ks_status_t ks_thread_create_detached_ex(ks_thread_function_t func, void *data, size_t stack_size);
|
||||
void ks_thread_override_default_stacksize(size_t size);
|
||||
KS_DECLARE(ks_status_t) ks_mutex_create(ks_mutex_t **mutex);
|
||||
KS_DECLARE(ks_status_t) ks_mutex_destroy(ks_mutex_t **mutex);
|
||||
KS_DECLARE(ks_status_t) ks_mutex_lock(ks_mutex_t *mutex);
|
||||
KS_DECLARE(ks_status_t) ks_mutex_trylock(ks_mutex_t *mutex);
|
||||
KS_DECLARE(ks_status_t) ks_mutex_unlock(ks_mutex_t *mutex);
|
||||
#define KS_THREAD_DEFAULT_STACK 240 * 1024
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* defined(__cplusplus) */
|
||||
typedef struct ks_thread ks_thread_t;
|
||||
typedef void *(*ks_thread_function_t) (ks_thread_t *, void *);
|
||||
|
||||
#endif /* defined(_KS_THREADMUTEX_H) */
|
||||
typedef
|
||||
#ifdef WIN32
|
||||
void *
|
||||
#else
|
||||
pthread_t
|
||||
#endif
|
||||
ks_thread_os_handle_t;
|
||||
|
||||
struct ks_thread {
|
||||
ks_pool_t *pool;
|
||||
#ifdef WIN32
|
||||
void *handle;
|
||||
#else
|
||||
pthread_t handle;
|
||||
pthread_attr_t attribute;
|
||||
#endif
|
||||
void *private_data;
|
||||
ks_thread_function_t function;
|
||||
size_t stack_size;
|
||||
uint32_t flags;
|
||||
uint8_t running;
|
||||
uint8_t priority;
|
||||
void *return_data;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
KS_PRI_LOW = 1,
|
||||
KS_PRI_NORMAL = 10,
|
||||
KS_PRI_IMPORTANT = 50,
|
||||
KS_PRI_REALTIME = 99,
|
||||
} ks_thread_priority_t;
|
||||
|
||||
typedef enum {
|
||||
KS_THREAD_FLAG_DEFAULT = 0,
|
||||
KS_THREAD_FLAG_DETATCHED = (1 << 0)
|
||||
} ks_thread_flags_t;
|
||||
|
||||
KS_DECLARE(int) ks_thread_set_priority(int nice_val);
|
||||
KS_DECLARE(ks_thread_os_handle_t) ks_thread_self(void);
|
||||
KS_DECLARE(ks_thread_os_handle_t) ks_thread_os_handle(ks_thread_t *thread);
|
||||
KS_DECLARE(ks_status_t) ks_thread_create_ex(ks_thread_t **thread, ks_thread_function_t func, void *data,
|
||||
uint32_t flags, size_t stack_size, ks_thread_priority_t priority, ks_pool_t *pool);
|
||||
KS_DECLARE(ks_status_t) ks_thread_join(ks_thread_t *thread);
|
||||
KS_DECLARE(uint8_t) ks_thread_priority(ks_thread_t *thread);
|
||||
|
||||
#define ks_thread_create(thread, func, data, pool) \
|
||||
ks_thread_create_ex(thread, func, data, KS_THREAD_FLAG_DEFAULT, KS_THREAD_DEFAULT_STACK, KS_PRI_NORMAL, pool)
|
||||
|
||||
typedef enum {
|
||||
KS_MUTEX_FLAG_DEFAULT = 0,
|
||||
KS_MUTEX_FLAG_NON_RECURSIVE = (1 << 0)
|
||||
} ks_mutex_flags_t;
|
||||
|
||||
typedef struct ks_mutex ks_mutex_t;
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_mutex_create(ks_mutex_t **mutex, unsigned int flags, ks_pool_t *pool);
|
||||
KS_DECLARE(ks_status_t) ks_mutex_lock(ks_mutex_t *mutex);
|
||||
KS_DECLARE(ks_status_t) ks_mutex_trylock(ks_mutex_t *mutex);
|
||||
KS_DECLARE(ks_status_t) ks_mutex_unlock(ks_mutex_t *mutex);
|
||||
KS_DECLARE(ks_status_t) ks_mutex_destroy(ks_mutex_t **mutex);
|
||||
|
||||
typedef struct ks_cond ks_cond_t;
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_create(ks_cond_t **cond, ks_pool_t *pool);
|
||||
KS_DECLARE(ks_status_t) ks_cond_create_ex(ks_cond_t **cond, ks_pool_t *pool, ks_mutex_t *mutex);
|
||||
KS_DECLARE(ks_status_t) ks_cond_lock(ks_cond_t *cond);
|
||||
KS_DECLARE(ks_status_t) ks_cond_trylock(ks_cond_t *cond);
|
||||
KS_DECLARE(ks_status_t) ks_cond_unlock(ks_cond_t *cond);
|
||||
KS_DECLARE(ks_status_t) ks_cond_signal(ks_cond_t *cond);
|
||||
KS_DECLARE(ks_status_t) ks_cond_broadcast(ks_cond_t *cond);
|
||||
KS_DECLARE(ks_status_t) ks_cond_try_signal(ks_cond_t *cond);
|
||||
KS_DECLARE(ks_status_t) ks_cond_try_broadcast(ks_cond_t *cond);
|
||||
KS_DECLARE(ks_status_t) ks_cond_wait(ks_cond_t *cond);
|
||||
KS_DECLARE(ks_status_t) ks_cond_timedwait(ks_cond_t *cond, ks_time_t ms);
|
||||
KS_DECLARE(ks_status_t) ks_cond_destroy(ks_cond_t **cond);
|
||||
KS_DECLARE(ks_mutex_t *) ks_cond_get_mutex(ks_cond_t *cond);
|
||||
|
||||
typedef struct ks_rwl ks_rwl_t;
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rwl_create(ks_rwl_t **rwlock, ks_pool_t *pool);
|
||||
KS_DECLARE(ks_status_t) ks_rwl_read_lock(ks_rwl_t *rwlock);
|
||||
KS_DECLARE(ks_status_t) ks_rwl_write_lock(ks_rwl_t *rwlock);
|
||||
KS_DECLARE(ks_status_t) ks_rwl_try_read_lock(ks_rwl_t *rwlock);
|
||||
KS_DECLARE(ks_status_t) ks_rwl_try_write_lock(ks_rwl_t *rwlock);
|
||||
KS_DECLARE(ks_status_t) ks_rwl_read_unlock(ks_rwl_t *rwlock);
|
||||
KS_DECLARE(ks_status_t) ks_rwl_write_unlock(ks_rwl_t *rwlock);
|
||||
KS_DECLARE(ks_status_t) ks_rwl_destroy(ks_rwl_t **rwlock);
|
||||
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* defined(_KS_THREADMUTEX_H) */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2015, Anthony Minessale II
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 _KS_TIME_H_
|
||||
#define _KS_TIME_H_
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
#define KS_USEC_PER_SEC 1000000
|
||||
#define ks_time_sec(time) ((time) / KS_USEC_PER_SEC)
|
||||
#define ks_time_usec(time) ((time) % KS_USEC_PER_SEC)
|
||||
#define ks_time_nsec(time) (((time) % KS_USEC_PER_SEC) * 1000)
|
||||
#define ks_sleep_ms(_t) ks_sleep(_t * 1000)
|
||||
|
||||
KS_DECLARE(ks_time_t) ks_time_now(void);
|
||||
KS_DECLARE(ks_time_t) ks_time_now_sec(void);
|
||||
KS_DECLARE(void) ks_sleep(ks_time_t microsec);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* defined(_KS_TIME_H_) */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2014, Anthony Minessale II
|
||||
* Copyright (c) 2007-2015, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -34,113 +34,119 @@
|
|||
#ifndef _KS_TYPES_H_
|
||||
#define _KS_TYPES_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "ks.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* defined(__cplusplus) */
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
#include <ks_platform.h>
|
||||
#define KS_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) KS_DECLARE(_TYPE) _FUNC1 (const char *name); KS_DECLARE(const char *) _FUNC2 (_TYPE type);
|
||||
|
||||
#define KS_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \
|
||||
KS_DECLARE(_TYPE) _FUNC1 (const char *name) \
|
||||
{ \
|
||||
int i; \
|
||||
_TYPE t = _MAX ; \
|
||||
\
|
||||
for (i = 0; i < _MAX ; i++) { \
|
||||
if (!strcasecmp(name, _STRINGS[i])) { \
|
||||
t = (_TYPE) i; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return t; \
|
||||
} \
|
||||
KS_DECLARE(const char *) _FUNC2 (_TYPE type) \
|
||||
{ \
|
||||
if (type > _MAX) { \
|
||||
type = _MAX; \
|
||||
} \
|
||||
return _STRINGS[(int)type]; \
|
||||
} \
|
||||
|
||||
#define KS_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL };
|
||||
|
||||
#define KS_VA_NONE "%s", ""
|
||||
|
||||
typedef enum {
|
||||
KS_POLL_READ = (1 << 0),
|
||||
KS_POLL_WRITE = (1 << 1),
|
||||
KS_POLL_ERROR = (1 << 2)
|
||||
} ks_poll_t;
|
||||
|
||||
typedef enum {
|
||||
KS_POLL_READ = (1 << 0),
|
||||
KS_POLL_WRITE = (1 << 1),
|
||||
KS_POLL_ERROR = (1 << 2)
|
||||
} ks_poll_t;
|
||||
typedef uint16_t ks_port_t;
|
||||
typedef size_t ks_size_t;
|
||||
|
||||
#ifdef WIN32
|
||||
#define KS_SEQ_FWHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
|
||||
#define KS_SEQ_BWHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
#define KS_SEQ_FRED FOREGROUND_RED | FOREGROUND_INTENSITY
|
||||
#define KS_SEQ_BRED FOREGROUND_RED
|
||||
#define KS_SEQ_FMAGEN FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY
|
||||
#define KS_SEQ_BMAGEN FOREGROUND_BLUE | FOREGROUND_RED
|
||||
#define KS_SEQ_FCYAN FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
|
||||
#define KS_SEQ_BCYAN FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
#define KS_SEQ_FGREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
|
||||
#define KS_SEQ_BGREEN FOREGROUND_GREEN
|
||||
#define KS_SEQ_FYELLOW FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY
|
||||
#define KS_SEQ_BYELLOW FOREGROUND_RED | FOREGROUND_GREEN
|
||||
#define KS_SEQ_DEFAULT_COLOR KS_SEQ_FWHITE
|
||||
#define KS_SEQ_FBLUE FOREGROUND_BLUE | FOREGROUND_INTENSITY
|
||||
#define KS_SEQ_BBLUE FOREGROUND_BLUE
|
||||
#define KS_SEQ_FBLACK 0 | FOREGROUND_INTENSITY
|
||||
#define KS_SEQ_BBLACK 0
|
||||
#else
|
||||
#define KS_SEQ_ESC "\033["
|
||||
/* Ansi Control character suffixes */
|
||||
#define KS_SEQ_HOME_CHAR 'H'
|
||||
#define KS_SEQ_HOME_CHAR_STR "H"
|
||||
#define KS_SEQ_CLEARLINE_CHAR '1'
|
||||
#define KS_SEQ_CLEARLINE_CHAR_STR "1"
|
||||
#define KS_SEQ_CLEARLINEEND_CHAR "K"
|
||||
#define KS_SEQ_CLEARSCR_CHAR0 '2'
|
||||
#define KS_SEQ_CLEARSCR_CHAR1 'J'
|
||||
#define KS_SEQ_CLEARSCR_CHAR "2J"
|
||||
#define KS_SEQ_DEFAULT_COLOR KS_SEQ_ESC KS_SEQ_END_COLOR /* Reset to Default fg/bg color */
|
||||
#define KS_SEQ_AND_COLOR ";" /* To add multiple color definitions */
|
||||
#define KS_SEQ_END_COLOR "m" /* To end color definitions */
|
||||
/* Foreground colors values */
|
||||
#define KS_SEQ_F_BLACK "30"
|
||||
#define KS_SEQ_F_RED "31"
|
||||
#define KS_SEQ_F_GREEN "32"
|
||||
#define KS_SEQ_F_YELLOW "33"
|
||||
#define KS_SEQ_F_BLUE "34"
|
||||
#define KS_SEQ_F_MAGEN "35"
|
||||
#define KS_SEQ_F_CYAN "36"
|
||||
#define KS_SEQ_F_WHITE "37"
|
||||
/* Background colors values */
|
||||
#define KS_SEQ_B_BLACK "40"
|
||||
#define KS_SEQ_B_RED "41"
|
||||
#define KS_SEQ_B_GREEN "42"
|
||||
#define KS_SEQ_B_YELLOW "43"
|
||||
#define KS_SEQ_B_BLUE "44"
|
||||
#define KS_SEQ_B_MAGEN "45"
|
||||
#define KS_SEQ_B_CYAN "46"
|
||||
#define KS_SEQ_B_WHITE "47"
|
||||
/* Preset escape sequences - Change foreground colors only */
|
||||
#define KS_SEQ_FBLACK KS_SEQ_ESC KS_SEQ_F_BLACK KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_FRED KS_SEQ_ESC KS_SEQ_F_RED KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_FGREEN KS_SEQ_ESC KS_SEQ_F_GREEN KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_FYELLOW KS_SEQ_ESC KS_SEQ_F_YELLOW KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_FBLUE KS_SEQ_ESC KS_SEQ_F_BLUE KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_FMAGEN KS_SEQ_ESC KS_SEQ_F_MAGEN KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_FCYAN KS_SEQ_ESC KS_SEQ_F_CYAN KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_FWHITE KS_SEQ_ESC KS_SEQ_F_WHITE KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_BBLACK KS_SEQ_ESC KS_SEQ_B_BLACK KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_BRED KS_SEQ_ESC KS_SEQ_B_RED KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_BGREEN KS_SEQ_ESC KS_SEQ_B_GREEN KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_BYELLOW KS_SEQ_ESC KS_SEQ_B_YELLOW KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_BBLUE KS_SEQ_ESC KS_SEQ_B_BLUE KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_BMAGEN KS_SEQ_ESC KS_SEQ_B_MAGEN KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_BCYAN KS_SEQ_ESC KS_SEQ_B_CYAN KS_SEQ_END_COLOR
|
||||
#define KS_SEQ_BWHITE KS_SEQ_ESC KS_SEQ_B_WHITE KS_SEQ_END_COLOR
|
||||
/* Preset escape sequences */
|
||||
#define KS_SEQ_HOME KS_SEQ_ESC KS_SEQ_HOME_CHAR_STR
|
||||
#define KS_SEQ_CLEARLINE KS_SEQ_ESC KS_SEQ_CLEARLINE_CHAR_STR
|
||||
#define KS_SEQ_CLEARLINEEND KS_SEQ_ESC KS_SEQ_CLEARLINEEND_CHAR
|
||||
#define KS_SEQ_CLEARSCR KS_SEQ_ESC KS_SEQ_CLEARSCR_CHAR KS_SEQ_HOME
|
||||
#endif
|
||||
typedef enum {
|
||||
KS_STATUS_SUCCESS,
|
||||
KS_STATUS_FAIL,
|
||||
KS_STATUS_BREAK,
|
||||
KS_STATUS_DISCONNECTED,
|
||||
KS_STATUS_GENERR,
|
||||
KS_STATUS_INACTIVE,
|
||||
KS_STATUS_TIMEOUT,
|
||||
/* Memory pool errors */
|
||||
KS_STATUS_ARG_NULL, /* function argument is null */
|
||||
KS_STATUS_ARG_INVALID, /* function argument is invalid */
|
||||
KS_STATUS_PNT, /* invalid ks_pool pointer */
|
||||
KS_STATUS_POOL_OVER, /* ks_pool structure was overwritten */
|
||||
KS_STATUS_PAGE_SIZE, /* could not get system page-size */
|
||||
KS_STATUS_OPEN_ZERO, /* could not open /dev/zero */
|
||||
KS_STATUS_NO_MEM, /* no memory available */
|
||||
KS_STATUS_MMAP, /* problems with mmap */
|
||||
KS_STATUS_SIZE, /* error processing requested size */
|
||||
KS_STATUS_TOO_BIG, /* allocation exceeded max size */
|
||||
KS_STATUS_MEM, /* invalid memory address */
|
||||
KS_STATUS_MEM_OVER, /* memory lower bounds overwritten */
|
||||
KS_STATUS_NOT_FOUND, /* memory block not found in pool */
|
||||
KS_STATUS_IS_FREE, /* memory block already free */
|
||||
KS_STATUS_BLOCK_STAT, /* invalid internal block status */
|
||||
KS_STATUS_FREE_ADDR, /* invalid internal free address */
|
||||
KS_STATUS_NO_PAGES, /* ran out of pages in pool */
|
||||
KS_STATUS_ALLOC, /* calloc,malloc,free,realloc failed */
|
||||
KS_STATUS_PNT_OVER, /* pointer structure was overwritten */
|
||||
KS_STATUS_INVALID_POINTER, /* address is not valid */
|
||||
/* Always insert new entries above this line*/
|
||||
KS_STATUS_COUNT
|
||||
} ks_status_t;
|
||||
|
||||
typedef int16_t ks_port_t;
|
||||
typedef size_t ks_size_t;
|
||||
#define STATUS_STRINGS\
|
||||
"SUCCESS",\
|
||||
"FAIL",\
|
||||
"BREAK",\
|
||||
"DISCONNECTED",\
|
||||
"GENERR",\
|
||||
"INACTIVE",\
|
||||
"TIMEOUT",\
|
||||
"ARG_NULL",\
|
||||
"ARG_INVALID",\
|
||||
"PNT",\
|
||||
"POOL_OVER",\
|
||||
"PAGE_SIZE",\
|
||||
"OPEN_ZERO",\
|
||||
"NO_MEM",\
|
||||
"MMAP",\
|
||||
"SIZE",\
|
||||
"TOO_BIG",\
|
||||
"MEM",\
|
||||
"MEM_OVER",\
|
||||
"NOT_FOUN",\
|
||||
"IS_FREE",\
|
||||
"BLOCK_STAT",\
|
||||
"FREE_ADDR",\
|
||||
"NO_PAGES",\
|
||||
"ALLOC",\
|
||||
"PNT_OVER",\
|
||||
"INVALID_POINTER",\
|
||||
/* insert new entries before this */\
|
||||
"COUNT"
|
||||
|
||||
typedef enum {
|
||||
KS_SUCCESS,
|
||||
KS_FAIL,
|
||||
KS_BREAK,
|
||||
KS_DISCONNECTED,
|
||||
KS_GENERR
|
||||
} ks_status_t;
|
||||
KS_STR2ENUM_P(ks_str2ks_status, ks_status2str, ks_status_t)
|
||||
|
||||
/*! \brief Used internally for truth test */
|
||||
typedef enum {
|
||||
KS_TRUE = 1,
|
||||
KS_FALSE = 0
|
||||
} ks_bool_t;
|
||||
typedef enum {
|
||||
KS_TRUE = 1,
|
||||
KS_FALSE = 0
|
||||
} ks_bool_t;
|
||||
|
||||
#ifndef __FUNCTION__
|
||||
#define __FUNCTION__ (const char *)__func__
|
||||
|
@ -164,16 +170,49 @@ typedef enum {
|
|||
#define KS_LOG_CRIT KS_PRE, KS_LOG_LEVEL_CRIT
|
||||
#define KS_LOG_ALERT KS_PRE, KS_LOG_LEVEL_ALERT
|
||||
#define KS_LOG_EMERG KS_PRE, KS_LOG_LEVEL_EMERG
|
||||
typedef void (*ks_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...);
|
||||
typedef void (*ks_listen_callback_t)(ks_socket_t server_sock, ks_socket_t client_sock, struct sockaddr_in *addr);
|
||||
|
||||
struct ks_pool_s;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* defined(__cplusplus) */
|
||||
typedef struct ks_pool_s ks_pool_t;
|
||||
typedef void (*ks_hash_destructor_t)(void *ptr);
|
||||
|
||||
typedef enum {
|
||||
KS_MPCL_ANNOUNCE,
|
||||
KS_MPCL_TEARDOWN,
|
||||
KS_MPCL_DESTROY
|
||||
} ks_pool_cleanup_action_t;
|
||||
|
||||
#endif /* defined(_KS_TYPES_H_) */
|
||||
typedef enum {
|
||||
KS_MPCL_FREE,
|
||||
KS_MPCL_GLOBAL_FREE,
|
||||
} ks_pool_cleanup_type_t;
|
||||
|
||||
typedef union {
|
||||
struct sockaddr_in v4;
|
||||
struct sockaddr_in6 v6;
|
||||
} ks_sockaddr_in_t;
|
||||
|
||||
typedef struct {
|
||||
int family;
|
||||
ks_sockaddr_in_t v;
|
||||
ks_port_t port;
|
||||
char host[48];
|
||||
} ks_sockaddr_t;
|
||||
|
||||
typedef void (*ks_pool_cleanup_fn_t) (ks_pool_t *mpool, void *ptr, void *arg, int type, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t ctype);
|
||||
|
||||
typedef void (*ks_logger_t) (const char *file, const char *func, int line, int level, const char *fmt, ...);
|
||||
typedef void (*ks_listen_callback_t) (ks_socket_t server_sock, ks_socket_t client_sock, ks_sockaddr_t *addr, void *user_data);
|
||||
|
||||
typedef int64_t ks_time_t;
|
||||
|
||||
struct ks_q_s;
|
||||
typedef struct ks_q_s ks_q_t;
|
||||
typedef void (*ks_flush_fn_t)(ks_q_t *q, void *ptr, void *flush_data);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* defined(_KS_TYPES_H_) */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
|
@ -185,4 +224,3 @@ typedef void (*ks_listen_callback_t)(ks_socket_t server_sock, ks_socket_t client
|
|||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
||||
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2015, Anthony Minessale II
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 _KS_UTP_H_
|
||||
#define _KS_UTP_H_
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
typedef struct utp_socket utp_socket_t;
|
||||
typedef struct utp_context utp_context_t;
|
||||
|
||||
enum {
|
||||
UTP_UDP_DONTFRAG = 2, // Used to be a #define as UDP_IP_DONTFRAG
|
||||
};
|
||||
|
||||
enum {
|
||||
/* socket has reveived syn-ack (notification only for outgoing connection completion) this implies writability */
|
||||
UTP_STATE_CONNECT = 1,
|
||||
|
||||
/* socket is able to send more data */
|
||||
UTP_STATE_WRITABLE = 2,
|
||||
|
||||
/* connection closed */
|
||||
UTP_STATE_EOF = 3,
|
||||
|
||||
/* socket is being destroyed, meaning all data has been sent if possible. it is not valid to refer to the socket after this state change occurs */
|
||||
UTP_STATE_DESTROYING = 4,
|
||||
};
|
||||
|
||||
/* Errors codes that can be passed to UTP_ON_ERROR callback */
|
||||
enum {
|
||||
UTP_ECONNREFUSED = 0,
|
||||
UTP_ECONNRESET,
|
||||
UTP_ETIMEDOUT,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* callback names */
|
||||
UTP_ON_FIREWALL = 0,
|
||||
UTP_ON_ACCEPT,
|
||||
UTP_ON_CONNECT,
|
||||
UTP_ON_ERROR,
|
||||
UTP_ON_READ,
|
||||
UTP_ON_OVERHEAD_STATISTICS,
|
||||
UTP_ON_STATE_CHANGE,
|
||||
UTP_GET_READ_BUFFER_SIZE,
|
||||
UTP_ON_DELAY_SAMPLE,
|
||||
UTP_GET_UDP_MTU,
|
||||
UTP_GET_UDP_OVERHEAD,
|
||||
UTP_GET_MILLISECONDS,
|
||||
UTP_GET_MICROSECONDS,
|
||||
UTP_GET_RANDOM,
|
||||
UTP_LOG,
|
||||
UTP_SENDTO,
|
||||
|
||||
/* context and socket options that may be set/queried */
|
||||
UTP_LOG_NORMAL,
|
||||
UTP_LOG_MTU,
|
||||
UTP_LOG_DEBUG,
|
||||
UTP_SNDBUF,
|
||||
UTP_RCVBUF,
|
||||
UTP_TARGET_DELAY,
|
||||
|
||||
/* must be last */
|
||||
UTP_ARRAY_SIZE,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
utp_context_t *context;
|
||||
utp_socket_t *socket;
|
||||
size_t len;
|
||||
uint32_t flags;
|
||||
int callback_type;
|
||||
const uint8_t *buf;
|
||||
|
||||
union {
|
||||
const struct sockaddr *address;
|
||||
int send;
|
||||
int sample_ms;
|
||||
int error_code;
|
||||
int state;
|
||||
} d1;
|
||||
|
||||
union {
|
||||
socklen_t address_len;
|
||||
int type;
|
||||
} d2;
|
||||
} utp_callback_arguments;
|
||||
|
||||
typedef uint64_t utp_callback_t (utp_callback_arguments *);
|
||||
|
||||
/* Returned by utp_get_context_stats() */
|
||||
typedef struct {
|
||||
uint32_t _nraw_recv[5]; // total packets recieved less than 300/600/1200/MTU bytes fpr all connections (context-wide)
|
||||
uint32_t _nraw_send[5]; // total packets sent less than 300/600/1200/MTU bytes for all connections (context-wide)
|
||||
} utp_context_stats;
|
||||
|
||||
// Returned by utp_get_stats()
|
||||
typedef struct {
|
||||
uint64_t nbytes_recv; // total bytes received
|
||||
uint64_t nbytes_xmit; // total bytes transmitted
|
||||
uint32_t rexmit; // retransmit counter
|
||||
uint32_t fastrexmit; // fast retransmit counter
|
||||
uint32_t nxmit; // transmit counter
|
||||
uint32_t nrecv; // receive counter (total)
|
||||
uint32_t nduprecv; // duplicate receive counter
|
||||
uint32_t mtu_guess; // Best guess at MTU
|
||||
} utp_socket_stats;
|
||||
|
||||
#define UTP_IOV_MAX 1024
|
||||
|
||||
/* For utp_writev, to writes data from multiple buffers */
|
||||
struct utp_iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
// Public Functions
|
||||
utp_context_t* utp_init (int version);
|
||||
void utp_destroy (utp_context_t *ctx);
|
||||
void utp_set_callback (utp_context_t *ctx, int callback_name, utp_callback_t *proc);
|
||||
void* utp_context_set_userdata (utp_context_t *ctx, void *userdata);
|
||||
void* utp_context_get_userdata (utp_context_t *ctx);
|
||||
int utp_context_set_option (utp_context_t *ctx, int opt, int val);
|
||||
int utp_context_get_option (utp_context_t *ctx, int opt);
|
||||
int utp_process_udp (utp_context_t *ctx, const uint8_t *buf, size_t len, const struct sockaddr *to, socklen_t tolen);
|
||||
int utp_process_icmp_error (utp_context_t *ctx, const uint8_t *buffer, size_t len, const struct sockaddr *to, socklen_t tolen);
|
||||
int utp_process_icmp_fragmentation (utp_context_t *ctx, const uint8_t *buffer, size_t len, const struct sockaddr *to, socklen_t tolen, uint16_t next_hop_mtu);
|
||||
void utp_check_timeouts (utp_context_t *ctx);
|
||||
void utp_issue_deferred_acks (utp_context_t *ctx);
|
||||
utp_context_stats* utp_get_context_stats (utp_context_t *ctx);
|
||||
utp_socket_t* utp_create_socket (utp_context_t *ctx);
|
||||
void* utp_set_userdata (utp_socket_t *s, void *userdata);
|
||||
void* utp_get_userdata (utp_socket_t *s);
|
||||
int utp_setsockopt (utp_socket_t *s, int opt, int val);
|
||||
int utp_getsockopt (utp_socket_t *s, int opt);
|
||||
int utp_connect (utp_socket_t *s, const struct sockaddr *to, socklen_t tolen);
|
||||
ssize_t utp_write (utp_socket_t *s, void *buf, size_t count);
|
||||
ssize_t utp_writev (utp_socket_t *s, struct utp_iovec *iovec, size_t num_iovecs);
|
||||
int utp_getpeername (utp_socket_t *s, struct sockaddr *addr, socklen_t *addrlen);
|
||||
void utp_read_drained (utp_socket_t *s);
|
||||
int utp_get_delays (utp_socket_t *s, uint32_t *ours, uint32_t *theirs, uint32_t *age);
|
||||
utp_socket_stats* utp_get_stats (utp_socket_t *s);
|
||||
utp_context_t* utp_get_context (utp_socket_t *s);
|
||||
void utp_close (utp_socket_t *s);
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* defined(_KS_UTP_H_) */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2014, Anthony Minessale II
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 _KWS_H
|
||||
#define _KWS_H
|
||||
|
||||
#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
#define B64BUFFLEN 1024
|
||||
#include "ks.h"
|
||||
|
||||
KS_BEGIN_EXTERN_C
|
||||
|
||||
typedef enum {
|
||||
WS_NONE = 0,
|
||||
WS_NORMAL = 1000,
|
||||
WS_PROTO_ERR = 1002,
|
||||
WS_DATA_TOO_BIG = 1009
|
||||
} kws_cause_t;
|
||||
|
||||
typedef enum {
|
||||
WSOC_CONTINUATION = 0x0,
|
||||
WSOC_TEXT = 0x1,
|
||||
WSOC_BINARY = 0x2,
|
||||
WSOC_CLOSE = 0x8,
|
||||
WSOC_PING = 0x9,
|
||||
WSOC_PONG = 0xA
|
||||
} kws_opcode_t;
|
||||
|
||||
typedef enum {
|
||||
KWS_CLIENT,
|
||||
KWS_SERVER
|
||||
} kws_type_t;
|
||||
|
||||
typedef enum {
|
||||
KWS_CLOSE_SOCK,
|
||||
KWS_BLOCK,
|
||||
KWS_STAY_OPEN
|
||||
} kws_flag_t;
|
||||
|
||||
struct kws_s;
|
||||
typedef struct kws_s kws_t;
|
||||
|
||||
|
||||
KS_DECLARE(ks_ssize_t) kws_read_frame(kws_t *kws, kws_opcode_t *oc, uint8_t **data);
|
||||
KS_DECLARE(ks_ssize_t) kws_write_frame(kws_t *kws, kws_opcode_t oc, void *data, ks_size_t bytes);
|
||||
KS_DECLARE(ks_ssize_t) kws_raw_read(kws_t *kws, void *data, ks_size_t bytes, int block);
|
||||
KS_DECLARE(ks_ssize_t) kws_raw_write(kws_t *kws, void *data, ks_size_t bytes);
|
||||
KS_DECLARE(ks_status_t) kws_init(kws_t **kwsP, ks_socket_t sock, SSL_CTX *ssl_ctx, const char *client_data, kws_flag_t flags, ks_pool_t *pool);
|
||||
KS_DECLARE(ks_ssize_t) kws_close(kws_t *kws, int16_t reason);
|
||||
KS_DECLARE(void) kws_destroy(kws_t **kwsP);
|
||||
KS_DECLARE(ks_status_t) kws_get_buffer(kws_t *kws, char **bufP, ks_size_t *buflen);
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
static inline uint64_t get_unaligned_uint64(const void *p)
|
||||
{
|
||||
const struct { uint64_t d; } __attribute__((packed)) *pp = p;
|
||||
return pp->d;
|
||||
}
|
||||
#endif
|
||||
|
||||
KS_END_EXTERN_C
|
||||
|
||||
#endif /* defined(_KWS_H_) */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -32,20 +32,20 @@ extern "C" {
|
|||
#include <sys/types.h>
|
||||
|
||||
#ifndef SIMCLIST_NO_DUMPRESTORE
|
||||
# ifndef _WIN32
|
||||
# include <sys/time.h> /* list_dump_info_t's struct timeval */
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h> /* list_dump_info_t's struct timeval */
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Be friend of both C90 and C99 compilers */
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
/* "inline" and "restrict" are keywords */
|
||||
/* "inline" and "restrict" are keywords */
|
||||
#else
|
||||
# define inline /* inline */
|
||||
# define restrict /* restrict */
|
||||
#define inline /* inline */
|
||||
#define restrict /* restrict */
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -58,13 +58,13 @@ extern "C" {
|
|||
|
||||
#ifndef SIMCLIST_NO_DUMPRESTORE
|
||||
typedef struct {
|
||||
uint16_t version; /* dump version */
|
||||
struct timeval timestamp; /* when the list has been dumped, seconds since UNIX epoch */
|
||||
uint16_t version; /* dump version */
|
||||
struct timeval timestamp; /* when the list has been dumped, seconds since UNIX epoch */
|
||||
uint32_t list_size;
|
||||
uint32_t list_numels;
|
||||
list_hash_t list_hash; /* hash of the list when dumped, or 0 if invalid */
|
||||
list_hash_t list_hash; /* hash of the list when dumped, or 0 if invalid */
|
||||
uint32_t dumpsize;
|
||||
int consistent; /* 1 if the dump is verified complete/consistent; 0 otherwise */
|
||||
int consistent; /* 1 if the dump is verified complete/consistent; 0 otherwise */
|
||||
} list_dump_info_t;
|
||||
#endif
|
||||
|
||||
|
@ -77,7 +77,7 @@ extern "C" {
|
|||
*
|
||||
* It is responsability of the function to handle possible NULL values.
|
||||
*/
|
||||
typedef int (*element_comparator)(const void *a, const void *b);
|
||||
typedef int (*element_comparator) (const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* a seeker of elements.
|
||||
|
@ -90,7 +90,7 @@ extern "C" {
|
|||
* It is responsability of the function to handle possible NULL values in any
|
||||
* argument.
|
||||
*/
|
||||
typedef int (*element_seeker)(const void *el, const void *indicator);
|
||||
typedef int (*element_seeker) (const void *el, const void *indicator);
|
||||
|
||||
/**
|
||||
* an element lenght meter.
|
||||
|
@ -101,7 +101,7 @@ extern "C" {
|
|||
*
|
||||
* It is responsability of the function to handle possible NULL values.
|
||||
*/
|
||||
typedef size_t (*element_meter)(const void *el);
|
||||
typedef size_t (*element_meter) (const void *el);
|
||||
|
||||
/**
|
||||
* a function computing the hash of elements.
|
||||
|
@ -112,7 +112,7 @@ extern "C" {
|
|||
*
|
||||
* It is responsability of the function to handle possible NULL values.
|
||||
*/
|
||||
typedef list_hash_t (*element_hash_computer)(const void *el);
|
||||
typedef list_hash_t (*element_hash_computer) (const void *el);
|
||||
|
||||
/**
|
||||
* a function for serializing an element.
|
||||
|
@ -132,7 +132,7 @@ extern "C" {
|
|||
* @param serialize_buffer reference to fill with the length of the buffer
|
||||
* @return reference to the buffer with the serialized data
|
||||
*/
|
||||
typedef void *(*element_serializer)(const void *restrict el, uint32_t *restrict serializ_len);
|
||||
typedef void *(*element_serializer) (const void *restrict el, uint32_t *restrict serializ_len);
|
||||
|
||||
/**
|
||||
* a function for un-serializing an element.
|
||||
|
@ -149,7 +149,7 @@ extern "C" {
|
|||
* @param data_len reference to the location where to store the length of the data in the buffer returned
|
||||
* @return reference to a buffer with the original, unserialized representation of the element
|
||||
*/
|
||||
typedef void *(*element_unserializer)(const void *restrict data, uint32_t *restrict data_len);
|
||||
typedef void *(*element_unserializer) (const void *restrict data, uint32_t *restrict data_len);
|
||||
|
||||
/* [private-use] list entry -- olds actual user datum */
|
||||
struct list_entry_s {
|
||||
|
@ -776,49 +776,49 @@ extern "C" {
|
|||
* ready-made comparator for int8_t elements.
|
||||
* @see list_attributes_comparator()
|
||||
*/
|
||||
int list_comparator_int8_t(const void *a, const void *b);
|
||||
int list_comparator_int8_t (const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* ready-made comparator for int16_t elements.
|
||||
* @see list_attributes_comparator()
|
||||
*/
|
||||
int list_comparator_int16_t(const void *a, const void *b);
|
||||
int list_comparator_int16_t (const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* ready-made comparator for int32_t elements.
|
||||
* @see list_attributes_comparator()
|
||||
*/
|
||||
int list_comparator_int32_t(const void *a, const void *b);
|
||||
int list_comparator_int32_t (const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* ready-made comparator for int64_t elements.
|
||||
* @see list_attributes_comparator()
|
||||
*/
|
||||
int list_comparator_int64_t(const void *a, const void *b);
|
||||
int list_comparator_int64_t (const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* ready-made comparator for uint8_t elements.
|
||||
* @see list_attributes_comparator()
|
||||
*/
|
||||
int list_comparator_uint8_t(const void *a, const void *b);
|
||||
int list_comparator_uint8_t (const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* ready-made comparator for uint16_t elements.
|
||||
* @see list_attributes_comparator()
|
||||
*/
|
||||
int list_comparator_uint16_t(const void *a, const void *b);
|
||||
int list_comparator_uint16_t (const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* ready-made comparator for uint32_t elements.
|
||||
* @see list_attributes_comparator()
|
||||
*/
|
||||
int list_comparator_uint32_t(const void *a, const void *b);
|
||||
int list_comparator_uint32_t (const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* ready-made comparator for uint64_t elements.
|
||||
* @see list_attributes_comparator()
|
||||
*/
|
||||
int list_comparator_uint64_t(const void *a, const void *b);
|
||||
int list_comparator_uint64_t (const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* ready-made comparator for float elements.
|
||||
|
@ -843,49 +843,49 @@ extern "C" {
|
|||
* ready-made metric function for int8_t elements.
|
||||
* @see list_attributes_copy()
|
||||
*/
|
||||
size_t list_meter_int8_t(const void *el);
|
||||
size_t list_meter_int8_t (const void *el);
|
||||
|
||||
/**
|
||||
* ready-made metric function for int16_t elements.
|
||||
* @see list_attributes_copy()
|
||||
*/
|
||||
size_t list_meter_int16_t(const void *el);
|
||||
size_t list_meter_int16_t (const void *el);
|
||||
|
||||
/**
|
||||
* ready-made metric function for int32_t elements.
|
||||
* @see list_attributes_copy()
|
||||
*/
|
||||
size_t list_meter_int32_t(const void *el);
|
||||
size_t list_meter_int32_t (const void *el);
|
||||
|
||||
/**
|
||||
* ready-made metric function for int64_t elements.
|
||||
* @see list_attributes_copy()
|
||||
*/
|
||||
size_t list_meter_int64_t(const void *el);
|
||||
size_t list_meter_int64_t (const void *el);
|
||||
|
||||
/**
|
||||
* ready-made metric function for uint8_t elements.
|
||||
* @see list_attributes_copy()
|
||||
*/
|
||||
size_t list_meter_uint8_t(const void *el);
|
||||
size_t list_meter_uint8_t (const void *el);
|
||||
|
||||
/**
|
||||
* ready-made metric function for uint16_t elements.
|
||||
* @see list_attributes_copy()
|
||||
*/
|
||||
size_t list_meter_uint16_t(const void *el);
|
||||
size_t list_meter_uint16_t (const void *el);
|
||||
|
||||
/**
|
||||
* ready-made metric function for uint32_t elements.
|
||||
* @see list_attributes_copy()
|
||||
*/
|
||||
size_t list_meter_uint32_t(const void *el);
|
||||
size_t list_meter_uint32_t (const void *el);
|
||||
|
||||
/**
|
||||
* ready-made metric function for uint64_t elements.
|
||||
* @see list_attributes_copy()
|
||||
*/
|
||||
size_t list_meter_uint64_t(const void *el);
|
||||
size_t list_meter_uint64_t (const void *el);
|
||||
|
||||
/**
|
||||
* ready-made metric function for float elements.
|
||||
|
@ -975,9 +975,7 @@ extern "C" {
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
|
|
|
@ -31,346 +31,78 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
/* Use select on windows and poll everywhere else.
|
||||
Select is the devil. Especially if you are doing a lot of small socket connections.
|
||||
If your FD number is bigger than 1024 you will silently create memory corruption.
|
||||
|
||||
If you have build errors on your platform because you don't have poll find a way to detect it and #define KS_USE_SELECT and #undef KS_USE_POLL
|
||||
All of this will be upgraded to autoheadache eventually.
|
||||
*/
|
||||
|
||||
/* TBD for win32 figure out how to tell if you have WSAPoll (vista or higher) and use it when available by #defining KS_USE_WSAPOLL (see below) */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define FD_SETSIZE 8192
|
||||
#define KS_USE_SELECT
|
||||
#else
|
||||
#define KS_USE_POLL
|
||||
#endif
|
||||
|
||||
#include <ks.h>
|
||||
#ifndef WIN32
|
||||
#define closesocket(x) shutdown(x, 2); close(x)
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#else
|
||||
#pragma warning (disable:6386)
|
||||
/* These warnings need to be ignored warning in sdk header */
|
||||
#include <Ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#ifndef errno
|
||||
#define errno WSAGetLastError()
|
||||
#endif
|
||||
#ifndef EINTR
|
||||
#define EINTR WSAEINTR
|
||||
#endif
|
||||
#pragma warning (default:6386)
|
||||
#endif
|
||||
|
||||
#ifdef KS_USE_POLL
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifndef KS_MIN
|
||||
#define KS_MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||
#endif
|
||||
#ifndef KS_MAX
|
||||
#define KS_MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
#endif
|
||||
#ifndef KS_CLAMP
|
||||
#define KS_CLAMP(min,max,val) (KS_MIN(max,KS_MAX(val,min)))
|
||||
#endif
|
||||
static ks_pool_t *pool = NULL;
|
||||
|
||||
|
||||
/* Written by Marc Espie, public domain */
|
||||
#define KS_CTYPE_NUM_CHARS 256
|
||||
|
||||
const short _ks_C_toupper_[1 + KS_CTYPE_NUM_CHARS] = {
|
||||
EOF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
||||
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||
};
|
||||
|
||||
const short *_ks_toupper_tab_ = _ks_C_toupper_;
|
||||
|
||||
KS_DECLARE(int) ks_toupper(int c)
|
||||
KS_DECLARE(void) ks_random_string(char *buf, uint16_t len, char *set)
|
||||
{
|
||||
if ((unsigned int)c > 255)
|
||||
return(c);
|
||||
if (c < -1)
|
||||
return EOF;
|
||||
return((_ks_toupper_tab_ + 1)[c]);
|
||||
}
|
||||
char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
int max;
|
||||
uint16_t x;
|
||||
|
||||
const short _ks_C_tolower_[1 + KS_CTYPE_NUM_CHARS] = {
|
||||
EOF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
||||
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
|
||||
'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||
};
|
||||
|
||||
const short *_ks_tolower_tab_ = _ks_C_tolower_;
|
||||
|
||||
KS_DECLARE(int) ks_tolower(int c)
|
||||
{
|
||||
if ((unsigned int)c > 255)
|
||||
return(c);
|
||||
if (c < -1)
|
||||
return EOF;
|
||||
return((_ks_tolower_tab_ + 1)[c]);
|
||||
}
|
||||
|
||||
KS_DECLARE(const char *)ks_stristr(const char *instr, const char *str)
|
||||
{
|
||||
/*
|
||||
** Rev History: 16/07/97 Greg Thayer Optimized
|
||||
** 07/04/95 Bob Stout ANSI-fy
|
||||
** 02/03/94 Fred Cole Original
|
||||
** 09/01/03 Bob Stout Bug fix (lines 40-41) per Fred Bulback
|
||||
**
|
||||
** Hereby donated to public domain.
|
||||
*/
|
||||
const char *pptr, *sptr, *start;
|
||||
|
||||
if (!str || !instr)
|
||||
return NULL;
|
||||
|
||||
for (start = str; *start; start++) {
|
||||
/* find start of pattern in string */
|
||||
for (; ((*start) && (ks_toupper(*start) != ks_toupper(*instr))); start++);
|
||||
|
||||
if (!*start)
|
||||
return NULL;
|
||||
|
||||
pptr = instr;
|
||||
sptr = start;
|
||||
|
||||
while (ks_toupper(*sptr) == ks_toupper(*pptr)) {
|
||||
sptr++;
|
||||
pptr++;
|
||||
|
||||
/* if end of pattern then pattern was found */
|
||||
if (!*pptr)
|
||||
return (start);
|
||||
|
||||
if (!*sptr)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef vsnprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
int vasprintf(char **ret, const char *format, va_list ap);
|
||||
|
||||
KS_DECLARE(int) ks_vasprintf(char **ret, const char *fmt, va_list ap)
|
||||
{
|
||||
#if !defined(WIN32) && !defined(__sun)
|
||||
return vasprintf(ret, fmt, ap);
|
||||
#else
|
||||
char *buf;
|
||||
int len;
|
||||
size_t buflen;
|
||||
va_list ap2;
|
||||
char *tmp = NULL;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1500
|
||||
/* hack for incorrect assumption in msvc header files for code analysis */
|
||||
__analysis_assume(tmp);
|
||||
#endif
|
||||
ap2 = ap;
|
||||
#else
|
||||
va_copy(ap2, ap);
|
||||
#endif
|
||||
|
||||
len = vsnprintf(tmp, 0, fmt, ap2);
|
||||
|
||||
if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) {
|
||||
len = vsnprintf(buf, buflen, fmt, ap);
|
||||
*ret = buf;
|
||||
} else {
|
||||
*ret = NULL;
|
||||
len = -1;
|
||||
if (!set) {
|
||||
set = chars;
|
||||
}
|
||||
|
||||
va_end(ap2);
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
max = (int) strlen(set);
|
||||
|
||||
|
||||
|
||||
|
||||
KS_DECLARE(int) ks_snprintf(char *buffer, size_t count, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vsnprintf(buffer, count-1, fmt, ap);
|
||||
if (ret < 0)
|
||||
buffer[count-1] = '\0';
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
|
||||
{
|
||||
if (file && func && line && level && fmt) {
|
||||
return;
|
||||
for (x = 0; x < len; x++) {
|
||||
int j = (int) (max * 1.0 * rand() / (RAND_MAX + 1.0));
|
||||
buf[x] = set[j];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static const char *LEVEL_NAMES[] = {
|
||||
"EMERG",
|
||||
"ALERT",
|
||||
"CRIT",
|
||||
"ERROR",
|
||||
"WARNING",
|
||||
"NOTICE",
|
||||
"INFO",
|
||||
"DEBUG",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int ks_log_level = 7;
|
||||
|
||||
static const char *cut_path(const char *in)
|
||||
KS_DECLARE(ks_status_t) ks_global_set_cleanup(ks_pool_cleanup_fn_t fn, void *arg)
|
||||
{
|
||||
const char *p, *ret = in;
|
||||
char delims[] = "/\\";
|
||||
char *i;
|
||||
|
||||
for (i = delims; *i; i++) {
|
||||
p = in;
|
||||
while ((p = strchr(p, *i)) != 0) {
|
||||
ret = ++p;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return ks_pool_set_cleanup(ks_global_pool(), NULL, arg, 0, fn);
|
||||
}
|
||||
|
||||
|
||||
static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
|
||||
{
|
||||
const char *fp;
|
||||
char *data;
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
if (level < 0 || level > 7) {
|
||||
level = 7;
|
||||
}
|
||||
if (level > ks_log_level) {
|
||||
return;
|
||||
KS_DECLARE(ks_status_t) ks_init(void)
|
||||
{
|
||||
|
||||
srand(getpid() * (intptr_t)&pool + time(NULL));
|
||||
ks_ssl_init_ssl_locks();
|
||||
ks_global_pool();
|
||||
ks_rng_init();
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_shutdown(void)
|
||||
{
|
||||
ks_status_t status = KS_STATUS_SUCCESS;
|
||||
|
||||
ks_ssl_destroy_ssl_locks();
|
||||
//ks_rng_shutdown();
|
||||
|
||||
if (pool) {
|
||||
status = ks_pool_close(&pool);
|
||||
}
|
||||
|
||||
fp = cut_path(file);
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
ret = ks_vasprintf(&data, fmt, ap);
|
||||
|
||||
if (ret != -1) {
|
||||
fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], fp, line, func, data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ks_logger_t ks_log = null_logger;
|
||||
|
||||
KS_DECLARE(void) ks_global_set_logger(ks_logger_t logger)
|
||||
KS_DECLARE(ks_pool_t *) ks_global_pool(void)
|
||||
{
|
||||
if (logger) {
|
||||
ks_log = logger;
|
||||
} else {
|
||||
ks_log = null_logger;
|
||||
}
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_global_set_default_logger(int level)
|
||||
{
|
||||
if (level < 0 || level > 7) {
|
||||
level = 7;
|
||||
ks_status_t status;
|
||||
|
||||
if (!pool) {
|
||||
if ((status = ks_pool_open(&pool)) != KS_STATUS_SUCCESS) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
ks_log = default_logger;
|
||||
ks_log_level = level;
|
||||
return pool;
|
||||
}
|
||||
|
||||
KS_ENUM_NAMES(STATUS_NAMES, STATUS_STRINGS)
|
||||
KS_STR2ENUM(ks_str2ks_status, ks_status2str, ks_status_t, STATUS_NAMES, KS_STATUS_COUNT)
|
||||
|
||||
KS_DECLARE(size_t) ks_url_encode(const char *url, char *buf, size_t len)
|
||||
{
|
||||
const char *p;
|
||||
|
@ -408,7 +140,7 @@ KS_DECLARE(size_t) ks_url_encode(const char *url, char *buf, size_t len)
|
|||
return x;
|
||||
}
|
||||
|
||||
KS_DECLARE(char *)ks_url_decode(char *s)
|
||||
KS_DECLARE(char *) ks_url_decode(char *s)
|
||||
{
|
||||
char *o;
|
||||
unsigned int tmp;
|
||||
|
@ -425,316 +157,30 @@ KS_DECLARE(char *)ks_url_decode(char *s)
|
|||
return s;
|
||||
}
|
||||
|
||||
|
||||
static int ks_socket_reuseaddr(ks_socket_t socket)
|
||||
KS_DECLARE(int) ks_cpu_count(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
BOOL reuse_addr = TRUE;
|
||||
return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse_addr, sizeof(reuse_addr));
|
||||
#else
|
||||
int reuse_addr = 1;
|
||||
return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
struct thread_handler {
|
||||
ks_listen_callback_t callback;
|
||||
ks_socket_t server_sock;
|
||||
ks_socket_t client_sock;
|
||||
struct sockaddr_in addr;
|
||||
};
|
||||
|
||||
static void *client_thread(ks_thread_t *me, void *obj)
|
||||
{
|
||||
struct thread_handler *handler = (struct thread_handler *) obj;
|
||||
|
||||
handler->callback(handler->server_sock, handler->client_sock, &handler->addr);
|
||||
free(handler);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_listen(const char *host, ks_port_t port, ks_listen_callback_t callback)
|
||||
{
|
||||
ks_socket_t server_sock = KS_SOCK_INVALID;
|
||||
struct sockaddr_in addr;
|
||||
ks_status_t status = KS_SUCCESS;
|
||||
|
||||
if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
|
||||
return KS_FAIL;
|
||||
}
|
||||
|
||||
ks_socket_reuseaddr(server_sock);
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
status = KS_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (listen(server_sock, 10000) < 0) {
|
||||
status = KS_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int client_sock;
|
||||
struct sockaddr_in echoClntAddr;
|
||||
#ifdef WIN32
|
||||
int clntLen;
|
||||
#else
|
||||
unsigned int clntLen;
|
||||
#endif
|
||||
|
||||
clntLen = sizeof(echoClntAddr);
|
||||
|
||||
if ((client_sock = accept(server_sock, (struct sockaddr *) &echoClntAddr, &clntLen)) == KS_SOCK_INVALID) {
|
||||
status = KS_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
callback(server_sock, client_sock, &echoClntAddr);
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
if (server_sock != KS_SOCK_INVALID) {
|
||||
closesocket(server_sock);
|
||||
server_sock = KS_SOCK_INVALID;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_listen_threaded(const char *host, ks_port_t port, ks_listen_callback_t callback, int max)
|
||||
{
|
||||
ks_socket_t server_sock = KS_SOCK_INVALID;
|
||||
struct sockaddr_in addr;
|
||||
ks_status_t status = KS_SUCCESS;
|
||||
struct thread_handler *handler = NULL;
|
||||
|
||||
if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
|
||||
return KS_FAIL;
|
||||
}
|
||||
|
||||
ks_socket_reuseaddr(server_sock);
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
status = KS_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (listen(server_sock, max) < 0) {
|
||||
status = KS_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int client_sock;
|
||||
struct sockaddr_in echoClntAddr;
|
||||
#ifdef WIN32
|
||||
int clntLen;
|
||||
#else
|
||||
unsigned int clntLen;
|
||||
#endif
|
||||
|
||||
clntLen = sizeof(echoClntAddr);
|
||||
|
||||
if ((client_sock = accept(server_sock, (struct sockaddr *) &echoClntAddr, &clntLen)) == KS_SOCK_INVALID) {
|
||||
status = KS_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
handler = malloc(sizeof(*handler));
|
||||
ks_assert(handler);
|
||||
|
||||
memset(handler, 0, sizeof(*handler));
|
||||
handler->callback = callback;
|
||||
handler->server_sock = server_sock;
|
||||
handler->client_sock = client_sock;
|
||||
handler->addr = echoClntAddr;
|
||||
|
||||
ks_thread_create_detached(client_thread, handler);
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
if (server_sock != KS_SOCK_INVALID) {
|
||||
closesocket(server_sock);
|
||||
server_sock = KS_SOCK_INVALID;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* USE WSAPoll on vista or higher */
|
||||
#ifdef KS_USE_WSAPOLL
|
||||
KS_DECLARE(int) ks_wait_sock(ks_socket_t sock, uint32_t ms, ks_poll_t flags)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef KS_USE_SELECT
|
||||
#ifdef WIN32
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 6262 ) /* warning C6262: Function uses '98348' bytes of stack: exceeds /analyze:stacksize'16384'. Consider moving some data to heap */
|
||||
#endif
|
||||
KS_DECLARE(int) ks_wait_sock(ks_socket_t sock, uint32_t ms, ks_poll_t flags)
|
||||
{
|
||||
int s = 0, r = 0;
|
||||
fd_set rfds;
|
||||
fd_set wfds;
|
||||
fd_set efds;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
FD_ZERO(&efds);
|
||||
int cpu_count;
|
||||
|
||||
#ifndef WIN32
|
||||
/* Wouldn't you rather know?? */
|
||||
assert(sock <= FD_SETSIZE);
|
||||
#endif
|
||||
|
||||
if ((flags & KS_POLL_READ)) {
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4127 )
|
||||
FD_SET(sock, &rfds);
|
||||
#pragma warning( pop )
|
||||
cpu_count = sysconf (_SC_NPROCESSORS_ONLN);
|
||||
#else
|
||||
FD_SET(sock, &rfds);
|
||||
#endif
|
||||
{
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo( &sysinfo );
|
||||
cpu_count = sysinfo.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
if ((flags & KS_POLL_WRITE)) {
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4127 )
|
||||
FD_SET(sock, &wfds);
|
||||
#pragma warning( pop )
|
||||
#else
|
||||
FD_SET(sock, &wfds);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((flags & KS_POLL_ERROR)) {
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4127 )
|
||||
FD_SET(sock, &efds);
|
||||
#pragma warning( pop )
|
||||
#else
|
||||
FD_SET(sock, &efds);
|
||||
#endif
|
||||
}
|
||||
|
||||
tv.tv_sec = ms / 1000;
|
||||
tv.tv_usec = (ms % 1000) * ms;
|
||||
|
||||
s = select(sock + 1, (flags & KS_POLL_READ) ? &rfds : NULL, (flags & KS_POLL_WRITE) ? &wfds : NULL, (flags & KS_POLL_ERROR) ? &efds : NULL, &tv);
|
||||
|
||||
if (s < 0) {
|
||||
r = s;
|
||||
} else if (s > 0) {
|
||||
if ((flags & KS_POLL_READ) && FD_ISSET(sock, &rfds)) {
|
||||
r |= KS_POLL_READ;
|
||||
}
|
||||
|
||||
if ((flags & KS_POLL_WRITE) && FD_ISSET(sock, &wfds)) {
|
||||
r |= KS_POLL_WRITE;
|
||||
}
|
||||
|
||||
if ((flags & KS_POLL_ERROR) && FD_ISSET(sock, &efds)) {
|
||||
r |= KS_POLL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
#ifdef WIN32
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef KS_USE_POLL
|
||||
KS_DECLARE(int) ks_wait_sock(ks_socket_t sock, uint32_t ms, ks_poll_t flags)
|
||||
{
|
||||
struct pollfd pfds[2] = { { 0 } };
|
||||
int s = 0, r = 0;
|
||||
|
||||
pfds[0].fd = sock;
|
||||
|
||||
if ((flags & KS_POLL_READ)) {
|
||||
pfds[0].events |= POLLIN;
|
||||
}
|
||||
|
||||
if ((flags & KS_POLL_WRITE)) {
|
||||
pfds[0].events |= POLLOUT;
|
||||
}
|
||||
|
||||
if ((flags & KS_POLL_ERROR)) {
|
||||
pfds[0].events |= POLLERR;
|
||||
}
|
||||
|
||||
s = poll(pfds, 1, ms);
|
||||
|
||||
if (s < 0) {
|
||||
r = s;
|
||||
} else if (s > 0) {
|
||||
if ((pfds[0].revents & POLLIN)) {
|
||||
r |= KS_POLL_READ;
|
||||
}
|
||||
if ((pfds[0].revents & POLLOUT)) {
|
||||
r |= KS_POLL_WRITE;
|
||||
}
|
||||
if ((pfds[0].revents & POLLERR)) {
|
||||
r |= KS_POLL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
KS_DECLARE(unsigned int) ks_separate_string_string(char *buf, const char *delim, char **array, unsigned int arraylen)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
char *d;
|
||||
size_t dlen = strlen(delim);
|
||||
|
||||
array[count++] = buf;
|
||||
|
||||
while (count < arraylen && array[count - 1]) {
|
||||
if ((d = strstr(array[count - 1], delim))) {
|
||||
*d = '\0';
|
||||
d += dlen;
|
||||
array[count++] = d;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
return count;
|
||||
return cpu_count;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -32,7 +32,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "ks_buffer.h"
|
||||
#include "ks.h"
|
||||
|
||||
static unsigned buffer_id = 0;
|
||||
|
||||
|
@ -61,7 +61,7 @@ KS_DECLARE(ks_status_t) ks_buffer_create(ks_buffer_t **buffer, ks_size_t blocksi
|
|||
new_buffer->data = malloc(start_len);
|
||||
if (!new_buffer->data) {
|
||||
free(new_buffer);
|
||||
return KS_FAIL;
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
memset(new_buffer->data, 0, start_len);
|
||||
}
|
||||
|
@ -73,10 +73,10 @@ KS_DECLARE(ks_status_t) ks_buffer_create(ks_buffer_t **buffer, ks_size_t blocksi
|
|||
new_buffer->head = new_buffer->data;
|
||||
|
||||
*buffer = new_buffer;
|
||||
return KS_SUCCESS;
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return KS_FAIL;
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_size_t) ks_buffer_len(ks_buffer_t *buffer)
|
||||
|
@ -163,7 +163,7 @@ KS_DECLARE(ks_size_t) ks_buffer_read_loop(ks_buffer_t *buffer, void *data, ks_si
|
|||
}
|
||||
buffer->head = buffer->data;
|
||||
buffer->used = buffer->actually_used;
|
||||
len = ks_buffer_read(buffer, (char*)data + len, datalen - len);
|
||||
len = ks_buffer_read(buffer, (char *) data + len, datalen - len);
|
||||
buffer->loops--;
|
||||
}
|
||||
return len;
|
||||
|
@ -199,22 +199,23 @@ KS_DECLARE(ks_size_t) ks_buffer_packet_count(ks_buffer_t *buffer)
|
|||
{
|
||||
char *pe, *p, *e, *head = (char *) buffer->head;
|
||||
ks_size_t x = 0;
|
||||
|
||||
|
||||
ks_assert(buffer != NULL);
|
||||
|
||||
e = (head + buffer->used);
|
||||
|
||||
for (p = head; p && *p && p < e; p++) {
|
||||
if (*p == '\n') {
|
||||
pe = p+1;
|
||||
if (*pe == '\r') pe++;
|
||||
pe = p + 1;
|
||||
if (*pe == '\r')
|
||||
pe++;
|
||||
if (pe <= e && *pe == '\n') {
|
||||
p = pe++;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
@ -230,8 +231,9 @@ KS_DECLARE(ks_size_t) ks_buffer_read_packet(ks_buffer_t *buffer, void *data, ks_
|
|||
|
||||
for (p = head; p && *p && p < e; p++) {
|
||||
if (*p == '\n') {
|
||||
pe = p+1;
|
||||
if (*pe == '\r') pe++;
|
||||
pe = p + 1;
|
||||
if (*pe == '\r')
|
||||
pe++;
|
||||
if (pe <= e && *pe == '\n') {
|
||||
pe++;
|
||||
datalen = pe - head;
|
||||
|
@ -242,7 +244,7 @@ KS_DECLARE(ks_size_t) ks_buffer_read_packet(ks_buffer_t *buffer, void *data, ks_
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ks_buffer_read(buffer, data, datalen);
|
||||
}
|
||||
|
||||
|
@ -268,16 +270,16 @@ KS_DECLARE(ks_size_t) ks_buffer_write(ks_buffer_t *buffer, const void *data, ks_
|
|||
freespace = buffer->datalen - buffer->used;
|
||||
|
||||
/*
|
||||
if (buffer->data != buffer->head) {
|
||||
memmove(buffer->data, buffer->head, buffer->used);
|
||||
buffer->head = buffer->data;
|
||||
}
|
||||
*/
|
||||
|
||||
if (buffer->data != buffer->head) {
|
||||
memmove(buffer->data, buffer->head, buffer->used);
|
||||
buffer->head = buffer->data;
|
||||
}
|
||||
*/
|
||||
|
||||
if (freespace < datalen) {
|
||||
ks_size_t new_size, new_block_size;
|
||||
void *data1;
|
||||
|
||||
|
||||
new_size = buffer->datalen + datalen;
|
||||
new_block_size = buffer->datalen + buffer->blocksize;
|
||||
|
||||
|
@ -293,7 +295,7 @@ KS_DECLARE(ks_size_t) ks_buffer_write(ks_buffer_t *buffer, const void *data, ks_
|
|||
buffer->head = buffer->data;
|
||||
buffer->datalen = new_size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
freespace = buffer->datalen - buffer->used;
|
||||
|
||||
|
@ -322,7 +324,7 @@ KS_DECLARE(void) ks_buffer_zero(ks_buffer_t *buffer)
|
|||
KS_DECLARE(ks_size_t) ks_buffer_zwrite(ks_buffer_t *buffer, const void *data, ks_size_t datalen)
|
||||
{
|
||||
ks_size_t w;
|
||||
|
||||
|
||||
if (!(w = ks_buffer_write(buffer, data, datalen))) {
|
||||
ks_buffer_zero(buffer);
|
||||
return ks_buffer_write(buffer, data, datalen);
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
*/
|
||||
|
||||
#include "ks.h"
|
||||
#include "ks_config.h"
|
||||
|
||||
KS_DECLARE(int) ks_config_open_file(ks_config_t *cfg, const char *file_path)
|
||||
{
|
||||
|
@ -157,7 +156,7 @@ KS_DECLARE(int) ks_config_next_pair(ks_config_t *cfg, char **var, char **val)
|
|||
}
|
||||
|
||||
|
||||
if ((end = strchr(*var, ';')) && *(end+1) == *end) {
|
||||
if ((end = strchr(*var, ';')) && *(end + 1) == *end) {
|
||||
*end = '\0';
|
||||
end--;
|
||||
} else if ((end = strchr(*var, '\n')) != 0) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Cross Platform dso/dll load abstraction
|
||||
* Copyright(C) 2008 Michael Jerris
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so.
|
||||
*
|
||||
* This work is provided under this license on an "as is" basis, without warranty of any kind,
|
||||
* either expressed or implied, including, without limitation, warranties that the covered code
|
||||
* is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
|
||||
* risk as to the quality and performance of the covered code is with you. Should any covered
|
||||
* code prove defective in any respect, you (not the initial developer or any other contributor)
|
||||
* assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
|
||||
* constitutes an essential part of this license. No use of any covered code is authorized hereunder
|
||||
* except under this disclaimer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_dso_destroy(ks_dso_lib_t *lib) {
|
||||
if (lib && *lib) {
|
||||
FreeLibrary(*lib);
|
||||
*lib = NULL;
|
||||
}
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_dso_lib_t) ks_dso_open(const char *path, char **err) {
|
||||
HINSTANCE lib;
|
||||
#ifdef UNICODE
|
||||
size_t len = strlen(path) + 1;
|
||||
wchar_t *wpath = malloc(len);
|
||||
|
||||
size_t converted;
|
||||
mbstowcs_s(&converted, wpath, len, path, _TRUNCATE);
|
||||
#else
|
||||
char * wpath = path;
|
||||
#endif
|
||||
lib = LoadLibraryEx(wpath, NULL, 0);
|
||||
|
||||
if (!lib) {
|
||||
LoadLibraryEx(wpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
}
|
||||
|
||||
if (!lib) {
|
||||
DWORD error = GetLastError();
|
||||
char tmp[80];
|
||||
sprintf(tmp, "dll open error [%lu]\n", error);
|
||||
*err = strdup(tmp);
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
free(wpath);
|
||||
#endif
|
||||
return lib;
|
||||
}
|
||||
|
||||
KS_DECLARE(void*) ks_dso_func_sym(ks_dso_lib_t lib, const char *sym, char **err) {
|
||||
FARPROC func = GetProcAddress(lib, sym);
|
||||
if (!func) {
|
||||
DWORD error = GetLastError();
|
||||
char tmp[80];
|
||||
sprintf(tmp, "dll sym error [%lu]\n", error);
|
||||
*err = strdup(tmp);
|
||||
}
|
||||
return (void *)(intptr_t)func; // this should really be addr - ks_dso_func_data
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
** {========================================================================
|
||||
** This is an implementation of loadlib based on the dlfcn interface.
|
||||
** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
|
||||
** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
|
||||
** as an emulation layer on top of native functions.
|
||||
** =========================================================================
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_dso_destroy(ks_dso_lib_t *lib) {
|
||||
int rc;
|
||||
if (lib && *lib) {
|
||||
rc = dlclose(*lib);
|
||||
if (rc) {
|
||||
//ks_log(KS_LOG_ERROR, "Failed to close lib %p: %s\n", *lib, dlerror());
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
//ks_log(KS_LOG_DEBUG, "lib %p was closed with success\n", *lib);
|
||||
*lib = NULL;
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
//ks_log(KS_LOG_ERROR, "Invalid pointer provided to ks_dso_destroy\n");
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_dso_lib_t) ks_dso_open(const char *path, char **err) {
|
||||
void *lib = dlopen(path, RTLD_NOW | RTLD_LOCAL);
|
||||
if (lib == NULL) {
|
||||
*err = strdup(dlerror());
|
||||
}
|
||||
return lib;
|
||||
}
|
||||
|
||||
KS_DECLARE(void *) ks_dso_func_sym(ks_dso_lib_t lib, const char *sym, char **err) {
|
||||
void *func = dlsym(lib, sym);
|
||||
if (!func) {
|
||||
*err = strdup(dlerror());
|
||||
}
|
||||
return func;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,648 @@
|
|||
/*
|
||||
* Copyright (c) 2002, Christopher Clark
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 "ks.h"
|
||||
#include "ks_hash.h"
|
||||
|
||||
struct entry
|
||||
{
|
||||
void *k, *v;
|
||||
unsigned int h;
|
||||
ks_hash_flag_t flags;
|
||||
ks_hash_destructor_t destructor;
|
||||
struct entry *next;
|
||||
};
|
||||
|
||||
struct ks_hash_iterator {
|
||||
unsigned int pos;
|
||||
ks_locked_t locked;
|
||||
struct entry *e;
|
||||
struct ks_hash *h;
|
||||
};
|
||||
|
||||
struct ks_hash {
|
||||
ks_pool_t *pool;
|
||||
unsigned int tablelength;
|
||||
struct entry **table;
|
||||
unsigned int entrycount;
|
||||
unsigned int loadlimit;
|
||||
unsigned int primeindex;
|
||||
unsigned int (*hashfn) (void *k);
|
||||
int (*eqfn) (void *k1, void *k2);
|
||||
ks_hash_flag_t flags;
|
||||
ks_hash_destructor_t destructor;
|
||||
ks_rwl_t *rwl;
|
||||
ks_mutex_t *mutex;
|
||||
uint32_t readers;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
static inline unsigned int
|
||||
hash(ks_hash_t *h, void *k)
|
||||
{
|
||||
/* Aim to protect against poor hash functions by adding logic here
|
||||
* - logic taken from java 1.4 ks_hash source */
|
||||
unsigned int i = h->hashfn(k);
|
||||
i += ~(i << 9);
|
||||
i ^= ((i >> 14) | (i << 18)); /* >>> */
|
||||
i += (i << 4);
|
||||
i ^= ((i >> 10) | (i << 22)); /* >>> */
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* indexFor */
|
||||
static __inline__ unsigned int
|
||||
indexFor(unsigned int tablelength, unsigned int hashvalue) {
|
||||
return (hashvalue % tablelength);
|
||||
}
|
||||
|
||||
/* Only works if tablelength == 2^N */
|
||||
/*static inline unsigned int
|
||||
indexFor(unsigned int tablelength, unsigned int hashvalue)
|
||||
{
|
||||
return (hashvalue & (tablelength - 1u));
|
||||
}
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
//#define freekey(X) free(X)
|
||||
|
||||
/*
|
||||
Credit for primes table: Aaron Krowne
|
||||
http://br.endernet.org/~akrowne/
|
||||
http://planetmath.org/encyclopedia/GoodKs_HashPrimes.html
|
||||
*/
|
||||
static const unsigned int primes[] = {
|
||||
53, 97, 193, 389,
|
||||
769, 1543, 3079, 6151,
|
||||
12289, 24593, 49157, 98317,
|
||||
196613, 393241, 786433, 1572869,
|
||||
3145739, 6291469, 12582917, 25165843,
|
||||
50331653, 100663319, 201326611, 402653189,
|
||||
805306457, 1610612741
|
||||
};
|
||||
const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
|
||||
const float max_load_factor = 0.65f;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void ks_hash_cleanup(ks_pool_t *mpool, void *ptr, void *arg, int type, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t ctype)
|
||||
{
|
||||
//ks_hash_t *hash = (ks_hash_t *) ptr;
|
||||
|
||||
switch(action) {
|
||||
case KS_MPCL_ANNOUNCE:
|
||||
break;
|
||||
case KS_MPCL_TEARDOWN:
|
||||
break;
|
||||
case KS_MPCL_DESTROY:
|
||||
//ks_hash_destroy(&hash);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_hash_create(ks_hash_t **hp, ks_hash_mode_t mode, ks_hash_flag_t flags, ks_pool_t *pool)
|
||||
{
|
||||
return ks_hash_create_ex(hp, 16, NULL, NULL, mode, flags, NULL, pool);
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_hash_set_flags(ks_hash_t *h, ks_hash_flag_t flags)
|
||||
{
|
||||
h->flags = flags;
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_hash_set_destructor(ks_hash_t *h, ks_hash_destructor_t destructor)
|
||||
{
|
||||
h->destructor = destructor;
|
||||
}
|
||||
|
||||
|
||||
KS_DECLARE(ks_status_t)
|
||||
ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize,
|
||||
unsigned int (*hashf) (void*),
|
||||
int (*eqf) (void*,void*), ks_hash_mode_t mode, ks_hash_flag_t flags, ks_hash_destructor_t destructor, ks_pool_t *pool)
|
||||
{
|
||||
ks_hash_t *h;
|
||||
unsigned int pindex, size = primes[0];
|
||||
|
||||
switch(mode) {
|
||||
case KS_HASH_MODE_CASE_INSENSITIVE:
|
||||
ks_assert(hashf == NULL);
|
||||
hashf = ks_hash_default_ci;
|
||||
break;
|
||||
case KS_HASH_MODE_INT:
|
||||
ks_assert(hashf == NULL);
|
||||
ks_assert(eqf == NULL);
|
||||
hashf = ks_hash_default_int;
|
||||
eqf = ks_hash_equalkeys_int;
|
||||
break;
|
||||
case KS_HASH_MODE_INT64:
|
||||
ks_assert(hashf == NULL);
|
||||
ks_assert(eqf == NULL);
|
||||
hashf = ks_hash_default_int64;
|
||||
eqf = ks_hash_equalkeys_int64;
|
||||
break;
|
||||
case KS_HASH_MODE_PTR:
|
||||
ks_assert(hashf == NULL);
|
||||
ks_assert(eqf == NULL);
|
||||
hashf = ks_hash_default_ptr;
|
||||
eqf = ks_hash_equalkeys_ptr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags == KS_HASH_FLAG_DEFAULT) {
|
||||
flags = KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_RWLOCK;
|
||||
}
|
||||
|
||||
ks_assert(pool);
|
||||
if (!hashf) hashf = ks_hash_default;
|
||||
if (!eqf) eqf = ks_hash_equalkeys;
|
||||
if (!minsize) minsize = 16;
|
||||
|
||||
/* Check requested ks_hash isn't too large */
|
||||
if (minsize > (1u << 30)) {*hp = NULL; return KS_STATUS_FAIL;}
|
||||
/* Enforce size as prime */
|
||||
for (pindex=0; pindex < prime_table_length; pindex++) {
|
||||
if (primes[pindex] > minsize) {
|
||||
size = primes[pindex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
h = (ks_hash_t *) ks_pool_alloc(pool, sizeof(ks_hash_t));
|
||||
h->pool = pool;
|
||||
h->flags = flags;
|
||||
h->destructor = destructor;
|
||||
|
||||
if ((flags & KS_HASH_FLAG_RWLOCK)) {
|
||||
ks_rwl_create(&h->rwl, h->pool);
|
||||
}
|
||||
|
||||
ks_mutex_create(&h->mutex, KS_MUTEX_FLAG_DEFAULT, h->pool);
|
||||
|
||||
|
||||
if (NULL == h) abort(); /*oom*/
|
||||
|
||||
h->table = (struct entry **)ks_pool_alloc(h->pool, sizeof(struct entry*) * size);
|
||||
|
||||
if (NULL == h->table) abort(); /*oom*/
|
||||
|
||||
//memset(h->table, 0, size * sizeof(struct entry *));
|
||||
h->tablelength = size;
|
||||
h->primeindex = pindex;
|
||||
h->entrycount = 0;
|
||||
h->hashfn = hashf;
|
||||
h->eqfn = eqf;
|
||||
h->loadlimit = (unsigned int) ceil(size * max_load_factor);
|
||||
|
||||
*hp = h;
|
||||
|
||||
ks_pool_set_cleanup(pool, h, NULL, 0, ks_hash_cleanup);
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
ks_hash_expand(ks_hash_t *h)
|
||||
{
|
||||
/* Double the size of the table to accomodate more entries */
|
||||
struct entry **newtable;
|
||||
struct entry *e;
|
||||
struct entry **pE;
|
||||
unsigned int newsize, i, index;
|
||||
/* Check we're not hitting max capacity */
|
||||
if (h->primeindex == (prime_table_length - 1)) return 0;
|
||||
newsize = primes[++(h->primeindex)];
|
||||
|
||||
newtable = (struct entry **)ks_pool_alloc(h->pool, sizeof(struct entry*) * newsize);
|
||||
if (NULL != newtable)
|
||||
{
|
||||
memset(newtable, 0, newsize * sizeof(struct entry *));
|
||||
/* This algorithm is not 'stable'. ie. it reverses the list
|
||||
* when it transfers entries between the tables */
|
||||
for (i = 0; i < h->tablelength; i++) {
|
||||
while (NULL != (e = h->table[i])) {
|
||||
h->table[i] = e->next;
|
||||
index = indexFor(newsize,e->h);
|
||||
e->next = newtable[index];
|
||||
newtable[index] = e;
|
||||
}
|
||||
}
|
||||
ks_pool_safe_free(h->pool, h->table);
|
||||
h->table = newtable;
|
||||
}
|
||||
/* Plan B: realloc instead */
|
||||
else
|
||||
{
|
||||
newtable = (struct entry **)
|
||||
ks_pool_resize(h->pool, h->table, newsize * sizeof(struct entry *));
|
||||
if (NULL == newtable) { (h->primeindex)--; return 0; }
|
||||
h->table = newtable;
|
||||
memset(newtable[h->tablelength], 0, newsize - h->tablelength);
|
||||
for (i = 0; i < h->tablelength; i++) {
|
||||
for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
|
||||
index = indexFor(newsize,e->h);
|
||||
|
||||
if (index == i) {
|
||||
pE = &(e->next);
|
||||
} else {
|
||||
*pE = e->next;
|
||||
e->next = newtable[index];
|
||||
newtable[index] = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
h->tablelength = newsize;
|
||||
h->loadlimit = (unsigned int) ceil(newsize * max_load_factor);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
KS_DECLARE(unsigned int)
|
||||
ks_hash_count(ks_hash_t *h)
|
||||
{
|
||||
return h->entrycount;
|
||||
}
|
||||
|
||||
static void * _ks_hash_remove(ks_hash_t *h, void *k, unsigned int hashvalue, unsigned int index) {
|
||||
/* TODO: consider compacting the table when the load factor drops enough,
|
||||
* or provide a 'compact' method. */
|
||||
|
||||
struct entry *e;
|
||||
struct entry **pE;
|
||||
void *v;
|
||||
|
||||
|
||||
pE = &(h->table[index]);
|
||||
e = *pE;
|
||||
while (NULL != e) {
|
||||
/* Check hash value to short circuit heavier comparison */
|
||||
if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {
|
||||
*pE = e->next;
|
||||
h->entrycount--;
|
||||
v = e->v;
|
||||
if (e->flags & KS_HASH_FLAG_FREE_KEY) {
|
||||
ks_pool_free(h->pool, e->k);
|
||||
}
|
||||
if (e->flags & KS_HASH_FLAG_FREE_VALUE) {
|
||||
ks_pool_safe_free(h->pool, e->v);
|
||||
v = NULL;
|
||||
} else if (e->destructor) {
|
||||
e->destructor(e->v);
|
||||
v = e->v = NULL;
|
||||
} else if (h->destructor) {
|
||||
h->destructor(e->v);
|
||||
v = e->v = NULL;
|
||||
}
|
||||
ks_pool_safe_free(h->pool, e);
|
||||
return v;
|
||||
}
|
||||
pE = &(e->next);
|
||||
e = e->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
KS_DECLARE(int)
|
||||
ks_hash_insert_ex(ks_hash_t *h, void *k, void *v, ks_hash_flag_t flags, ks_hash_destructor_t destructor)
|
||||
{
|
||||
struct entry *e;
|
||||
unsigned int hashvalue = hash(h, k);
|
||||
unsigned index = indexFor(h->tablelength, hashvalue);
|
||||
|
||||
ks_hash_write_lock(h);
|
||||
|
||||
if (!flags) {
|
||||
flags = h->flags;
|
||||
}
|
||||
|
||||
if (flags & KS_HASH_FLAG_DUP_CHECK) {
|
||||
_ks_hash_remove(h, k, hashvalue, index);
|
||||
}
|
||||
|
||||
if (++(h->entrycount) > h->loadlimit)
|
||||
{
|
||||
/* Ignore the return value. If expand fails, we should
|
||||
* still try cramming just this value into the existing table
|
||||
* -- we may not have memory for a larger table, but one more
|
||||
* element may be ok. Next time we insert, we'll try expanding again.*/
|
||||
ks_hash_expand(h);
|
||||
index = indexFor(h->tablelength, hashvalue);
|
||||
}
|
||||
e = (struct entry *)ks_pool_alloc(h->pool, sizeof(struct entry));
|
||||
if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
|
||||
e->h = hashvalue;
|
||||
e->k = k;
|
||||
e->v = v;
|
||||
e->flags = flags;
|
||||
e->destructor = destructor;
|
||||
e->next = h->table[index];
|
||||
h->table[index] = e;
|
||||
|
||||
ks_hash_write_unlock(h);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
KS_DECLARE(void) ks_hash_write_lock(ks_hash_t *h)
|
||||
{
|
||||
if ((h->flags & KS_HASH_FLAG_RWLOCK)) {
|
||||
ks_rwl_write_lock(h->rwl);
|
||||
} else {
|
||||
ks_mutex_lock(h->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_hash_write_unlock(ks_hash_t *h)
|
||||
{
|
||||
if ((h->flags & KS_HASH_FLAG_RWLOCK)) {
|
||||
ks_rwl_write_unlock(h->rwl);
|
||||
} else {
|
||||
ks_mutex_unlock(h->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_hash_read_lock(ks_hash_t *h)
|
||||
{
|
||||
if (!(h->flags & KS_HASH_FLAG_RWLOCK)) {
|
||||
return KS_STATUS_INACTIVE;
|
||||
}
|
||||
|
||||
ks_rwl_read_lock(h->rwl);
|
||||
|
||||
ks_mutex_lock(h->mutex);
|
||||
h->readers++;
|
||||
ks_mutex_unlock(h->mutex);
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_hash_read_unlock(ks_hash_t *h)
|
||||
{
|
||||
if (!(h->flags & KS_HASH_FLAG_RWLOCK)) {
|
||||
return KS_STATUS_INACTIVE;
|
||||
}
|
||||
|
||||
ks_mutex_lock(h->mutex);
|
||||
h->readers--;
|
||||
ks_mutex_unlock(h->mutex);
|
||||
|
||||
ks_rwl_read_unlock(h->rwl);
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
KS_DECLARE(void *) /* returns value associated with key */
|
||||
ks_hash_search(ks_hash_t *h, void *k, ks_locked_t locked)
|
||||
{
|
||||
struct entry *e;
|
||||
unsigned int hashvalue, index;
|
||||
void *v = NULL;
|
||||
|
||||
ks_assert(locked != KS_READLOCKED || (h->flags & KS_HASH_FLAG_RWLOCK));
|
||||
|
||||
hashvalue = hash(h,k);
|
||||
index = indexFor(h->tablelength,hashvalue);
|
||||
|
||||
if (locked == KS_READLOCKED) {
|
||||
ks_rwl_read_lock(h->rwl);
|
||||
|
||||
ks_mutex_lock(h->mutex);
|
||||
h->readers++;
|
||||
ks_mutex_unlock(h->mutex);
|
||||
}
|
||||
|
||||
e = h->table[index];
|
||||
while (NULL != e) {
|
||||
/* Check hash value to short circuit heavier comparison */
|
||||
if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {
|
||||
v = e->v;
|
||||
break;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
KS_DECLARE(void *) /* returns value associated with key */
|
||||
ks_hash_remove(ks_hash_t *h, void *k)
|
||||
{
|
||||
void *v;
|
||||
unsigned int hashvalue = hash(h,k);
|
||||
|
||||
ks_hash_write_lock(h);
|
||||
v = _ks_hash_remove(h, k, hashvalue, indexFor(h->tablelength,hashvalue));
|
||||
ks_hash_write_unlock(h);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* destroy */
|
||||
KS_DECLARE(void)
|
||||
ks_hash_destroy(ks_hash_t **h)
|
||||
{
|
||||
unsigned int i;
|
||||
struct entry *e, *f;
|
||||
struct entry **table = (*h)->table;
|
||||
ks_pool_t *pool;
|
||||
|
||||
ks_hash_write_lock(*h);
|
||||
|
||||
for (i = 0; i < (*h)->tablelength; i++) {
|
||||
e = table[i];
|
||||
while (NULL != e) {
|
||||
f = e; e = e->next;
|
||||
|
||||
if (f->flags & KS_HASH_FLAG_FREE_KEY) {
|
||||
ks_pool_free((*h)->pool, f->k);
|
||||
}
|
||||
|
||||
if (f->flags & KS_HASH_FLAG_FREE_VALUE) {
|
||||
ks_pool_safe_free((*h)->pool, f->v);
|
||||
} else if (f->destructor) {
|
||||
f->destructor(f->v);
|
||||
f->v = NULL;
|
||||
} else if ((*h)->destructor) {
|
||||
(*h)->destructor(f->v);
|
||||
f->v = NULL;
|
||||
}
|
||||
ks_pool_safe_free((*h)->pool, f);
|
||||
}
|
||||
}
|
||||
|
||||
pool = (*h)->pool;
|
||||
ks_pool_safe_free(pool, (*h)->table);
|
||||
ks_hash_write_unlock(*h);
|
||||
if ((*h)->rwl) ks_pool_free(pool, (*h)->rwl);
|
||||
ks_pool_free(pool, (*h)->mutex);
|
||||
ks_pool_free(pool, *h);
|
||||
pool = NULL;
|
||||
*h = NULL;
|
||||
|
||||
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_hash_last(ks_hash_iterator_t **iP)
|
||||
{
|
||||
ks_hash_iterator_t *i = *iP;
|
||||
|
||||
//ks_assert(i->locked != KS_READLOCKED || (i->h->flags & KS_HASH_FLAG_RWLOCK));
|
||||
|
||||
if (i->locked == KS_READLOCKED) {
|
||||
ks_mutex_lock(i->h->mutex);
|
||||
i->h->readers--;
|
||||
ks_mutex_unlock(i->h->mutex);
|
||||
|
||||
ks_rwl_read_unlock(i->h->rwl);
|
||||
}
|
||||
|
||||
ks_pool_free(i->h->pool, i);
|
||||
|
||||
*iP = NULL;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_hash_iterator_t *) ks_hash_next(ks_hash_iterator_t **iP)
|
||||
{
|
||||
|
||||
ks_hash_iterator_t *i = *iP;
|
||||
|
||||
if (i->e) {
|
||||
if ((i->e = i->e->next) != 0) {
|
||||
return i;
|
||||
} else {
|
||||
i->pos++;
|
||||
}
|
||||
}
|
||||
|
||||
while(i->pos < i->h->tablelength && !i->h->table[i->pos]) {
|
||||
i->pos++;
|
||||
}
|
||||
|
||||
if (i->pos >= i->h->tablelength) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((i->e = i->h->table[i->pos]) != 0) {
|
||||
return i;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
ks_hash_last(iP);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_hash_iterator_t *) ks_hash_first(ks_hash_t *h, ks_locked_t locked)
|
||||
{
|
||||
ks_hash_iterator_t *iterator;
|
||||
|
||||
ks_assert(locked != KS_READLOCKED || (h->flags & KS_HASH_FLAG_RWLOCK));
|
||||
|
||||
iterator = ks_pool_alloc(h->pool, sizeof(*iterator));
|
||||
ks_assert(iterator);
|
||||
|
||||
iterator->pos = 0;
|
||||
iterator->e = NULL;
|
||||
iterator->h = h;
|
||||
|
||||
if (locked == KS_READLOCKED) {
|
||||
ks_rwl_read_lock(h->rwl);
|
||||
iterator->locked = locked;
|
||||
ks_mutex_lock(h->mutex);
|
||||
h->readers++;
|
||||
ks_mutex_unlock(h->mutex);
|
||||
}
|
||||
|
||||
return ks_hash_next(&iterator);
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_hash_this_val(ks_hash_iterator_t *i, void *val)
|
||||
{
|
||||
if (i->e) {
|
||||
i->e->v = val;
|
||||
}
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_hash_this(ks_hash_iterator_t *i, const void **key, ks_ssize_t *klen, void **val)
|
||||
{
|
||||
if (i->e) {
|
||||
if (key) {
|
||||
*key = i->e->k;
|
||||
}
|
||||
if (klen) {
|
||||
*klen = (int)strlen(i->e->k);
|
||||
}
|
||||
if (val) {
|
||||
*val = i->e->v;
|
||||
}
|
||||
} else {
|
||||
if (key) {
|
||||
*key = NULL;
|
||||
}
|
||||
if (klen) {
|
||||
*klen = 0;
|
||||
}
|
||||
if (val) {
|
||||
*val = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
||||
|
|
@ -27,11 +27,11 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include "ks_json.h"
|
||||
#include "ks.h"
|
||||
#include "ks_json.h"
|
||||
#include <float.h>
|
||||
|
||||
static const char *ep;
|
||||
|
||||
|
@ -40,7 +40,7 @@ KS_DECLARE(const char *)cJSON_GetErrorPtr() {return ep;}
|
|||
static int cJSON_strcasecmp(const char *s1,const char *s2)
|
||||
{
|
||||
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
|
||||
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
|
||||
for(; tolower(*(const unsigned char *)s1) == tolower(*(const unsigned char *)s2); ++s1, ++s2) if(*s1 == 0) return 0;
|
||||
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
|
||||
}
|
||||
|
||||
|
@ -59,23 +59,23 @@ static void (*cJSON_free)(void *ptr) = glue_free;
|
|||
|
||||
static char* cJSON_strdup(const char* str)
|
||||
{
|
||||
size_t len;
|
||||
char* copy;
|
||||
const char *s = str ? str : "";
|
||||
size_t len;
|
||||
char* copy;
|
||||
const char *s = str ? str : "";
|
||||
|
||||
len = strlen(s) + 1;
|
||||
if (!(copy = (char*)cJSON_malloc(len))) return 0;
|
||||
memcpy(copy,s,len);
|
||||
return copy;
|
||||
len = strlen(s) + 1;
|
||||
if (!(copy = (char*)cJSON_malloc(len))) return 0;
|
||||
memcpy(copy,s,len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
KS_DECLARE(void)cJSON_InitHooks(cJSON_Hooks* hooks)
|
||||
{
|
||||
if (!hooks) { /* Reset hooks */
|
||||
cJSON_malloc = malloc;
|
||||
cJSON_free = free;
|
||||
return;
|
||||
}
|
||||
if (!hooks) { /* Reset hooks */
|
||||
cJSON_malloc = malloc;
|
||||
cJSON_free = free;
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
|
||||
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
|
||||
|
@ -281,8 +281,8 @@ KS_DECLARE(cJSON *)cJSON_Parse(const char *value)
|
|||
}
|
||||
|
||||
/* Render a cJSON item/entity/structure to text. */
|
||||
KS_DECLARE(char *) cJSON_Print(cJSON *item) {return print_value(item,0,1);}
|
||||
KS_DECLARE(char *) cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
|
||||
KS_DECLARE(char *)cJSON_Print(cJSON *item) {return print_value(item,0,1);}
|
||||
KS_DECLARE(char *)cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
|
||||
|
||||
/* Parser core - when encountering text, process appropriately. */
|
||||
static const char *parse_value(cJSON *item,const char *value)
|
||||
|
@ -349,7 +349,8 @@ static const char *parse_array(cJSON *item,const char *value)
|
|||
static char *print_array(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char **entries;
|
||||
char *out=0,*ptr,*ret;int len=5;
|
||||
char *out=0,*ptr,*ret;
|
||||
size_t len=5;
|
||||
cJSON *child=item->child;
|
||||
int numentries=0,i=0,fail=0;
|
||||
|
||||
|
@ -436,7 +437,8 @@ static const char *parse_object(cJSON *item,const char *value)
|
|||
static char *print_object(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char **entries=0,**names=0;
|
||||
char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
|
||||
char *out=0,*ptr,*ret,*str;int i=0,j;
|
||||
size_t len=7;
|
||||
cJSON *child=item->child;
|
||||
int numentries=0,fail=0;
|
||||
/* Count the number of entries. */
|
||||
|
@ -493,7 +495,20 @@ static char *print_object(cJSON *item,int depth,int fmt)
|
|||
/* Get Array size/item / object item. */
|
||||
KS_DECLARE(int) cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
|
||||
KS_DECLARE(cJSON *)cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
|
||||
KS_DECLARE(cJSON *)cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
|
||||
KS_DECLARE(cJSON *)cJSON_GetObjectItem(const cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
|
||||
|
||||
|
||||
KS_DECLARE(const char *)cJSON_GetObjectCstr(const cJSON *object, const char *string)
|
||||
{
|
||||
cJSON *cj = cJSON_GetObjectItem(object, string);
|
||||
|
||||
if (!cj || cj->type != cJSON_String || !cj->valuestring) return NULL;
|
||||
|
||||
return cj->valuestring;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Utility for array list handling. */
|
||||
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
|
||||
|
@ -529,7 +544,68 @@ KS_DECLARE(cJSON *)cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(ite
|
|||
KS_DECLARE(cJSON *)cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
|
||||
|
||||
/* Create Arrays: */
|
||||
KS_DECLARE(cJSON *)cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a!=0 && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
KS_DECLARE(cJSON *)cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a!=0 && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
KS_DECLARE(cJSON *)cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a!=0 && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
KS_DECLARE(cJSON *)cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a!=0 && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
KS_DECLARE(cJSON *)cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
KS_DECLARE(cJSON *)cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
KS_DECLARE(cJSON *)cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
KS_DECLARE(cJSON *)cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
|
||||
/* Duplication */
|
||||
KS_DECLARE(cJSON *) cJSON_Duplicate(cJSON *item,int recurse)
|
||||
{
|
||||
cJSON *newitem,*cptr,*nptr=0,*newchild;
|
||||
/* Bail on bad ptr */
|
||||
if (!item) return 0;
|
||||
/* Create new item */
|
||||
newitem=cJSON_New_Item();
|
||||
if (!newitem) return 0;
|
||||
/* Copy over all vars */
|
||||
newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
|
||||
if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
|
||||
if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
|
||||
/* If non-recursive, then we're done! */
|
||||
if (!recurse) return newitem;
|
||||
/* Walk the ->next chain for the child. */
|
||||
cptr=item->child;
|
||||
while (cptr) {
|
||||
newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
|
||||
if (!newchild) {cJSON_Delete(newitem);return 0;}
|
||||
if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
|
||||
else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
|
||||
cptr=cptr->next;
|
||||
}
|
||||
return newitem;
|
||||
}
|
||||
|
||||
|
||||
KS_DECLARE(cJSON *) cJSON_CreateStringPrintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *str;
|
||||
cJSON *item;
|
||||
|
||||
va_start(ap, fmt);
|
||||
str = ks_vmprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (!str) return NULL;
|
||||
|
||||
if ((item = cJSON_New_Item())) {
|
||||
item->type=cJSON_String;
|
||||
item->valuestring = str;
|
||||
} else {
|
||||
free(str);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2014, Anthony Minessale II
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 <ks.h>
|
||||
|
||||
static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
|
||||
{
|
||||
if (file && func && line && level && fmt) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static const char *LEVEL_NAMES[] = {
|
||||
"EMERG",
|
||||
"ALERT",
|
||||
"CRIT",
|
||||
"ERROR",
|
||||
"WARNING",
|
||||
"NOTICE",
|
||||
"INFO",
|
||||
"DEBUG",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int ks_log_level = 7;
|
||||
|
||||
static const char *cut_path(const char *in)
|
||||
{
|
||||
const char *p, *ret = in;
|
||||
char delims[] = "/\\";
|
||||
char *i;
|
||||
|
||||
for (i = delims; *i; i++) {
|
||||
p = in;
|
||||
while ((p = strchr(p, *i)) != 0) {
|
||||
ret = ++p;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
|
||||
{
|
||||
const char *fp;
|
||||
char *data;
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
if (level < 0 || level > 7) {
|
||||
level = 7;
|
||||
}
|
||||
if (level > ks_log_level) {
|
||||
return;
|
||||
}
|
||||
|
||||
fp = cut_path(file);
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
ret = ks_vasprintf(&data, fmt, ap);
|
||||
|
||||
if (ret != -1) {
|
||||
fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], fp, line, func, data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
}
|
||||
|
||||
ks_logger_t ks_log = null_logger;
|
||||
|
||||
KS_DECLARE(void) ks_global_set_logger(ks_logger_t logger)
|
||||
{
|
||||
if (logger) {
|
||||
ks_log = logger;
|
||||
} else {
|
||||
ks_log = null_logger;
|
||||
}
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_global_set_default_logger(int level)
|
||||
{
|
||||
if (level < 0 || level > 7) {
|
||||
level = 7;
|
||||
}
|
||||
|
||||
ks_log = default_logger;
|
||||
ks_log_level = level;
|
||||
}
|
|
@ -0,0 +1,648 @@
|
|||
/*
|
||||
* Cross Platform Thread/Mutex abstraction
|
||||
* Copyright(C) 2007 Michael Jerris
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so.
|
||||
*
|
||||
* This work is provided under this license on an "as is" basis, without warranty of any kind,
|
||||
* either expressed or implied, including, without limitation, warranties that the covered code
|
||||
* is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
|
||||
* risk as to the quality and performance of the covered code is with you. Should any covered
|
||||
* code prove defective in any respect, you (not the initial developer or any other contributor)
|
||||
* assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
|
||||
* constitutes an essential part of this license. No use of any covered code is authorized hereunder
|
||||
* except under this disclaimer.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
/* required for TryEnterCriticalSection definition. Must be defined before windows.h include */
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#endif
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <process.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
KS_MUTEX_TYPE_DEFAULT,
|
||||
KS_MUTEX_TYPE_NON_RECURSIVE
|
||||
} ks_mutex_type_t;
|
||||
|
||||
struct ks_mutex {
|
||||
#ifdef WIN32
|
||||
CRITICAL_SECTION mutex;
|
||||
HANDLE handle;
|
||||
#else
|
||||
pthread_mutex_t mutex;
|
||||
#endif
|
||||
ks_pool_t * pool;
|
||||
ks_mutex_type_t type;
|
||||
uint8_t malloc;
|
||||
};
|
||||
|
||||
static void ks_mutex_cleanup(ks_pool_t *mpool, void *ptr, void *arg, int type, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t ctype)
|
||||
{
|
||||
ks_mutex_t *mutex = (ks_mutex_t *) ptr;
|
||||
|
||||
switch(action) {
|
||||
case KS_MPCL_ANNOUNCE:
|
||||
break;
|
||||
case KS_MPCL_TEARDOWN:
|
||||
break;
|
||||
case KS_MPCL_DESTROY:
|
||||
#ifdef WIN32
|
||||
if (mutex->type == KS_MUTEX_TYPE_NON_RECURSIVE) {
|
||||
CloseHandle(mutex->handle);
|
||||
} else {
|
||||
DeleteCriticalSection(&mutex->mutex);
|
||||
}
|
||||
#else
|
||||
pthread_mutex_destroy(&mutex->mutex);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_mutex_destroy(ks_mutex_t **mutexP)
|
||||
{
|
||||
ks_mutex_t *mutex;
|
||||
|
||||
ks_assert(mutexP);
|
||||
|
||||
mutex = *mutexP;
|
||||
*mutexP = NULL;
|
||||
|
||||
if (!mutex) return KS_STATUS_FAIL;
|
||||
|
||||
if (mutex->malloc) {
|
||||
#ifdef WIN32
|
||||
if (mutex->type == KS_MUTEX_TYPE_NON_RECURSIVE) {
|
||||
CloseHandle(mutex->handle);
|
||||
} else {
|
||||
DeleteCriticalSection(&mutex->mutex);
|
||||
}
|
||||
#else
|
||||
pthread_mutex_destroy(&mutex->mutex);
|
||||
#endif
|
||||
free(mutex);
|
||||
} else {
|
||||
ks_pool_free(mutex->pool, (void *)mutex);
|
||||
}
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_mutex_create(ks_mutex_t **mutex, unsigned int flags, ks_pool_t *pool)
|
||||
{
|
||||
ks_status_t status = KS_STATUS_FAIL;
|
||||
#ifndef WIN32
|
||||
pthread_mutexattr_t attr;
|
||||
#endif
|
||||
ks_mutex_t *check = NULL;
|
||||
|
||||
if (pool) {
|
||||
if (!(check = (ks_mutex_t *) ks_pool_alloc(pool, sizeof(**mutex)))) {
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
check = malloc(sizeof(**mutex));
|
||||
memset(check, 0, sizeof(**mutex));
|
||||
check->malloc = 1;
|
||||
}
|
||||
|
||||
check->pool = pool;
|
||||
check->type = KS_MUTEX_TYPE_DEFAULT;
|
||||
|
||||
#ifdef WIN32
|
||||
if (flags & KS_MUTEX_FLAG_NON_RECURSIVE) {
|
||||
check->type = KS_MUTEX_TYPE_NON_RECURSIVE;
|
||||
check->handle = CreateEvent(NULL, FALSE, TRUE, NULL);
|
||||
} else {
|
||||
InitializeCriticalSection(&check->mutex);
|
||||
}
|
||||
#else
|
||||
if (flags & KS_MUTEX_FLAG_NON_RECURSIVE) {
|
||||
if (pthread_mutex_init(&check->mutex, NULL))
|
||||
goto done;
|
||||
|
||||
} else {
|
||||
if (pthread_mutexattr_init(&attr))
|
||||
goto done;
|
||||
|
||||
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
|
||||
goto fail;
|
||||
|
||||
if (pthread_mutex_init(&check->mutex, &attr))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
goto success;
|
||||
|
||||
fail:
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
goto done;
|
||||
|
||||
success:
|
||||
#endif
|
||||
*mutex = check;
|
||||
status = KS_STATUS_SUCCESS;
|
||||
|
||||
if (pool) {
|
||||
ks_pool_set_cleanup(pool, check, NULL, 0, ks_mutex_cleanup);
|
||||
}
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_mutex_lock(ks_mutex_t *mutex)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (mutex->type == KS_MUTEX_TYPE_NON_RECURSIVE) {
|
||||
DWORD ret = WaitForSingleObject(mutex->handle, INFINITE);
|
||||
if ((ret != WAIT_OBJECT_0) && (ret != WAIT_ABANDONED)) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
} else {
|
||||
EnterCriticalSection(&mutex->mutex);
|
||||
}
|
||||
#else
|
||||
if (pthread_mutex_lock(&mutex->mutex))
|
||||
return KS_STATUS_FAIL;
|
||||
#endif
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_mutex_trylock(ks_mutex_t *mutex)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (mutex->type == KS_MUTEX_TYPE_NON_RECURSIVE) {
|
||||
DWORD ret = WaitForSingleObject(mutex->handle, 0);
|
||||
if ((ret != WAIT_OBJECT_0) && (ret != WAIT_ABANDONED)) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
} else {
|
||||
if (!TryEnterCriticalSection(&mutex->mutex))
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
#else
|
||||
if (pthread_mutex_trylock(&mutex->mutex))
|
||||
return KS_STATUS_FAIL;
|
||||
#endif
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_mutex_unlock(ks_mutex_t *mutex)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (mutex->type == KS_MUTEX_TYPE_NON_RECURSIVE) {
|
||||
if (!SetEvent(mutex->handle)) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
} else {
|
||||
LeaveCriticalSection(&mutex->mutex);
|
||||
}
|
||||
#else
|
||||
if (pthread_mutex_unlock(&mutex->mutex))
|
||||
return KS_STATUS_FAIL;
|
||||
#endif
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ks_cond {
|
||||
ks_pool_t * pool;
|
||||
ks_mutex_t *mutex;
|
||||
#ifdef WIN32
|
||||
CONDITION_VARIABLE cond;
|
||||
#else
|
||||
pthread_cond_t cond;
|
||||
#endif
|
||||
uint8_t static_mutex;
|
||||
};
|
||||
|
||||
static void ks_cond_cleanup(ks_pool_t *mpool, void *ptr, void *arg, int type, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t ctype)
|
||||
{
|
||||
ks_cond_t *cond = (ks_cond_t *) ptr;
|
||||
|
||||
switch(action) {
|
||||
case KS_MPCL_ANNOUNCE:
|
||||
break;
|
||||
case KS_MPCL_TEARDOWN:
|
||||
break;
|
||||
case KS_MPCL_DESTROY:
|
||||
if (!cond->static_mutex) {
|
||||
ks_mutex_destroy(&cond->mutex);
|
||||
}
|
||||
#ifndef WIN32
|
||||
pthread_cond_destroy(&cond->cond);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_create_ex(ks_cond_t **cond, ks_pool_t *pool, ks_mutex_t *mutex)
|
||||
{
|
||||
ks_status_t status = KS_STATUS_FAIL;
|
||||
ks_cond_t *check = NULL;
|
||||
|
||||
*cond = NULL;
|
||||
|
||||
if (!pool)
|
||||
goto done;
|
||||
|
||||
if (!(check = (ks_cond_t *) ks_pool_alloc(pool, sizeof(**cond)))) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
check->pool = pool;
|
||||
if (mutex) {
|
||||
check->mutex = mutex;
|
||||
check->static_mutex = 1;
|
||||
} else {
|
||||
if (ks_mutex_create(&check->mutex, KS_MUTEX_FLAG_DEFAULT, pool) != KS_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
InitializeConditionVariable(&check->cond);
|
||||
#else
|
||||
if (pthread_cond_init(&check->cond, NULL)) {
|
||||
if (!check->static_mutex) {
|
||||
ks_mutex_destroy(&check->mutex);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
*cond = check;
|
||||
status = KS_STATUS_SUCCESS;
|
||||
ks_pool_set_cleanup(pool, check, NULL, 0, ks_cond_cleanup);
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_mutex_t *) ks_cond_get_mutex(ks_cond_t *cond)
|
||||
{
|
||||
return cond->mutex;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_create(ks_cond_t **cond, ks_pool_t *pool)
|
||||
{
|
||||
return ks_cond_create_ex(cond, pool, NULL);
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_lock(ks_cond_t *cond)
|
||||
{
|
||||
return ks_mutex_lock(cond->mutex);
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_trylock(ks_cond_t *cond)
|
||||
{
|
||||
return ks_mutex_trylock(cond->mutex);
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_unlock(ks_cond_t *cond)
|
||||
{
|
||||
return ks_mutex_unlock(cond->mutex);
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_signal(ks_cond_t *cond)
|
||||
{
|
||||
ks_cond_lock(cond);
|
||||
#ifdef WIN32
|
||||
WakeConditionVariable(&cond->cond);
|
||||
#else
|
||||
pthread_cond_signal(&cond->cond);
|
||||
#endif
|
||||
ks_cond_unlock(cond);
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_broadcast(ks_cond_t *cond)
|
||||
{
|
||||
ks_cond_lock(cond);
|
||||
#ifdef WIN32
|
||||
WakeAllConditionVariable(&cond->cond);
|
||||
#else
|
||||
pthread_cond_broadcast(&cond->cond);
|
||||
#endif
|
||||
ks_cond_unlock(cond);
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_try_signal(ks_cond_t *cond)
|
||||
{
|
||||
if (ks_cond_trylock(cond) != KS_STATUS_SUCCESS) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
#ifdef WIN32
|
||||
WakeConditionVariable(&cond->cond);
|
||||
#else
|
||||
pthread_cond_signal(&cond->cond);
|
||||
#endif
|
||||
ks_cond_unlock(cond);
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_try_broadcast(ks_cond_t *cond)
|
||||
{
|
||||
if (ks_cond_trylock(cond) != KS_STATUS_SUCCESS) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
#ifdef WIN32
|
||||
WakeAllConditionVariable(&cond->cond);
|
||||
#else
|
||||
pthread_cond_broadcast(&cond->cond);
|
||||
#endif
|
||||
ks_cond_unlock(cond);
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_wait(ks_cond_t *cond)
|
||||
{
|
||||
#ifdef WIN32
|
||||
SleepConditionVariableCS(&cond->cond, &cond->mutex->mutex, INFINITE);
|
||||
#else
|
||||
pthread_cond_wait(&cond->cond, &cond->mutex->mutex);
|
||||
#endif
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_timedwait(ks_cond_t *cond, ks_time_t ms)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if(!SleepConditionVariableCS(&cond->cond, &cond->mutex->mutex, (DWORD)ms)) {
|
||||
if (GetLastError() == ERROR_TIMEOUT) {
|
||||
return KS_STATUS_TIMEOUT;
|
||||
} else {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct timespec ts;
|
||||
ks_time_t n = ks_time_now() + (ms * 1000);
|
||||
ts.tv_sec = ks_time_sec(n);
|
||||
ts.tv_nsec = ks_time_nsec(n);
|
||||
if (pthread_cond_timedwait(&cond->cond, &cond->mutex->mutex, &ts)) {
|
||||
switch(errno) {
|
||||
case ETIMEDOUT:
|
||||
return KS_STATUS_TIMEOUT;
|
||||
default:
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_cond_destroy(ks_cond_t **cond)
|
||||
{
|
||||
ks_cond_t *condp = *cond;
|
||||
|
||||
if (!condp) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
|
||||
*cond = NULL;
|
||||
|
||||
return ks_pool_free(condp->pool, condp);
|
||||
}
|
||||
|
||||
|
||||
struct ks_rwl {
|
||||
#ifdef WIN32
|
||||
SRWLOCK rwlock;
|
||||
ks_hash_t *read_lock_list;
|
||||
#else
|
||||
pthread_rwlock_t rwlock;
|
||||
#endif
|
||||
ks_pool_t *pool;
|
||||
ks_thread_os_handle_t write_locker;
|
||||
uint32_t wlc;
|
||||
};
|
||||
|
||||
static void ks_rwl_cleanup(ks_pool_t *mpool, void *ptr, void *arg, int type, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t ctype)
|
||||
{
|
||||
#ifndef WIN32
|
||||
ks_rwl_t *rwlock = (ks_rwl_t *) ptr;
|
||||
#endif
|
||||
|
||||
switch(action) {
|
||||
case KS_MPCL_ANNOUNCE:
|
||||
break;
|
||||
case KS_MPCL_TEARDOWN:
|
||||
break;
|
||||
case KS_MPCL_DESTROY:
|
||||
#ifndef WIN32
|
||||
pthread_rwlock_destroy(&rwlock->rwlock);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rwl_create(ks_rwl_t **rwlock, ks_pool_t *pool)
|
||||
{
|
||||
ks_status_t status = KS_STATUS_FAIL;
|
||||
ks_rwl_t *check = NULL;
|
||||
*rwlock = NULL;
|
||||
|
||||
if (!pool) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(check = (ks_rwl_t *) ks_pool_alloc(pool, sizeof(**rwlock)))) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
check->pool = pool;
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
if (ks_hash_create(&check->read_lock_list, KS_HASH_MODE_PTR, KS_HASH_FLAG_NONE, pool) != KS_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
InitializeSRWLock(&check->rwlock);
|
||||
#else
|
||||
if ((pthread_rwlock_init(&check->rwlock, NULL))) {
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
*rwlock = check;
|
||||
status = KS_STATUS_SUCCESS;
|
||||
ks_pool_set_cleanup(pool, check, NULL, 0, ks_rwl_cleanup);
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rwl_read_lock(ks_rwl_t *rwlock)
|
||||
{
|
||||
#ifdef WIN32
|
||||
int count = (int)(intptr_t)ks_hash_remove(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self());
|
||||
|
||||
if (count) {
|
||||
ks_hash_insert(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self(), (void *)(intptr_t)++count);
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
AcquireSRWLockShared(&rwlock->rwlock);
|
||||
#else
|
||||
pthread_rwlock_rdlock(&rwlock->rwlock);
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
ks_hash_insert(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self(), (void *)(intptr_t)(int)1);
|
||||
#endif
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rwl_write_lock(ks_rwl_t *rwlock)
|
||||
{
|
||||
|
||||
int me = (rwlock->write_locker == ks_thread_self());
|
||||
|
||||
if (me) {
|
||||
rwlock->wlc++;
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
AcquireSRWLockExclusive(&rwlock->rwlock);
|
||||
#else
|
||||
pthread_rwlock_wrlock(&rwlock->rwlock);
|
||||
#endif
|
||||
rwlock->write_locker = ks_thread_self();
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rwl_try_read_lock(ks_rwl_t *rwlock)
|
||||
{
|
||||
#ifdef WIN32
|
||||
int count = (int)(intptr_t)ks_hash_remove(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self());
|
||||
|
||||
if (count) {
|
||||
ks_hash_insert(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self(), (void *)(intptr_t)++count);
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!TryAcquireSRWLockShared(&rwlock->rwlock)) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
#else
|
||||
if (pthread_rwlock_tryrdlock(&rwlock->rwlock)) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
ks_hash_insert(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self(), (void *)(intptr_t)(int)1);
|
||||
#endif
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rwl_try_write_lock(ks_rwl_t *rwlock)
|
||||
{
|
||||
int me = (rwlock->write_locker == ks_thread_self());
|
||||
|
||||
if (me) {
|
||||
rwlock->wlc++;
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
if (!TryAcquireSRWLockExclusive(&rwlock->rwlock)) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
#else
|
||||
if (pthread_rwlock_trywrlock(&rwlock->rwlock)) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
rwlock->write_locker = ks_thread_self();
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rwl_read_unlock(ks_rwl_t *rwlock)
|
||||
{
|
||||
#ifdef WIN32
|
||||
int count = (int)(intptr_t)ks_hash_remove(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self());
|
||||
|
||||
if (count > 1) {
|
||||
ks_hash_insert(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self(), (void *)(intptr_t)--count);
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ReleaseSRWLockShared(&rwlock->rwlock);
|
||||
#else
|
||||
pthread_rwlock_unlock(&rwlock->rwlock);
|
||||
#endif
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rwl_write_unlock(ks_rwl_t *rwlock)
|
||||
{
|
||||
int me = (rwlock->write_locker == ks_thread_self());
|
||||
|
||||
if (me && rwlock->wlc > 0) {
|
||||
rwlock->wlc--;
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
rwlock->write_locker = 0;
|
||||
|
||||
#ifdef WIN32
|
||||
ReleaseSRWLockExclusive(&rwlock->rwlock);
|
||||
#else
|
||||
pthread_rwlock_unlock(&rwlock->rwlock);
|
||||
#endif
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rwl_destroy(ks_rwl_t **rwlock)
|
||||
{
|
||||
ks_rwl_t *rwlockp = *rwlock;
|
||||
|
||||
|
||||
if (!rwlockp) {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
|
||||
*rwlock = NULL;
|
||||
|
||||
return ks_pool_free(rwlockp->pool, rwlockp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,980 @@
|
|||
/*
|
||||
** The "printf" code that follows dates from the 1980's. It is in
|
||||
** the public domain. The original comments are included here for
|
||||
** completeness. They are very out-of-date but might be useful as
|
||||
** an historical reference. Most of the "enhancements" have been backed
|
||||
** out so that the functionality is now the same as standard printf().
|
||||
**
|
||||
**************************************************************************
|
||||
**
|
||||
** The following modules is an enhanced replacement for the "printf" subroutines
|
||||
** found in the standard C library. The following enhancements are
|
||||
** supported:
|
||||
**
|
||||
** + Additional functions. The standard set of "printf" functions
|
||||
** includes printf, fprintf, sprintf, vprintf, vfprintf, and
|
||||
** vsprintf. This module adds the following:
|
||||
**
|
||||
** * snprintf -- Works like sprintf, but has an extra argument
|
||||
** which is the size of the buffer written to.
|
||||
**
|
||||
** * mprintf -- Similar to sprintf. Writes output to memory
|
||||
** obtained from malloc.
|
||||
**
|
||||
** * xprintf -- Calls a function to dispose of output.
|
||||
**
|
||||
** * nprintf -- No output, but returns the number of characters
|
||||
** that would have been output by printf.
|
||||
**
|
||||
** * A v- version (ex: vsnprintf) of every function is also
|
||||
** supplied.
|
||||
**
|
||||
** + A few extensions to the formatting notation are supported:
|
||||
**
|
||||
** * The "=" flag (similar to "-") causes the output to be
|
||||
** be centered in the appropriately sized field.
|
||||
**
|
||||
** * The %b field outputs an integer in binary notation.
|
||||
**
|
||||
** * The %c field now accepts a precision. The character output
|
||||
** is repeated by the number of times the precision specifies.
|
||||
**
|
||||
** * The %' field works like %c, but takes as its character the
|
||||
** next character of the format string, instead of the next
|
||||
** argument. For example, printf("%.78'-") prints 78 minus
|
||||
** signs, the same as printf("%.78c",'-').
|
||||
**
|
||||
** + When compiled using GCC on a SPARC, this version of printf is
|
||||
** faster than the library printf for SUN OS 4.1.
|
||||
**
|
||||
** + All functions are fully reentrant.
|
||||
**
|
||||
*/
|
||||
/*
|
||||
* 20090210 (stkn):
|
||||
* Taken from sqlite-3.3.x,
|
||||
* renamed SQLITE_ -> KS_,
|
||||
* renamed visible functions to ks_*
|
||||
* disabled functions without extra conversion specifiers
|
||||
*/
|
||||
|
||||
#include <ks.h>
|
||||
|
||||
#define LONGDOUBLE_TYPE long double
|
||||
|
||||
/*
|
||||
** Conversion types fall into various categories as defined by the
|
||||
** following enumeration.
|
||||
*/
|
||||
#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
|
||||
#define etFLOAT 2 /* Floating point. %f */
|
||||
#define etEXP 3 /* Exponentional notation. %e and %E */
|
||||
#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
|
||||
#define etSIZE 5 /* Return number of characters processed so far. %n */
|
||||
#define etSTRING 6 /* Strings. %s */
|
||||
#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
|
||||
#define etPERCENT 8 /* Percent symbol. %% */
|
||||
#define etCHARX 9 /* Characters. %c */
|
||||
/* The rest are extensions, not normally found in printf() */
|
||||
#define etCHARLIT 10 /* Literal characters. %' */
|
||||
#define etSQLESCAPE 11 /* Strings with '\'' doubled. %q */
|
||||
#define etSQLESCAPE2 12 /* Strings with '\'' doubled and enclosed in '',
|
||||
NULL pointers replaced by SQL NULL. %Q */
|
||||
#ifdef __UNSUPPORTED__
|
||||
#define etTOKEN 13 /* a pointer to a Token structure */
|
||||
#define etSRCLIST 14 /* a pointer to a SrcList */
|
||||
#endif
|
||||
#define etPOINTER 15 /* The %p conversion */
|
||||
#define etSQLESCAPE3 16
|
||||
#define etSQLESCAPE4 17
|
||||
|
||||
/*
|
||||
** An "etByte" is an 8-bit unsigned value.
|
||||
*/
|
||||
typedef unsigned char etByte;
|
||||
|
||||
/*
|
||||
** Each builtin conversion character (ex: the 'd' in "%d") is described
|
||||
** by an instance of the following structure
|
||||
*/
|
||||
typedef struct et_info { /* Information about each format field */
|
||||
char fmttype; /* The format field code letter */
|
||||
etByte base; /* The base for radix conversion */
|
||||
etByte flags; /* One or more of FLAG_ constants below */
|
||||
etByte type; /* Conversion paradigm */
|
||||
etByte charset; /* Offset into aDigits[] of the digits string */
|
||||
etByte prefix; /* Offset into aPrefix[] of the prefix string */
|
||||
} et_info;
|
||||
|
||||
/*
|
||||
** Allowed values for et_info.flags
|
||||
*/
|
||||
#define FLAG_SIGNED 1 /* True if the value to convert is signed */
|
||||
#define FLAG_INTERN 2 /* True if for internal use only */
|
||||
#define FLAG_STRING 4 /* Allow infinity precision */
|
||||
|
||||
|
||||
/*
|
||||
** The following table is searched linearly, so it is good to put the
|
||||
** most frequently used conversion types first.
|
||||
*/
|
||||
static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
|
||||
static const char aPrefix[] = "-x0\000X0";
|
||||
static const et_info fmtinfo[] = {
|
||||
{'d', 10, 1, etRADIX, 0, 0},
|
||||
{'s', 0, 4, etSTRING, 0, 0},
|
||||
{'g', 0, 1, etGENERIC, 30, 0},
|
||||
{'z', 0, 6, etDYNSTRING, 0, 0},
|
||||
{'q', 0, 4, etSQLESCAPE, 0, 0},
|
||||
{'Q', 0, 4, etSQLESCAPE2, 0, 0},
|
||||
{'w', 0, 4, etSQLESCAPE3, 0, 0},
|
||||
{'y', 0, 4, etSQLESCAPE4, 0, 0},
|
||||
{'c', 0, 0, etCHARX, 0, 0},
|
||||
{'o', 8, 0, etRADIX, 0, 2},
|
||||
{'u', 10, 0, etRADIX, 0, 0},
|
||||
{'x', 16, 0, etRADIX, 16, 1},
|
||||
{'X', 16, 0, etRADIX, 0, 4},
|
||||
#ifndef KS_OMIT_FLOATING_POINT
|
||||
{'f', 0, 1, etFLOAT, 0, 0},
|
||||
{'e', 0, 1, etEXP, 30, 0},
|
||||
{'E', 0, 1, etEXP, 14, 0},
|
||||
{'G', 0, 1, etGENERIC, 14, 0},
|
||||
#endif
|
||||
{'i', 10, 1, etRADIX, 0, 0},
|
||||
{'n', 0, 0, etSIZE, 0, 0},
|
||||
{'%', 0, 0, etPERCENT, 0, 0},
|
||||
{'p', 16, 0, etPOINTER, 0, 1},
|
||||
#ifdef __UNSUPPORTED__
|
||||
{'T', 0, 2, etTOKEN, 0, 0},
|
||||
{'S', 0, 2, etSRCLIST, 0, 0},
|
||||
#endif
|
||||
};
|
||||
|
||||
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
|
||||
|
||||
/*
|
||||
** If KS_OMIT_FLOATING_POINT is defined, then none of the floating point
|
||||
** conversions will work.
|
||||
*/
|
||||
#ifndef KS_OMIT_FLOATING_POINT
|
||||
/*
|
||||
** "*val" is a double such that 0.1 <= *val < 10.0
|
||||
** Return the ascii code for the leading digit of *val, then
|
||||
** multiply "*val" by 10.0 to renormalize.
|
||||
**
|
||||
** Example:
|
||||
** input: *val = 3.14159
|
||||
** output: *val = 1.4159 function return = '3'
|
||||
**
|
||||
** The counter *cnt is incremented each time. After counter exceeds
|
||||
** 16 (the number of significant digits in a 64-bit float) '0' is
|
||||
** always returned.
|
||||
*/
|
||||
static int et_getdigit(LONGDOUBLE_TYPE * val, int *cnt)
|
||||
{
|
||||
int digit;
|
||||
LONGDOUBLE_TYPE d;
|
||||
if ((*cnt)++ >= 16)
|
||||
return '0';
|
||||
digit = (int) *val;
|
||||
d = digit;
|
||||
digit += '0';
|
||||
*val = (*val - d) * 10.0;
|
||||
return digit;
|
||||
}
|
||||
#endif /* KS_OMIT_FLOATING_POINT */
|
||||
|
||||
/*
|
||||
** On machines with a small stack size, you can redefine the
|
||||
** KS_PRINT_BUF_SIZE to be less than 350. But beware - for
|
||||
** smaller values some %f conversions may go into an infinite loop.
|
||||
*/
|
||||
#ifndef KS_PRINT_BUF_SIZE
|
||||
# define KS_PRINT_BUF_SIZE 350
|
||||
#endif
|
||||
#define etBUFSIZE KS_PRINT_BUF_SIZE /* Size of the output buffer */
|
||||
|
||||
/*
|
||||
** The root program. All variations call this core.
|
||||
**
|
||||
** INPUTS:
|
||||
** func This is a pointer to a function taking three arguments
|
||||
** 1. A pointer to anything. Same as the "arg" parameter.
|
||||
** 2. A pointer to the list of characters to be output
|
||||
** (Note, this list is NOT null terminated.)
|
||||
** 3. An integer number of characters to be output.
|
||||
** (Note: This number might be zero.)
|
||||
**
|
||||
** arg This is the pointer to anything which will be passed as the
|
||||
** first argument to "func". Use it for whatever you like.
|
||||
**
|
||||
** fmt This is the format string, as in the usual print.
|
||||
**
|
||||
** ap This is a pointer to a list of arguments. Same as in
|
||||
** vfprint.
|
||||
**
|
||||
** OUTPUTS:
|
||||
** The return value is the total number of characters sent to
|
||||
** the function "func". Returns -1 on a error.
|
||||
**
|
||||
** Note that the order in which automatic variables are declared below
|
||||
** seems to make a big difference in determining how fast this beast
|
||||
** will run.
|
||||
*/
|
||||
static int vxprintf(void (*func) (void *, const char *, int), /* Consumer of text */
|
||||
void *arg, /* First argument to the consumer */
|
||||
int useExtended, /* Allow extended %-conversions */
|
||||
const char *fmt, /* Format string */
|
||||
va_list ap /* arguments */
|
||||
)
|
||||
{
|
||||
int c; /* Next character in the format string */
|
||||
char *bufpt; /* Pointer to the conversion buffer */
|
||||
int precision; /* Precision of the current field */
|
||||
int length; /* Length of the field */
|
||||
int idx; /* A general purpose loop counter */
|
||||
int count; /* Total number of characters output */
|
||||
int width; /* Width of the current field */
|
||||
etByte flag_leftjustify; /* True if "-" flag is present */
|
||||
etByte flag_plussign; /* True if "+" flag is present */
|
||||
etByte flag_blanksign; /* True if " " flag is present */
|
||||
etByte flag_alternateform; /* True if "#" flag is present */
|
||||
etByte flag_altform2; /* True if "!" flag is present */
|
||||
etByte flag_zeropad; /* True if field width constant starts with zero */
|
||||
etByte flag_long; /* True if "l" flag is present */
|
||||
etByte flag_longlong; /* True if the "ll" flag is present */
|
||||
etByte done; /* Loop termination flag */
|
||||
uint64_t longvalue; /* Value for integer types */
|
||||
LONGDOUBLE_TYPE realvalue; /* Value for real types */
|
||||
const et_info *infop; /* Pointer to the appropriate info structure */
|
||||
char buf[etBUFSIZE]; /* Conversion buffer */
|
||||
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
|
||||
etByte errorflag = 0; /* True if an error is encountered */
|
||||
etByte xtype = 0; /* Conversion paradigm */
|
||||
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
|
||||
static const char spaces[] = " ";
|
||||
#define etSPACESIZE (sizeof(spaces)-1)
|
||||
#ifndef KS_OMIT_FLOATING_POINT
|
||||
int exp, e2; /* exponent of real numbers */
|
||||
double rounder; /* Used for rounding floating point values */
|
||||
etByte flag_dp; /* True if decimal point should be shown */
|
||||
etByte flag_rtz; /* True if trailing zeros should be removed */
|
||||
etByte flag_exp; /* True to force display of the exponent */
|
||||
int nsd; /* Number of significant digits returned */
|
||||
#endif
|
||||
|
||||
func(arg, "", 0);
|
||||
count = length = 0;
|
||||
bufpt = 0;
|
||||
for (; (c = (*fmt)) != 0; ++fmt) {
|
||||
if (c != '%') {
|
||||
int amt;
|
||||
bufpt = (char *) fmt;
|
||||
amt = 1;
|
||||
while ((c = (*++fmt)) != '%' && c != 0)
|
||||
amt++;
|
||||
(*func) (arg, bufpt, amt);
|
||||
count += amt;
|
||||
if (c == 0)
|
||||
break;
|
||||
}
|
||||
if ((c = (*++fmt)) == 0) {
|
||||
errorflag = 1;
|
||||
(*func) (arg, "%", 1);
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
/* Find out what flags are present */
|
||||
flag_leftjustify = flag_plussign = flag_blanksign = flag_alternateform = flag_altform2 = flag_zeropad = 0;
|
||||
done = 0;
|
||||
do {
|
||||
switch (c) {
|
||||
case '-':
|
||||
flag_leftjustify = 1;
|
||||
break;
|
||||
case '+':
|
||||
flag_plussign = 1;
|
||||
break;
|
||||
case ' ':
|
||||
flag_blanksign = 1;
|
||||
break;
|
||||
case '#':
|
||||
flag_alternateform = 1;
|
||||
break;
|
||||
case '!':
|
||||
flag_altform2 = 1;
|
||||
break;
|
||||
case '0':
|
||||
flag_zeropad = 1;
|
||||
break;
|
||||
default:
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
} while (!done && (c = (*++fmt)) != 0);
|
||||
/* Get the field width */
|
||||
width = 0;
|
||||
if (c == '*') {
|
||||
width = va_arg(ap, int);
|
||||
if (width < 0) {
|
||||
flag_leftjustify = 1;
|
||||
width = -width;
|
||||
}
|
||||
c = *++fmt;
|
||||
} else {
|
||||
while (c >= '0' && c <= '9') {
|
||||
width = width * 10 + c - '0';
|
||||
c = *++fmt;
|
||||
}
|
||||
}
|
||||
if (width > etBUFSIZE - 10) {
|
||||
width = etBUFSIZE - 10;
|
||||
}
|
||||
/* Get the precision */
|
||||
if (c == '.') {
|
||||
precision = 0;
|
||||
c = *++fmt;
|
||||
if (c == '*') {
|
||||
precision = va_arg(ap, int);
|
||||
if (precision < 0)
|
||||
precision = -precision;
|
||||
c = *++fmt;
|
||||
} else {
|
||||
while (c >= '0' && c <= '9') {
|
||||
precision = precision * 10 + c - '0';
|
||||
c = *++fmt;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
precision = -1;
|
||||
}
|
||||
/* Get the conversion type modifier */
|
||||
if (c == 'l') {
|
||||
flag_long = 1;
|
||||
c = *++fmt;
|
||||
if (c == 'l') {
|
||||
flag_longlong = 1;
|
||||
c = *++fmt;
|
||||
} else {
|
||||
flag_longlong = 0;
|
||||
}
|
||||
} else {
|
||||
flag_long = flag_longlong = 0;
|
||||
}
|
||||
/* Fetch the info entry for the field */
|
||||
infop = 0;
|
||||
for (idx = 0; idx < etNINFO; idx++) {
|
||||
if (c == fmtinfo[idx].fmttype) {
|
||||
infop = &fmtinfo[idx];
|
||||
if (useExtended || (infop->flags & FLAG_INTERN) == 0) {
|
||||
xtype = infop->type;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
zExtra = 0;
|
||||
if (infop == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Limit the precision to prevent overflowing buf[] during conversion */
|
||||
if (precision > etBUFSIZE - 40 && (infop->flags & FLAG_STRING) == 0) {
|
||||
precision = etBUFSIZE - 40;
|
||||
}
|
||||
|
||||
/*
|
||||
** At this point, variables are initialized as follows:
|
||||
**
|
||||
** flag_alternateform TRUE if a '#' is present.
|
||||
** flag_altform2 TRUE if a '!' is present.
|
||||
** flag_plussign TRUE if a '+' is present.
|
||||
** flag_leftjustify TRUE if a '-' is present or if the
|
||||
** field width was negative.
|
||||
** flag_zeropad TRUE if the width began with 0.
|
||||
** flag_long TRUE if the letter 'l' (ell) prefixed
|
||||
** the conversion character.
|
||||
** flag_longlong TRUE if the letter 'll' (ell ell) prefixed
|
||||
** the conversion character.
|
||||
** flag_blanksign TRUE if a ' ' is present.
|
||||
** width The specified field width. This is
|
||||
** always non-negative. Zero is the default.
|
||||
** precision The specified precision. The default
|
||||
** is -1.
|
||||
** xtype The class of the conversion.
|
||||
** infop Pointer to the appropriate info struct.
|
||||
*/
|
||||
switch (xtype) {
|
||||
case etPOINTER:
|
||||
flag_longlong = sizeof(char *) == sizeof(int64_t);
|
||||
flag_long = sizeof(char *) == sizeof(long int);
|
||||
/* Fall through into the next case */
|
||||
case etRADIX:
|
||||
if (infop->flags & FLAG_SIGNED) {
|
||||
int64_t v;
|
||||
if (flag_longlong)
|
||||
v = va_arg(ap, int64_t);
|
||||
else if (flag_long)
|
||||
v = va_arg(ap, long int);
|
||||
else
|
||||
v = va_arg(ap, int);
|
||||
if (v < 0) {
|
||||
longvalue = -v;
|
||||
prefix = '-';
|
||||
} else {
|
||||
longvalue = v;
|
||||
if (flag_plussign)
|
||||
prefix = '+';
|
||||
else if (flag_blanksign)
|
||||
prefix = ' ';
|
||||
else
|
||||
prefix = 0;
|
||||
}
|
||||
} else {
|
||||
if (flag_longlong)
|
||||
longvalue = va_arg(ap, uint64_t);
|
||||
else if (flag_long)
|
||||
longvalue = va_arg(ap, unsigned long int);
|
||||
else
|
||||
longvalue = va_arg(ap, unsigned int);
|
||||
prefix = 0;
|
||||
}
|
||||
if (longvalue == 0)
|
||||
flag_alternateform = 0;
|
||||
if (flag_zeropad && precision < width - (prefix != 0)) {
|
||||
precision = width - (prefix != 0);
|
||||
}
|
||||
bufpt = &buf[etBUFSIZE - 1];
|
||||
{
|
||||
register const char *cset; /* Use registers for speed */
|
||||
register int base;
|
||||
cset = &aDigits[infop->charset];
|
||||
base = infop->base;
|
||||
do { /* Convert to ascii */
|
||||
*(--bufpt) = cset[longvalue % base];
|
||||
longvalue = longvalue / base;
|
||||
} while (longvalue > 0);
|
||||
}
|
||||
length = (int)(&buf[etBUFSIZE - 1] - bufpt);
|
||||
for (idx = precision - length; idx > 0; idx--) {
|
||||
*(--bufpt) = '0'; /* Zero pad */
|
||||
}
|
||||
if (prefix)
|
||||
*(--bufpt) = prefix; /* Add sign */
|
||||
if (flag_alternateform && infop->prefix) { /* Add "0" or "0x" */
|
||||
const char *pre;
|
||||
char x;
|
||||
pre = &aPrefix[infop->prefix];
|
||||
if (*bufpt != pre[0]) {
|
||||
for (; (x = (*pre)) != 0; pre++)
|
||||
*(--bufpt) = x;
|
||||
}
|
||||
}
|
||||
length = (int)(&buf[etBUFSIZE - 1] - bufpt);
|
||||
break;
|
||||
case etFLOAT:
|
||||
case etEXP:
|
||||
case etGENERIC:
|
||||
realvalue = va_arg(ap, double);
|
||||
#ifndef KS_OMIT_FLOATING_POINT
|
||||
if (precision < 0)
|
||||
precision = 6; /* Set default precision */
|
||||
if (precision > etBUFSIZE / 2 - 10)
|
||||
precision = etBUFSIZE / 2 - 10;
|
||||
if (realvalue < 0.0) {
|
||||
realvalue = -realvalue;
|
||||
prefix = '-';
|
||||
} else {
|
||||
if (flag_plussign)
|
||||
prefix = '+';
|
||||
else if (flag_blanksign)
|
||||
prefix = ' ';
|
||||
else
|
||||
prefix = 0;
|
||||
}
|
||||
if (xtype == etGENERIC && precision > 0)
|
||||
precision--;
|
||||
#if 0
|
||||
/* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
|
||||
for (idx = precision, rounder = 0.4999; idx > 0; idx--, rounder *= 0.1);
|
||||
#else
|
||||
/* It makes more sense to use 0.5 */
|
||||
for (idx = precision, rounder = 0.5; idx > 0; idx--, rounder *= 0.1) {
|
||||
}
|
||||
#endif
|
||||
if (xtype == etFLOAT)
|
||||
realvalue += rounder;
|
||||
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
|
||||
exp = 0;
|
||||
if (realvalue > 0.0) {
|
||||
while (realvalue >= 1e32 && exp <= 350) {
|
||||
realvalue *= 1e-32;
|
||||
exp += 32;
|
||||
}
|
||||
while (realvalue >= 1e8 && exp <= 350) {
|
||||
realvalue *= 1e-8;
|
||||
exp += 8;
|
||||
}
|
||||
while (realvalue >= 10.0 && exp <= 350) {
|
||||
realvalue *= 0.1;
|
||||
exp++;
|
||||
}
|
||||
while (realvalue < 1e-8 && exp >= -350) {
|
||||
realvalue *= 1e8;
|
||||
exp -= 8;
|
||||
}
|
||||
while (realvalue < 1.0 && exp >= -350) {
|
||||
realvalue *= 10.0;
|
||||
exp--;
|
||||
}
|
||||
if (exp > 350 || exp < -350) {
|
||||
bufpt = "NaN";
|
||||
length = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bufpt = buf;
|
||||
/*
|
||||
** If the field type is etGENERIC, then convert to either etEXP
|
||||
** or etFLOAT, as appropriate.
|
||||
*/
|
||||
flag_exp = xtype == etEXP;
|
||||
if (xtype != etFLOAT) {
|
||||
realvalue += rounder;
|
||||
if (realvalue >= 10.0) {
|
||||
realvalue *= 0.1;
|
||||
exp++;
|
||||
}
|
||||
}
|
||||
if (xtype == etGENERIC) {
|
||||
flag_rtz = !flag_alternateform;
|
||||
if (exp < -4 || exp > precision) {
|
||||
xtype = etEXP;
|
||||
} else {
|
||||
precision = precision - exp;
|
||||
xtype = etFLOAT;
|
||||
}
|
||||
} else {
|
||||
flag_rtz = 0;
|
||||
}
|
||||
if (xtype == etEXP) {
|
||||
e2 = 0;
|
||||
} else {
|
||||
e2 = exp;
|
||||
}
|
||||
nsd = 0;
|
||||
flag_dp = (precision > 0) | flag_alternateform | flag_altform2;
|
||||
/* The sign in front of the number */
|
||||
if (prefix) {
|
||||
*(bufpt++) = prefix;
|
||||
}
|
||||
/* Digits prior to the decimal point */
|
||||
if (e2 < 0) {
|
||||
*(bufpt++) = '0';
|
||||
} else {
|
||||
for (; e2 >= 0; e2--) {
|
||||
*(bufpt++) = (char) et_getdigit(&realvalue, &nsd);
|
||||
}
|
||||
}
|
||||
/* The decimal point */
|
||||
if (flag_dp) {
|
||||
*(bufpt++) = '.';
|
||||
}
|
||||
/* "0" digits after the decimal point but before the first
|
||||
** significant digit of the number */
|
||||
for (e2++; e2 < 0 && precision > 0; precision--, e2++) {
|
||||
*(bufpt++) = '0';
|
||||
}
|
||||
/* Significant digits after the decimal point */
|
||||
while ((precision--) > 0) {
|
||||
*(bufpt++) = (char) et_getdigit(&realvalue, &nsd);
|
||||
}
|
||||
/* Remove trailing zeros and the "." if no digits follow the "." */
|
||||
if (flag_rtz && flag_dp) {
|
||||
while (bufpt[-1] == '0')
|
||||
*(--bufpt) = 0;
|
||||
assert(bufpt > buf);
|
||||
if (bufpt[-1] == '.') {
|
||||
if (flag_altform2) {
|
||||
*(bufpt++) = '0';
|
||||
} else {
|
||||
*(--bufpt) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Add the "eNNN" suffix */
|
||||
if (flag_exp || (xtype == etEXP && exp)) {
|
||||
*(bufpt++) = aDigits[infop->charset];
|
||||
if (exp < 0) {
|
||||
*(bufpt++) = '-';
|
||||
exp = -exp;
|
||||
} else {
|
||||
*(bufpt++) = '+';
|
||||
}
|
||||
if (exp >= 100) {
|
||||
*(bufpt++) = (char) (exp / 100) + '0'; /* 100's digit */
|
||||
exp %= 100;
|
||||
}
|
||||
*(bufpt++) = (char) exp / 10 + '0'; /* 10's digit */
|
||||
*(bufpt++) = exp % 10 + '0'; /* 1's digit */
|
||||
}
|
||||
*bufpt = 0;
|
||||
|
||||
/* The converted number is in buf[] and zero terminated. Output it.
|
||||
** Note that the number is in the usual order, not reversed as with
|
||||
** integer conversions. */
|
||||
length = (int)(bufpt - buf);
|
||||
bufpt = buf;
|
||||
|
||||
/* Special case: Add leading zeros if the flag_zeropad flag is
|
||||
** set and we are not left justified */
|
||||
if (flag_zeropad && !flag_leftjustify && length < width) {
|
||||
int i;
|
||||
int nPad = width - length;
|
||||
for (i = width; i >= nPad; i--) {
|
||||
bufpt[i] = bufpt[i - nPad];
|
||||
}
|
||||
i = prefix != 0;
|
||||
while (nPad--)
|
||||
bufpt[i++] = '0';
|
||||
length = width;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case etSIZE:
|
||||
*(va_arg(ap, int *)) = count;
|
||||
length = width = 0;
|
||||
break;
|
||||
case etPERCENT:
|
||||
buf[0] = '%';
|
||||
bufpt = buf;
|
||||
length = 1;
|
||||
break;
|
||||
case etCHARLIT:
|
||||
case etCHARX:
|
||||
c = buf[0] = (char) (xtype == etCHARX ? va_arg(ap, int) : *++fmt);
|
||||
if (precision >= 0) {
|
||||
for (idx = 1; idx < precision; idx++)
|
||||
buf[idx] = (char) c;
|
||||
length = precision;
|
||||
} else {
|
||||
length = 1;
|
||||
}
|
||||
bufpt = buf;
|
||||
break;
|
||||
case etSTRING:
|
||||
case etDYNSTRING:
|
||||
bufpt = va_arg(ap, char *);
|
||||
if (bufpt == 0) {
|
||||
bufpt = "";
|
||||
} else if (xtype == etDYNSTRING) {
|
||||
zExtra = bufpt;
|
||||
}
|
||||
length = (int)strlen(bufpt);
|
||||
if (precision >= 0 && precision < length)
|
||||
length = precision;
|
||||
break;
|
||||
case etSQLESCAPE:
|
||||
case etSQLESCAPE2:
|
||||
case etSQLESCAPE4:
|
||||
case etSQLESCAPE3:{
|
||||
int i, j, n, ch, isnull;
|
||||
int needQuote;
|
||||
char *escarg = va_arg(ap, char *);
|
||||
isnull = escarg == 0;
|
||||
if (isnull)
|
||||
escarg = (xtype == etSQLESCAPE2 ? "NULL" : "(NULL)");
|
||||
for (i = n = 0; (ch = escarg[i]) != 0; i++) {
|
||||
if (ch == '\'' || (xtype == etSQLESCAPE3 && ch == '\\'))
|
||||
n++;
|
||||
}
|
||||
needQuote = !isnull && xtype == etSQLESCAPE2;
|
||||
n += i + 1 + needQuote * 2;
|
||||
if (n > etBUFSIZE) {
|
||||
bufpt = zExtra = malloc(n);
|
||||
if (bufpt == 0)
|
||||
return -1;
|
||||
} else {
|
||||
bufpt = buf;
|
||||
}
|
||||
j = 0;
|
||||
if (needQuote)
|
||||
bufpt[j++] = '\'';
|
||||
for (i = 0; (ch = escarg[i]) != 0; i++) {
|
||||
bufpt[j++] = (char) ch;
|
||||
if (xtype == etSQLESCAPE4) {
|
||||
if (ch == '\'' || (xtype == etSQLESCAPE3 && ch == '\\')) {
|
||||
bufpt[j] = (char) ch;
|
||||
bufpt[j-1] = (char) '\\';
|
||||
j++;
|
||||
}
|
||||
} else {
|
||||
if (ch == '\'' || (xtype == etSQLESCAPE3 && ch == '\\'))
|
||||
bufpt[j++] = (char) ch;
|
||||
}
|
||||
}
|
||||
if (needQuote)
|
||||
bufpt[j++] = '\'';
|
||||
bufpt[j] = 0;
|
||||
length = j;
|
||||
/* The precision is ignored on %q and %Q */
|
||||
/* if ( precision>=0 && precision<length ) length = precision; */
|
||||
break;
|
||||
}
|
||||
#ifdef __UNSUPPORTED__
|
||||
case etTOKEN:{
|
||||
Token *pToken = va_arg(ap, Token *);
|
||||
if (pToken && pToken->z) {
|
||||
(*func) (arg, (char *) pToken->z, pToken->n);
|
||||
}
|
||||
length = width = 0;
|
||||
break;
|
||||
}
|
||||
case etSRCLIST:{
|
||||
SrcList *pSrc = va_arg(ap, SrcList *);
|
||||
int k = va_arg(ap, int);
|
||||
struct SrcList_item *pItem = &pSrc->a[k];
|
||||
assert(k >= 0 && k < pSrc->nSrc);
|
||||
if (pItem->zDatabase && pItem->zDatabase[0]) {
|
||||
(*func) (arg, pItem->zDatabase, strlen(pItem->zDatabase));
|
||||
(*func) (arg, ".", 1);
|
||||
}
|
||||
(*func) (arg, pItem->zName, strlen(pItem->zName));
|
||||
length = width = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
} /* End switch over the format type */
|
||||
/*
|
||||
** The text of the conversion is pointed to by "bufpt" and is
|
||||
** "length" characters long. The field width is "width". Do
|
||||
** the output.
|
||||
*/
|
||||
if (!flag_leftjustify) {
|
||||
register int nspace;
|
||||
nspace = width - length;
|
||||
if (nspace > 0) {
|
||||
count += nspace;
|
||||
while (nspace >= etSPACESIZE) {
|
||||
(*func) (arg, spaces, etSPACESIZE);
|
||||
nspace -= etSPACESIZE;
|
||||
}
|
||||
if (nspace > 0)
|
||||
(*func) (arg, spaces, nspace);
|
||||
}
|
||||
}
|
||||
if (length > 0) {
|
||||
(*func) (arg, bufpt, length);
|
||||
count += length;
|
||||
}
|
||||
if (flag_leftjustify) {
|
||||
register int nspace;
|
||||
nspace = width - length;
|
||||
if (nspace > 0) {
|
||||
count += nspace;
|
||||
while (nspace >= etSPACESIZE) {
|
||||
(*func) (arg, spaces, etSPACESIZE);
|
||||
nspace -= etSPACESIZE;
|
||||
}
|
||||
if (nspace > 0)
|
||||
(*func) (arg, spaces, nspace);
|
||||
}
|
||||
}
|
||||
if (zExtra) {
|
||||
free(zExtra);
|
||||
}
|
||||
} /* End for loop over the format string */
|
||||
return errorflag ? -1 : count;
|
||||
} /* End of function */
|
||||
|
||||
|
||||
/* This structure is used to store state information about the
|
||||
** write to memory that is currently in progress.
|
||||
*/
|
||||
struct sgMprintf {
|
||||
char *zBase; /* A base allocation */
|
||||
char *zText; /* The string collected so far */
|
||||
int nChar; /* Length of the string so far */
|
||||
int nTotal; /* Output size if unconstrained */
|
||||
int nAlloc; /* Amount of space allocated in zText */
|
||||
void *arg; /* Third arg to the realloc callback */
|
||||
void *(*xRealloc) (void *, int, void *); /* Function used to realloc memory */
|
||||
};
|
||||
|
||||
/*
|
||||
** This function implements the callback from vxprintf.
|
||||
**
|
||||
** This routine add nNewChar characters of text in zNewText to
|
||||
** the sgMprintf structure pointed to by "arg".
|
||||
*/
|
||||
static void mout(void *arg, const char *zNewText, int nNewChar)
|
||||
{
|
||||
struct sgMprintf *pM = (struct sgMprintf *) arg;
|
||||
pM->nTotal += nNewChar;
|
||||
if (pM->nChar + nNewChar + 1 > pM->nAlloc) {
|
||||
if (pM->xRealloc == 0) {
|
||||
nNewChar = pM->nAlloc - pM->nChar - 1;
|
||||
} else {
|
||||
pM->nAlloc = pM->nChar + nNewChar * 2 + 1;
|
||||
if (pM->zText == pM->zBase) {
|
||||
pM->zText = pM->xRealloc(0, pM->nAlloc, pM->arg);
|
||||
if (pM->zText && pM->nChar) {
|
||||
memcpy(pM->zText, pM->zBase, pM->nChar);
|
||||
}
|
||||
} else {
|
||||
char *zNew;
|
||||
zNew = pM->xRealloc(pM->zText, pM->nAlloc, pM->arg);
|
||||
if (zNew) {
|
||||
pM->zText = zNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pM->zText) {
|
||||
if (nNewChar > 0) {
|
||||
memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
|
||||
pM->nChar += nNewChar;
|
||||
}
|
||||
pM->zText[pM->nChar] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is a wrapper around xprintf() that invokes mout() as
|
||||
** the consumer.
|
||||
*/
|
||||
static char *base_vprintf(void *(*xRealloc) (void *, int, void *), /* Routine to realloc memory. May be NULL */
|
||||
int useInternal, /* Use internal %-conversions if true */
|
||||
char *zInitBuf, /* Initially write here, before mallocing */
|
||||
int nInitBuf, /* Size of zInitBuf[] */
|
||||
const char *zFormat, /* format string */
|
||||
va_list ap, /* arguments */
|
||||
void *realloc_arg /*arg to pass to realloc function*/
|
||||
)
|
||||
{
|
||||
struct sgMprintf sM;
|
||||
sM.zBase = sM.zText = zInitBuf;
|
||||
sM.nChar = sM.nTotal = 0;
|
||||
sM.nAlloc = nInitBuf;
|
||||
sM.xRealloc = xRealloc;
|
||||
sM.arg = realloc_arg;
|
||||
vxprintf(mout, &sM, useInternal, zFormat, ap);
|
||||
if (xRealloc) {
|
||||
if (sM.zText == sM.zBase) {
|
||||
sM.zText = xRealloc(0, sM.nChar + 1, realloc_arg);
|
||||
if (sM.zText) {
|
||||
memcpy(sM.zText, sM.zBase, sM.nChar + 1);
|
||||
}
|
||||
} else if (sM.nAlloc > sM.nChar + 10) {
|
||||
char *zNew = xRealloc(sM.zText, sM.nChar + 1, realloc_arg);
|
||||
if (zNew) {
|
||||
sM.zText = zNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sM.zText;
|
||||
}
|
||||
|
||||
/*
|
||||
** Realloc that is a real function, not a macro.
|
||||
*/
|
||||
static void *printf_realloc(void *old, int size, void *arg)
|
||||
{
|
||||
return realloc(old, size);
|
||||
}
|
||||
|
||||
/*
|
||||
** Print into memory. Omit the internal %-conversion extensions.
|
||||
*/
|
||||
KS_DECLARE(char *) ks_vmprintf(const char *zFormat, va_list ap)
|
||||
{
|
||||
char zBase[KS_PRINT_BUF_SIZE];
|
||||
return base_vprintf(printf_realloc, 0, zBase, sizeof(zBase), zFormat, ap, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** Print into memory. Omit the internal %-conversion extensions.
|
||||
*/
|
||||
KS_DECLARE(char *) ks_mprintf(const char *zFormat, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *z;
|
||||
char zBase[KS_PRINT_BUF_SIZE];
|
||||
va_start(ap, zFormat);
|
||||
z = base_vprintf(printf_realloc, 0, zBase, sizeof(zBase), zFormat, ap, NULL);
|
||||
va_end(ap);
|
||||
return z;
|
||||
}
|
||||
|
||||
/*
|
||||
** pool_realloc function
|
||||
*/
|
||||
static void *pool_realloc(void *old, int size, void *arg)
|
||||
{
|
||||
return ks_pool_resize(arg, old, size);
|
||||
}
|
||||
|
||||
/*
|
||||
** Print into pool memory. Omit the internal %-conversion extensions.
|
||||
*/
|
||||
KS_DECLARE(char *) ks_vpprintf(ks_pool_t *pool, const char *zFormat, va_list ap)
|
||||
{
|
||||
char zBase[KS_PRINT_BUF_SIZE];
|
||||
return base_vprintf(pool_realloc, 0, zBase, sizeof(zBase), zFormat, ap, pool);
|
||||
}
|
||||
|
||||
/*
|
||||
** Print into pool memory. Omit the internal %-conversion extensions.
|
||||
*/
|
||||
KS_DECLARE(char *) ks_pprintf(ks_pool_t *pool, const char *zFormat, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *z;
|
||||
char zBase[KS_PRINT_BUF_SIZE];
|
||||
va_start(ap, zFormat);
|
||||
z = base_vprintf(pool_realloc, 0, zBase, sizeof(zBase), zFormat, ap, pool);
|
||||
va_end(ap);
|
||||
return z;
|
||||
}
|
||||
|
||||
/*
|
||||
** ks_vsnprintf() works like vsnprintf() except that it ignores the
|
||||
** current locale settings. This is important for SQLite because we
|
||||
** are not able to use a "," as the decimal point in place of "." as
|
||||
** specified by some locales.
|
||||
*/
|
||||
KS_DECLARE(char *) ks_vsnprintfv(char *zBuf, int n, const char *zFormat, va_list ap)
|
||||
{
|
||||
return base_vprintf(0, 0, zBuf, n, zFormat, ap, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** ks_snprintf() works like snprintf() except that it ignores the
|
||||
** current locale settings. This is important for SQLite because we
|
||||
** are not able to use a "," as the decimal point in place of "." as
|
||||
** specified by some locales.
|
||||
*/
|
||||
|
||||
KS_DECLARE(char *) ks_snprintfv(char *zBuf, int n, const char *zFormat, ...)
|
||||
{
|
||||
char *z;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
z = base_vprintf(0, 0, zBuf, n, zFormat, ap, NULL);
|
||||
va_end(ap);
|
||||
return z;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,473 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2014, Anthony Minessale II
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 <ks.h>
|
||||
|
||||
typedef struct ks_qnode_s {
|
||||
void *ptr;
|
||||
struct ks_qnode_s *next;
|
||||
struct ks_qnode_s *prev;
|
||||
} ks_qnode_t;
|
||||
|
||||
struct ks_q_s {
|
||||
ks_pool_t *pool;
|
||||
ks_flush_fn_t flush_fn;
|
||||
void *flush_data;
|
||||
ks_size_t len;
|
||||
ks_size_t maxlen;
|
||||
ks_cond_t *pop_cond;
|
||||
ks_cond_t *push_cond;
|
||||
ks_mutex_t *list_mutex;
|
||||
uint32_t pushers;
|
||||
uint32_t poppers;
|
||||
struct ks_qnode_s *head;
|
||||
struct ks_qnode_s *tail;
|
||||
struct ks_qnode_s *empty;
|
||||
uint8_t active;
|
||||
};
|
||||
|
||||
static void ks_q_cleanup(ks_pool_t *mpool, void *ptr, void *arg, int type, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t ctype)
|
||||
{
|
||||
ks_q_t *q = (ks_q_t *) ptr;
|
||||
ks_qnode_t *np, *fp;
|
||||
|
||||
if (ctype == KS_MPCL_GLOBAL_FREE) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(action) {
|
||||
case KS_MPCL_ANNOUNCE:
|
||||
break;
|
||||
case KS_MPCL_TEARDOWN:
|
||||
np = q->head;
|
||||
while(np) {
|
||||
fp = np;
|
||||
np = np->next;
|
||||
ks_pool_free(q->pool, fp);
|
||||
}
|
||||
|
||||
np = q->empty;
|
||||
while(np) {
|
||||
fp = np;
|
||||
np = np->next;
|
||||
ks_pool_free(q->pool, fp);
|
||||
}
|
||||
break;
|
||||
case KS_MPCL_DESTROY:
|
||||
ks_cond_destroy(&q->pop_cond);
|
||||
ks_cond_destroy(&q->push_cond);
|
||||
ks_mutex_destroy(&q->list_mutex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_flush(ks_q_t *q)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (!q->active) return KS_STATUS_INACTIVE;
|
||||
if (!q->flush_fn) return KS_STATUS_FAIL;
|
||||
|
||||
while(ks_q_trypop(q, &ptr) == KS_STATUS_SUCCESS) {
|
||||
q->flush_fn(q, ptr, q->flush_data);
|
||||
}
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_set_flush_fn(ks_q_t *q, ks_flush_fn_t fn, void *flush_data)
|
||||
{
|
||||
if (!q->active) return KS_STATUS_INACTIVE;
|
||||
|
||||
q->flush_fn = fn;
|
||||
q->flush_data = flush_data;
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_wake(ks_q_t *q)
|
||||
{
|
||||
ks_mutex_lock(q->list_mutex);
|
||||
ks_cond_broadcast(q->push_cond);
|
||||
ks_cond_broadcast(q->pop_cond);
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_size_t) ks_q_term(ks_q_t *q)
|
||||
{
|
||||
int active;
|
||||
|
||||
ks_mutex_lock(q->list_mutex);
|
||||
active = q->active;
|
||||
q->active = 0;
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
|
||||
if (active) {
|
||||
ks_q_wake(q);
|
||||
}
|
||||
|
||||
return active ? KS_STATUS_SUCCESS : KS_STATUS_INACTIVE;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_size_t) ks_q_size(ks_q_t *q)
|
||||
{
|
||||
ks_size_t size;
|
||||
|
||||
ks_mutex_lock(q->list_mutex);
|
||||
size = q->len;
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_destroy(ks_q_t **qP)
|
||||
{
|
||||
ks_q_t *q;
|
||||
ks_pool_t *pool;
|
||||
|
||||
ks_assert(qP);
|
||||
|
||||
q = *qP;
|
||||
*qP = NULL;
|
||||
|
||||
if (q) {
|
||||
ks_q_flush(q);
|
||||
ks_q_term(q);
|
||||
|
||||
pool = q->pool;
|
||||
ks_pool_free(pool, q);
|
||||
pool = NULL;
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_create(ks_q_t **qP, ks_pool_t *pool, ks_size_t maxlen)
|
||||
{
|
||||
ks_q_t *q = NULL;
|
||||
|
||||
q = ks_pool_alloc(pool, sizeof(*q));
|
||||
ks_assert(q);
|
||||
|
||||
q->pool = pool;
|
||||
|
||||
|
||||
ks_mutex_create(&q->list_mutex, KS_MUTEX_FLAG_DEFAULT, pool);
|
||||
ks_assert(q->list_mutex);
|
||||
|
||||
ks_cond_create_ex(&q->pop_cond, pool, q->list_mutex);
|
||||
ks_assert(q->pop_cond);
|
||||
|
||||
ks_cond_create_ex(&q->push_cond, pool, q->list_mutex);
|
||||
ks_assert(q->push_cond);
|
||||
|
||||
q->maxlen = maxlen;
|
||||
q->active = 1;
|
||||
|
||||
ks_pool_set_cleanup(pool, q, NULL, 0, ks_q_cleanup);
|
||||
|
||||
*qP = q;
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static ks_qnode_t *new_node(ks_q_t *q)
|
||||
{
|
||||
ks_qnode_t *np;
|
||||
|
||||
if (q->empty) {
|
||||
np = q->empty;
|
||||
q->empty = q->empty->next;
|
||||
} else {
|
||||
np = ks_pool_alloc(q->pool, sizeof(*np));
|
||||
}
|
||||
|
||||
np->prev = np->next = NULL;
|
||||
np->ptr = NULL;
|
||||
|
||||
return np;
|
||||
}
|
||||
|
||||
static ks_status_t do_push(ks_q_t *q, void *ptr)
|
||||
{
|
||||
ks_qnode_t *node;
|
||||
|
||||
ks_mutex_lock(q->list_mutex);
|
||||
if (!q->active) {
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
return KS_STATUS_INACTIVE;
|
||||
}
|
||||
|
||||
node = new_node(q);
|
||||
node->ptr = ptr;
|
||||
|
||||
if (!q->head) {
|
||||
q->head = q->tail = node;
|
||||
} else {
|
||||
q->tail->next = node;
|
||||
node->prev = q->tail;
|
||||
q->tail = node;
|
||||
}
|
||||
q->len++;
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_push(ks_q_t *q, void *ptr)
|
||||
{
|
||||
ks_status_t r;
|
||||
|
||||
ks_mutex_lock(q->list_mutex);
|
||||
if (q->active == 0) {
|
||||
r = KS_STATUS_INACTIVE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
if (q->maxlen && q->len == q->maxlen) {
|
||||
q->pushers++;
|
||||
ks_cond_wait(q->push_cond);
|
||||
q->pushers--;
|
||||
|
||||
if (q->maxlen && q->len == q->maxlen) {
|
||||
if (!q->active) {
|
||||
r = KS_STATUS_INACTIVE;
|
||||
} else {
|
||||
r = KS_STATUS_BREAK;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
r = do_push(q, ptr);
|
||||
|
||||
if (q->poppers) {
|
||||
ks_cond_signal(q->pop_cond);
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_trypush(ks_q_t *q, void *ptr)
|
||||
{
|
||||
ks_status_t r;
|
||||
|
||||
ks_mutex_lock(q->list_mutex);
|
||||
if (q->active == 0) {
|
||||
r = KS_STATUS_INACTIVE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (q->maxlen && q->len == q->maxlen) {
|
||||
r = KS_STATUS_BREAK;
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = do_push(q, ptr);
|
||||
|
||||
if (q->poppers) {
|
||||
ks_cond_signal(q->pop_cond);
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static ks_status_t do_pop(ks_q_t *q, void **ptr)
|
||||
{
|
||||
ks_qnode_t *np;
|
||||
|
||||
ks_mutex_lock(q->list_mutex);
|
||||
|
||||
if (!q->active) {
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
return KS_STATUS_INACTIVE;
|
||||
}
|
||||
|
||||
if (!q->head) {
|
||||
*ptr = NULL;
|
||||
} else {
|
||||
np = q->head;
|
||||
if ((q->head = q->head->next)) {
|
||||
q->head->prev = NULL;
|
||||
}
|
||||
|
||||
*ptr = np->ptr;
|
||||
|
||||
np->next = q->empty;
|
||||
np->prev = NULL;
|
||||
np->ptr = NULL;
|
||||
q->empty = np;
|
||||
}
|
||||
|
||||
q->len--;
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_pop_timeout(ks_q_t *q, void **ptr, uint32_t timeout)
|
||||
{
|
||||
ks_status_t r;
|
||||
|
||||
ks_mutex_lock(q->list_mutex);
|
||||
|
||||
if (!q->active) {
|
||||
r = KS_STATUS_INACTIVE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (q->len == 0) {
|
||||
if (q->active) {
|
||||
q->poppers++;
|
||||
if (timeout) {
|
||||
r = ks_cond_timedwait(q->pop_cond, timeout);
|
||||
} else {
|
||||
r = ks_cond_wait(q->pop_cond);
|
||||
}
|
||||
q->poppers--;
|
||||
|
||||
if (timeout && r != KS_STATUS_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (q->len == 0) {
|
||||
if (!q->active) {
|
||||
r = KS_STATUS_INACTIVE;
|
||||
} else {
|
||||
r = KS_STATUS_BREAK;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
r = do_pop(q, ptr);
|
||||
|
||||
if (q->pushers) {
|
||||
ks_cond_signal(q->push_cond);
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_pop(ks_q_t *q, void **ptr)
|
||||
{
|
||||
return ks_q_pop_timeout(q, ptr, 0);
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_trypop(ks_q_t *q, void **ptr)
|
||||
{
|
||||
ks_status_t r;
|
||||
|
||||
ks_mutex_lock(q->list_mutex);
|
||||
|
||||
if (!q->active) {
|
||||
r = KS_STATUS_INACTIVE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (q->len == 0) {
|
||||
r = KS_STATUS_BREAK;
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = do_pop(q, ptr);
|
||||
|
||||
if (q->pushers) {
|
||||
ks_cond_signal(q->push_cond);
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_q_wait(ks_q_t *q)
|
||||
{
|
||||
ks_status_t r = KS_STATUS_SUCCESS;
|
||||
int done = 0;
|
||||
|
||||
do {
|
||||
ks_mutex_lock(q->list_mutex);
|
||||
|
||||
if (!q->active) {
|
||||
r = KS_STATUS_INACTIVE;
|
||||
done = 1;
|
||||
}
|
||||
|
||||
if (q->len == 0) {
|
||||
done = 1;
|
||||
}
|
||||
|
||||
ks_mutex_unlock(q->list_mutex);
|
||||
|
||||
} while (!done);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Cross Platform random/uuid abstraction
|
||||
* Copyright(C) 2015 Michael Jerris
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so.
|
||||
*
|
||||
* This work is provided under this license on an "as is" basis, without warranty of any kind,
|
||||
* either expressed or implied, including, without limitation, warranties that the covered code
|
||||
* is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
|
||||
* risk as to the quality and performance of the covered code is with you. Should any covered
|
||||
* code prove defective in any respect, you (not the initial developer or any other contributor)
|
||||
* assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
|
||||
* constitutes an essential part of this license. No use of any covered code is authorized hereunder
|
||||
* except under this disclaimer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ks.h"
|
||||
#include "sodium.h"
|
||||
#include <aes.h>
|
||||
#include <sha2.h>
|
||||
|
||||
static ks_bool_t initialized = KS_FALSE;
|
||||
static ks_mutex_t *rng_mutex = NULL;
|
||||
static sha512_ctx global_sha512;
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <Wincrypt.h>
|
||||
HCRYPTPROV crypt_provider;
|
||||
#else
|
||||
int fd = -1;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* memset_volatile is a volatile pointer to the memset function.
|
||||
* You can call (*memset_volatile)(buf, val, len) or even
|
||||
* memset_volatile(buf, val, len) just as you would call
|
||||
* memset(buf, val, len), but the use of a volatile pointer
|
||||
* guarantees that the compiler will not optimise the call away.
|
||||
*/
|
||||
//static void * (*volatile memset_volatile)(void *, int, size_t) = memset;
|
||||
|
||||
KS_DECLARE(uuid_t *) ks_uuid(uuid_t *uuid)
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
UuidCreate ( uuid );
|
||||
#else
|
||||
uuid_generate_random ( *uuid );
|
||||
#endif
|
||||
return uuid;
|
||||
}
|
||||
|
||||
KS_DECLARE(char *) ks_uuid_str(ks_pool_t *pool, uuid_t *uuid)
|
||||
{
|
||||
char *uuidstr = ks_pool_alloc(pool, 37);
|
||||
#ifdef __WINDOWS__
|
||||
unsigned char * str;
|
||||
UuidToStringA ( uuid, &str );
|
||||
uuidstr = ks_pstrdup(pool, str);
|
||||
RpcStringFreeA ( &str );
|
||||
#else
|
||||
char str[37] = { 0 };
|
||||
uuid_unparse ( *uuid, str );
|
||||
uuidstr = ks_pstrdup(pool, str);
|
||||
#endif
|
||||
return uuidstr;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rng_init(void)
|
||||
{
|
||||
if (!initialized) {
|
||||
if (sodium_init() == -1) {
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
randombytes_random();
|
||||
ks_aes_init();
|
||||
ks_mutex_create(&rng_mutex, KS_MUTEX_FLAG_DEFAULT, ks_global_pool());
|
||||
#ifdef __WINDOWS__
|
||||
if (!crypt_provider) {
|
||||
if (CryptAcquireContext(&crypt_provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == TRUE) {
|
||||
initialized = KS_TRUE;
|
||||
} else {
|
||||
initialized = KS_FALSE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (fd < 0) {
|
||||
fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fd = open("/dev/random", O_RDONLY);
|
||||
}
|
||||
}
|
||||
initialized = KS_TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
sha512_begin(&global_sha512);
|
||||
|
||||
if (initialized) {
|
||||
return KS_STATUS_SUCCESS;
|
||||
} else {
|
||||
return KS_STATUS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_rng_shutdown(void)
|
||||
{
|
||||
|
||||
initialized = KS_FALSE;
|
||||
#ifdef __WINDOWS__
|
||||
if (crypt_provider) {
|
||||
CryptReleaseContext(crypt_provider, 0);
|
||||
crypt_provider = 0;
|
||||
}
|
||||
#else
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
#endif
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(size_t) ks_rng_seed_data(uint8_t *seed, size_t length)
|
||||
{
|
||||
size_t bytes = 0;
|
||||
|
||||
if (!initialized && (ks_rng_init() != KS_STATUS_SUCCESS)) {
|
||||
return bytes;
|
||||
}
|
||||
#ifdef __WINDOWS__
|
||||
if (crypt_provider) {
|
||||
if(!CryptGenRandom(crypt_provider, length, seed)) {
|
||||
return 0;
|
||||
}
|
||||
bytes = length;
|
||||
}
|
||||
#else
|
||||
if (fd >= 0) {
|
||||
bytes = read(fd, seed, length);
|
||||
} else {
|
||||
}
|
||||
#endif
|
||||
return bytes;
|
||||
}
|
||||
|
||||
KS_DECLARE(size_t) ks_rng_add_entropy(const uint8_t *buffer, size_t length)
|
||||
{
|
||||
|
||||
uint8_t seed[64];
|
||||
size_t len = ks_rng_seed_data(seed, sizeof(seed));
|
||||
|
||||
ks_mutex_lock(rng_mutex);
|
||||
|
||||
if (!initialized) {
|
||||
ks_rng_init();
|
||||
}
|
||||
|
||||
if (buffer && length) {
|
||||
sha512_hash(buffer, length, &global_sha512);
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
sha512_hash(seed, len, &global_sha512);
|
||||
length += len;
|
||||
}
|
||||
|
||||
ks_mutex_unlock(rng_mutex);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
KS_DECLARE(size_t) ks_rng_get_data(uint8_t* buffer, size_t length) {
|
||||
randombytes_buf(buffer, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
KS_DECLARE(size_t) ks_rng_get_data(uint8_t* buffer, size_t length) {
|
||||
|
||||
aes_encrypt_ctx cx[1];
|
||||
sha512_ctx random_context;
|
||||
uint8_t md[SHA512_DIGEST_SIZE];
|
||||
uint8_t ctr[AES_BLOCK_SIZE];
|
||||
uint8_t rdata[AES_BLOCK_SIZE];
|
||||
size_t generated = length;
|
||||
|
||||
/* Add entropy from system state. We will include whatever happens to be in the buffer, it can't hurt */
|
||||
ks_rng_add_entropy(buffer, length);
|
||||
|
||||
ks_mutex_lock(rng_mutex);
|
||||
|
||||
/* Copy the mainCtx and finalize it into the md buffer */
|
||||
memcpy(&random_context, &global_sha512, sizeof(sha512_ctx));
|
||||
sha512_end(md, &random_context);
|
||||
|
||||
ks_mutex_lock(rng_mutex);
|
||||
|
||||
/* Key an AES context from this buffer */
|
||||
aes_encrypt_key256(md, cx);
|
||||
|
||||
/* Initialize counter, using excess from md if available */
|
||||
memset (ctr, 0, sizeof(ctr));
|
||||
uint32_t ctrbytes = AES_BLOCK_SIZE;
|
||||
memcpy(ctr + sizeof(ctr) - ctrbytes, md + 32, ctrbytes);
|
||||
|
||||
/* Encrypt counter, copy to destination buffer, increment counter */
|
||||
while (length) {
|
||||
uint8_t *ctrptr;
|
||||
size_t copied;
|
||||
aes_encrypt(ctr, rdata, cx);
|
||||
copied = (sizeof(rdata) < length) ? sizeof(rdata) : length;
|
||||
memcpy (buffer, rdata, copied);
|
||||
buffer += copied;
|
||||
length -= copied;
|
||||
|
||||
/* Increment counter */
|
||||
ctrptr = ctr + sizeof(ctr) - 1;
|
||||
while (ctrptr >= ctr) {
|
||||
if ((*ctrptr-- += 1) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
memset_volatile(&random_context, 0, sizeof(random_context));
|
||||
memset_volatile(md, 0, sizeof(md));
|
||||
memset_volatile(&cx, 0, sizeof(cx));
|
||||
memset_volatile(ctr, 0, sizeof(ctr));
|
||||
memset_volatile(rdata, 0, sizeof(rdata));
|
||||
|
||||
return generated;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2014, Anthony Minessale II
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 <ks.h>
|
||||
|
||||
static ks_mutex_t **ssl_mutexes;
|
||||
static ks_pool_t *ssl_pool = NULL;
|
||||
static int ssl_count = 0;
|
||||
static int is_init = 0;
|
||||
|
||||
static inline void ks_ssl_lock_callback(int mode, int type, char *file, int line)
|
||||
{
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
ks_mutex_lock(ssl_mutexes[type]);
|
||||
}
|
||||
else {
|
||||
ks_mutex_unlock(ssl_mutexes[type]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned long ks_ssl_thread_id(void)
|
||||
{
|
||||
return (unsigned long) ks_thread_self();
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_ssl_init_ssl_locks(void)
|
||||
{
|
||||
|
||||
int i, num;
|
||||
|
||||
if (is_init) return;
|
||||
|
||||
is_init = 1;
|
||||
|
||||
SSL_library_init();
|
||||
|
||||
if (ssl_count == 0) {
|
||||
num = CRYPTO_num_locks();
|
||||
|
||||
ssl_mutexes = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(ks_mutex_t*));
|
||||
ks_assert(ssl_mutexes != NULL);
|
||||
|
||||
ks_pool_open(&ssl_pool);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
ks_mutex_create(&(ssl_mutexes[i]), KS_MUTEX_FLAG_DEFAULT, ssl_pool);
|
||||
ks_assert(ssl_mutexes[i] != NULL);
|
||||
}
|
||||
|
||||
CRYPTO_set_id_callback(ks_ssl_thread_id);
|
||||
CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))ks_ssl_lock_callback);
|
||||
}
|
||||
|
||||
ssl_count++;
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_ssl_destroy_ssl_locks(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!is_init) return;
|
||||
|
||||
is_init = 0;
|
||||
|
||||
if (ssl_count == 1) {
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
if (ssl_mutexes[i]) {
|
||||
ks_mutex_destroy(&ssl_mutexes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
OPENSSL_free(ssl_mutexes);
|
||||
ssl_count--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days);
|
||||
|
||||
KS_DECLARE(int) ks_gen_cert(const char *dir, const char *file)
|
||||
{
|
||||
//BIO *bio_err;
|
||||
X509 *x509 = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
char *rsa = NULL, *pvt = NULL;
|
||||
FILE *fp;
|
||||
char *pem = NULL;
|
||||
|
||||
if (ks_stristr(".pem", file)) {
|
||||
pem = ks_mprintf("%s%s%s", dir, KS_PATH_SEPARATOR, file);
|
||||
} else {
|
||||
pvt = ks_mprintf("%s%s%s.key", dir, KS_PATH_SEPARATOR, file);
|
||||
rsa = ks_mprintf("%s%s%s.crt", dir, KS_PATH_SEPARATOR, file);
|
||||
}
|
||||
|
||||
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
|
||||
|
||||
//bio_err=BIO_new_fp(stderr, BIO_NOCLOSE);
|
||||
|
||||
mkcert(&x509, &pkey, 1024, 0, 36500);
|
||||
|
||||
//RSA_print_fp(stdout, pkey->pkey.rsa, 0);
|
||||
//X509_print_fp(stdout, x509);
|
||||
|
||||
if (pem) {
|
||||
if ((fp = fopen(pem, "w"))) {
|
||||
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
|
||||
PEM_write_X509(fp, x509);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (pvt && (fp = fopen(pvt, "w"))) {
|
||||
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (rsa && (fp = fopen(rsa, "w"))) {
|
||||
PEM_write_X509(fp, x509);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
X509_free(x509);
|
||||
EVP_PKEY_free(pkey);
|
||||
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
ENGINE_cleanup();
|
||||
#endif
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
|
||||
//CRYPTO_mem_leaks(bio_err);
|
||||
//BIO_free(bio_err);
|
||||
|
||||
|
||||
ks_safe_free(pvt);
|
||||
ks_safe_free(rsa);
|
||||
ks_safe_free(pem);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days)
|
||||
{
|
||||
X509 *x;
|
||||
EVP_PKEY *pk;
|
||||
RSA *rsa;
|
||||
X509_NAME *name=NULL;
|
||||
|
||||
ks_assert(pkeyp);
|
||||
ks_assert(x509p);
|
||||
|
||||
if (*pkeyp == NULL) {
|
||||
if ((pk = EVP_PKEY_new()) == NULL) {
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
pk = *pkeyp;
|
||||
}
|
||||
|
||||
if (*x509p == NULL) {
|
||||
if ((x = X509_new()) == NULL) {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
x = *x509p;
|
||||
}
|
||||
|
||||
rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
|
||||
|
||||
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
|
||||
abort();
|
||||
goto err;
|
||||
}
|
||||
|
||||
rsa = NULL;
|
||||
|
||||
X509_set_version(x, 0);
|
||||
ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
|
||||
X509_gmtime_adj(X509_get_notBefore(x), -(long)60*60*24*7);
|
||||
X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
|
||||
X509_set_pubkey(x, pk);
|
||||
|
||||
name = X509_get_subject_name(x);
|
||||
|
||||
/* This function creates and adds the entry, working out the
|
||||
* correct string type and performing checks on its length.
|
||||
* Normally we'd check the return value for errors...
|
||||
*/
|
||||
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0);
|
||||
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"FreeSWITCH-libKS", -1, -1, 0);
|
||||
|
||||
|
||||
/* Its self signed so set the issuer name to be the same as the
|
||||
* subject.
|
||||
*/
|
||||
X509_set_issuer_name(x, name);
|
||||
|
||||
if (!X509_sign(x, pk, EVP_sha1()))
|
||||
goto err;
|
||||
|
||||
*x509p = x;
|
||||
*pkeyp = pk;
|
||||
return(1);
|
||||
err:
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2014, Anthony Minessale II
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 <ks.h>
|
||||
|
||||
/* Written by Marc Espie, public domain */
|
||||
#define KS_CTYPE_NUM_CHARS 256
|
||||
|
||||
const short _ks_C_toupper_[1 + KS_CTYPE_NUM_CHARS] = {
|
||||
EOF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
||||
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||
};
|
||||
|
||||
const short *_ks_toupper_tab_ = _ks_C_toupper_;
|
||||
|
||||
KS_DECLARE(int) ks_toupper(int c)
|
||||
{
|
||||
if ((unsigned int) c > 255)
|
||||
return (c);
|
||||
if (c < -1)
|
||||
return EOF;
|
||||
return ((_ks_toupper_tab_ + 1)[c]);
|
||||
}
|
||||
|
||||
const short _ks_C_tolower_[1 + KS_CTYPE_NUM_CHARS] = {
|
||||
EOF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
||||
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
|
||||
'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||
};
|
||||
|
||||
const short *_ks_tolower_tab_ = _ks_C_tolower_;
|
||||
|
||||
KS_DECLARE(int) ks_tolower(int c)
|
||||
{
|
||||
if ((unsigned int) c > 255)
|
||||
return (c);
|
||||
if (c < -1)
|
||||
return EOF;
|
||||
return ((_ks_tolower_tab_ + 1)[c]);
|
||||
}
|
||||
|
||||
KS_DECLARE(const char *) ks_stristr(const char *instr, const char *str)
|
||||
{
|
||||
/*
|
||||
** Rev History: 16/07/97 Greg Thayer Optimized
|
||||
** 07/04/95 Bob Stout ANSI-fy
|
||||
** 02/03/94 Fred Cole Original
|
||||
** 09/01/03 Bob Stout Bug fix (lines 40-41) per Fred Bulback
|
||||
**
|
||||
** Hereby donated to public domain.
|
||||
*/
|
||||
const char *pptr, *sptr, *start;
|
||||
|
||||
if (!str || !instr)
|
||||
return NULL;
|
||||
|
||||
for (start = str; *start; start++) {
|
||||
/* find start of pattern in string */
|
||||
for (; ((*start) && (ks_toupper(*start) != ks_toupper(*instr))); start++);
|
||||
|
||||
if (!*start)
|
||||
return NULL;
|
||||
|
||||
pptr = instr;
|
||||
sptr = start;
|
||||
|
||||
while (ks_toupper(*sptr) == ks_toupper(*pptr)) {
|
||||
sptr++;
|
||||
pptr++;
|
||||
|
||||
/* if end of pattern then pattern was found */
|
||||
if (!*pptr)
|
||||
return (start);
|
||||
|
||||
if (!*sptr)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef vsnprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
int vasprintf(char **ret, const char *format, va_list ap);
|
||||
|
||||
KS_DECLARE(int) ks_vasprintf(char **ret, const char *fmt, va_list ap)
|
||||
{
|
||||
#if !defined(WIN32) && !defined(__sun)
|
||||
return vasprintf(ret, fmt, ap);
|
||||
#else
|
||||
char *buf;
|
||||
int len;
|
||||
size_t buflen;
|
||||
va_list ap2;
|
||||
char *tmp = NULL;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1500
|
||||
/* hack for incorrect assumption in msvc header files for code analysis */
|
||||
__analysis_assume(tmp);
|
||||
#endif
|
||||
ap2 = ap;
|
||||
#else
|
||||
va_copy(ap2, ap);
|
||||
#endif
|
||||
|
||||
len = vsnprintf(tmp, 0, fmt, ap2);
|
||||
|
||||
if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) {
|
||||
len = vsnprintf(buf, buflen, fmt, ap);
|
||||
*ret = buf;
|
||||
} else {
|
||||
*ret = NULL;
|
||||
len = -1;
|
||||
}
|
||||
|
||||
va_end(ap2);
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
KS_DECLARE(int) ks_snprintf(char *buffer, size_t count, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vsnprintf(buffer, count - 1, fmt, ap);
|
||||
if (ret < 0)
|
||||
buffer[count - 1] = '\0';
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
KS_DECLARE(unsigned int) ks_separate_string(char *buf, const char *delim, char **array, unsigned int arraylen)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
char *d;
|
||||
size_t dlen = strlen(delim);
|
||||
|
||||
array[count++] = buf;
|
||||
|
||||
while (count < arraylen && array[count - 1]) {
|
||||
if ((d = strstr(array[count - 1], delim))) {
|
||||
*d = '\0';
|
||||
d += dlen;
|
||||
array[count++] = d;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
KS_DECLARE(char *) ks_copy_string(char *from_str, const char *to_str, ks_size_t from_str_len)
|
||||
{
|
||||
char *p, *e;
|
||||
|
||||
if (!from_str)
|
||||
return NULL;
|
||||
if (!to_str) {
|
||||
*from_str = '\0';
|
||||
return from_str;
|
||||
}
|
||||
|
||||
e = from_str + from_str_len - 1;
|
||||
|
||||
for (p = from_str; p < e; ++p, ++to_str) {
|
||||
if (!(*p = *to_str)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
|
||||
return p;
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* Cross Platform Thread/Mutex abstraction
|
||||
* Copyright(C) 2007 Michael Jerris
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so.
|
||||
*
|
||||
* This work is provided under this license on an "as is" basis, without warranty of any kind,
|
||||
* either expressed or implied, including, without limitation, warranties that the covered code
|
||||
* is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
|
||||
* risk as to the quality and performance of the covered code is with you. Should any covered
|
||||
* code prove defective in any respect, you (not the initial developer or any other contributor)
|
||||
* assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
|
||||
* constitutes an essential part of this license. No use of any covered code is authorized hereunder
|
||||
* except under this disclaimer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ks.h"
|
||||
|
||||
size_t thread_default_stacksize = 240 * 1024;
|
||||
|
||||
#ifndef WIN32
|
||||
pthread_once_t init_priority = PTHREAD_ONCE_INIT;
|
||||
#endif
|
||||
|
||||
KS_DECLARE(ks_thread_os_handle_t) ks_thread_os_handle(ks_thread_t *thread)
|
||||
{
|
||||
return thread->handle;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_thread_os_handle_t) ks_thread_self(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return GetCurrentThread();
|
||||
#else
|
||||
return pthread_self();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ks_thread_init_priority(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
|
||||
#else
|
||||
#ifdef USE_SCHED_SETSCHEDULER
|
||||
/*
|
||||
* Try to use a round-robin scheduler
|
||||
* with a fallback if that does not work
|
||||
*/
|
||||
struct sched_param sched = { 0 };
|
||||
sched.sched_priority = KS_PRI_LOW;
|
||||
if (sched_setscheduler(0, SCHED_FIFO, &sched)) {
|
||||
sched.sched_priority = 0;
|
||||
if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
void ks_thread_override_default_stacksize(size_t size)
|
||||
{
|
||||
thread_default_stacksize = size;
|
||||
}
|
||||
|
||||
static void ks_thread_cleanup(ks_pool_t *mpool, void *ptr, void *arg, int type, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t ctype)
|
||||
{
|
||||
ks_thread_t *thread = (ks_thread_t *) ptr;
|
||||
|
||||
switch(action) {
|
||||
case KS_MPCL_ANNOUNCE:
|
||||
thread->running = 0;
|
||||
break;
|
||||
case KS_MPCL_TEARDOWN:
|
||||
if (!(thread->flags & KS_THREAD_FLAG_DETATCHED)) {
|
||||
ks_thread_join(thread);
|
||||
}
|
||||
break;
|
||||
case KS_MPCL_DESTROY:
|
||||
#ifdef WIN32
|
||||
if (!(thread->flags & KS_THREAD_FLAG_DETATCHED)) {
|
||||
CloseHandle(thread->handle);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void *KS_THREAD_CALLING_CONVENTION thread_launch(void *args)
|
||||
{
|
||||
ks_thread_t *thread = (ks_thread_t *) args;
|
||||
|
||||
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
|
||||
if (thread->priority) {
|
||||
int policy = SCHED_FIFO;
|
||||
struct sched_param param = { 0 };
|
||||
pthread_t tt = pthread_self();
|
||||
|
||||
pthread_once(&init_priority, ks_thread_init_priority);
|
||||
pthread_getschedparam(tt, &policy, ¶m);
|
||||
param.sched_priority = thread->priority;
|
||||
pthread_setschedparam(tt, policy, ¶m);
|
||||
}
|
||||
#endif
|
||||
|
||||
thread->return_data = thread->function(thread, thread->private_data);
|
||||
#ifndef WIN32
|
||||
pthread_attr_destroy(&thread->attribute);
|
||||
#endif
|
||||
|
||||
return thread->return_data;
|
||||
}
|
||||
|
||||
KS_DECLARE(int) ks_thread_set_priority(int nice_val)
|
||||
{
|
||||
#ifdef WIN32
|
||||
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
|
||||
#else
|
||||
#ifdef USE_SCHED_SETSCHEDULER
|
||||
/*
|
||||
* Try to use a round-robin scheduler
|
||||
* with a fallback if that does not work
|
||||
*/
|
||||
struct sched_param sched = { 0 };
|
||||
sched.sched_priority = KS_PRI_LOW;
|
||||
if (sched_setscheduler(0, SCHED_FIFO, &sched)) {
|
||||
sched.sched_priority = 0;
|
||||
if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nice_val) {
|
||||
#ifdef HAVE_SETPRIORITY
|
||||
/*
|
||||
* setpriority() works on FreeBSD (6.2), nice() doesn't
|
||||
*/
|
||||
if (setpriority(PRIO_PROCESS, getpid(), nice_val) < 0) {
|
||||
ks_log(KS_LOG_CRIT, "Could not set nice level\n");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if (nice(nice_val) != nice_val) {
|
||||
ks_log(KS_LOG_CRIT, "Could not set nice level\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
KS_DECLARE(uint8_t) ks_thread_priority(ks_thread_t *thread) {
|
||||
uint8_t priority = 0;
|
||||
#ifdef WIN32
|
||||
DWORD pri = GetThreadPriority(thread->handle);
|
||||
|
||||
if (pri >= THREAD_PRIORITY_TIME_CRITICAL) {
|
||||
priority = 99;
|
||||
} else if (pri >= THREAD_PRIORITY_ABOVE_NORMAL) {
|
||||
priority = 50;
|
||||
} else {
|
||||
priority = 10;
|
||||
}
|
||||
#else
|
||||
int policy;
|
||||
struct sched_param param = { 0 };
|
||||
|
||||
pthread_getschedparam(thread->handle, &policy, ¶m);
|
||||
priority = param.sched_priority;
|
||||
#endif
|
||||
return priority;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_thread_join(ks_thread_t *thread) {
|
||||
#ifdef WIN32
|
||||
WaitForSingleObject(thread->handle, INFINITE);
|
||||
#else
|
||||
void *ret;
|
||||
pthread_join(thread->handle, &ret);
|
||||
#endif
|
||||
return KS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_status_t) ks_thread_create_ex(ks_thread_t **rthread, ks_thread_function_t func, void *data,
|
||||
uint32_t flags, size_t stack_size, ks_thread_priority_t priority, ks_pool_t *pool)
|
||||
{
|
||||
ks_thread_t *thread = NULL;
|
||||
ks_status_t status = KS_STATUS_FAIL;
|
||||
|
||||
if (!rthread) goto done;
|
||||
|
||||
*rthread = NULL;
|
||||
|
||||
if (!func || !pool) goto done;
|
||||
|
||||
thread = (ks_thread_t *) ks_pool_alloc(pool, sizeof(ks_thread_t));
|
||||
|
||||
if (!thread) goto done;
|
||||
|
||||
thread->private_data = data;
|
||||
thread->function = func;
|
||||
thread->stack_size = stack_size;
|
||||
thread->running = 1;
|
||||
thread->flags = flags;
|
||||
thread->priority = priority;
|
||||
thread->pool = pool;
|
||||
|
||||
#if defined(WIN32)
|
||||
thread->handle = (void *) _beginthreadex(NULL, (unsigned) thread->stack_size, (unsigned int (__stdcall *) (void *)) thread_launch, thread, 0, NULL);
|
||||
|
||||
if (!thread->handle) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (priority >= 99) {
|
||||
SetThreadPriority(thread->handle, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
} else if (priority >= 50) {
|
||||
SetThreadPriority(thread->handle, THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
} else if (priority >= 10) {
|
||||
SetThreadPriority(thread->handle, THREAD_PRIORITY_NORMAL);
|
||||
} else if (priority >= 1) {
|
||||
SetThreadPriority(thread->handle, THREAD_PRIORITY_LOWEST);
|
||||
}
|
||||
|
||||
if (flags & KS_THREAD_FLAG_DETATCHED) {
|
||||
CloseHandle(thread->handle);
|
||||
}
|
||||
|
||||
status = KS_STATUS_SUCCESS;
|
||||
goto done;
|
||||
#else
|
||||
|
||||
if (pthread_attr_init(&thread->attribute) != 0)
|
||||
goto fail;
|
||||
|
||||
if ((flags & KS_THREAD_FLAG_DETATCHED) && pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0)
|
||||
goto failpthread;
|
||||
|
||||
if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0)
|
||||
goto failpthread;
|
||||
|
||||
if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0)
|
||||
goto failpthread;
|
||||
|
||||
status = KS_STATUS_SUCCESS;
|
||||
goto done;
|
||||
|
||||
failpthread:
|
||||
|
||||
pthread_attr_destroy(&thread->attribute);
|
||||
#endif
|
||||
|
||||
fail:
|
||||
if (thread) {
|
||||
thread->running = 0;
|
||||
if (pool) {
|
||||
ks_pool_safe_free(pool, thread);
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (status == KS_STATUS_SUCCESS) {
|
||||
*rthread = thread;
|
||||
ks_pool_set_cleanup(pool, thread, NULL, 0, ks_thread_cleanup);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2014, Anthony Minessale II
|
||||
* 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 the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 <ks.h>
|
||||
|
||||
#ifdef WIN32
|
||||
static CRITICAL_SECTION timer_section;
|
||||
static ks_time_t win32_tick_time_since_start = -1;
|
||||
static DWORD win32_last_get_time_tick = 0;
|
||||
|
||||
static uint8_t win32_use_qpc = 0;
|
||||
static uint64_t win32_qpc_freq = 0;
|
||||
static int timer_init;
|
||||
static inline void win32_init_timers(void)
|
||||
{
|
||||
OSVERSIONINFOEX version_info; /* Used to fetch current OS version from Windows */
|
||||
InitializeCriticalSection(&timer_section);
|
||||
EnterCriticalSection(&timer_section);
|
||||
|
||||
ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX));
|
||||
version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||
|
||||
/* Check if we should use timeGetTime() (pre-Vista) or QueryPerformanceCounter() (Vista and later) */
|
||||
|
||||
if (GetVersionEx((OSVERSIONINFO*) &version_info)) {
|
||||
if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 6) {
|
||||
if (QueryPerformanceFrequency((LARGE_INTEGER*)&win32_qpc_freq) && win32_qpc_freq > 0) {
|
||||
/* At least Vista, and QueryPerformanceFrequency() suceeded, enable qpc */
|
||||
win32_use_qpc = 1;
|
||||
} else {
|
||||
/* At least Vista, but QueryPerformanceFrequency() failed, disable qpc */
|
||||
win32_use_qpc = 0;
|
||||
}
|
||||
} else {
|
||||
/* Older then Vista, disable qpc */
|
||||
win32_use_qpc = 0;
|
||||
}
|
||||
} else {
|
||||
/* Unknown version - we want at least Vista, disable qpc */
|
||||
win32_use_qpc = 0;
|
||||
}
|
||||
|
||||
if (win32_use_qpc) {
|
||||
uint64_t count = 0;
|
||||
|
||||
if (!QueryPerformanceCounter((LARGE_INTEGER*)&count) || count == 0) {
|
||||
/* Call to QueryPerformanceCounter() failed, disable qpc again */
|
||||
win32_use_qpc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!win32_use_qpc) {
|
||||
/* This will enable timeGetTime() instead, qpc init failed */
|
||||
win32_last_get_time_tick = timeGetTime();
|
||||
win32_tick_time_since_start = win32_last_get_time_tick;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&timer_section);
|
||||
|
||||
timer_init = 1;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_time_t) ks_time_now(void)
|
||||
{
|
||||
ks_time_t now;
|
||||
|
||||
if (!timer_init) {
|
||||
win32_init_timers();
|
||||
}
|
||||
|
||||
if (win32_use_qpc) {
|
||||
/* Use QueryPerformanceCounter */
|
||||
uint64_t count = 0;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&count);
|
||||
now = ((count * 1000000) / win32_qpc_freq);
|
||||
} else {
|
||||
/* Use good old timeGetTime() */
|
||||
DWORD tick_now;
|
||||
DWORD tick_diff;
|
||||
|
||||
tick_now = timeGetTime();
|
||||
if (win32_tick_time_since_start != -1) {
|
||||
EnterCriticalSection(&timer_section);
|
||||
/* just add diff (to make it work more than 50 days). */
|
||||
tick_diff = tick_now - win32_last_get_time_tick;
|
||||
win32_tick_time_since_start += tick_diff;
|
||||
|
||||
win32_last_get_time_tick = tick_now;
|
||||
now = (win32_tick_time_since_start * 1000);
|
||||
LeaveCriticalSection(&timer_section);
|
||||
} else {
|
||||
/* If someone is calling us before timer is initialized,
|
||||
* return the current tick
|
||||
*/
|
||||
now = (tick_now * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
return now;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_time_t) ks_time_now_sec(void)
|
||||
{
|
||||
ks_time_t now;
|
||||
|
||||
if (!timer_init) {
|
||||
win32_init_timers();
|
||||
}
|
||||
|
||||
if (win32_use_qpc) {
|
||||
/* Use QueryPerformanceCounter */
|
||||
uint64_t count = 0;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&count);
|
||||
now = (count / win32_qpc_freq);
|
||||
} else {
|
||||
/* Use good old timeGetTime() */
|
||||
DWORD tick_now;
|
||||
DWORD tick_diff;
|
||||
|
||||
tick_now = timeGetTime();
|
||||
if (win32_tick_time_since_start != -1) {
|
||||
EnterCriticalSection(&timer_section);
|
||||
/* just add diff (to make it work more than 50 days). */
|
||||
tick_diff = tick_now - win32_last_get_time_tick;
|
||||
win32_tick_time_since_start += tick_diff;
|
||||
|
||||
win32_last_get_time_tick = tick_now;
|
||||
now = (win32_tick_time_since_start / 1000);
|
||||
LeaveCriticalSection(&timer_section);
|
||||
} else {
|
||||
/* If someone is calling us before timer is initialized,
|
||||
* return the current tick
|
||||
*/
|
||||
now = (tick_now / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
return now;
|
||||
}
|
||||
|
||||
KS_DECLARE(void) ks_sleep(ks_time_t microsec)
|
||||
{
|
||||
|
||||
LARGE_INTEGER perfCnt, start, now;
|
||||
|
||||
QueryPerformanceFrequency(&perfCnt);
|
||||
QueryPerformanceCounter(&start);
|
||||
|
||||
do {
|
||||
QueryPerformanceCounter((LARGE_INTEGER*) &now);
|
||||
} while ((now.QuadPart - start.QuadPart) / (float)(perfCnt.QuadPart) * 1000 * 1000 < (DWORD)microsec);
|
||||
|
||||
}
|
||||
|
||||
#else //!WINDOWS, UNIX ETC
|
||||
KS_DECLARE(ks_time_t) ks_time_now(void)
|
||||
{
|
||||
ks_time_t now;
|
||||
|
||||
#if (defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME))
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
now = (int64_t)ts.tv_sec * 1000000 + ((int64_t)ts.tv_nsec / 1000);
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
now = tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
#endif
|
||||
|
||||
return now;
|
||||
}
|
||||
|
||||
KS_DECLARE(ks_time_t) ks_time_now_sec(void)
|
||||
{
|
||||
ks_time_t now;
|
||||
|
||||
#if (defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME))
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
now = (int64_t)ts.tv_sec;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
now = tv.tv_sec;
|
||||
#endif
|
||||
|
||||
return now;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(__APPLE__)
|
||||
static void generic_sleep(ks_time_t microsec)
|
||||
{
|
||||
#ifdef HAVE_USLEEP
|
||||
usleep(microsec);
|
||||
#else
|
||||
struct timeval tv;
|
||||
tv.tv_usec = ks_time_usec(microsec);
|
||||
tv.tv_sec = ks_time_sec(microsec);
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
KS_DECLARE(void) ks_sleep(ks_time_t microsec)
|
||||
{
|
||||
#if defined(HAVE_CLOCK_NANOSLEEP) || defined(__APPLE__)
|
||||
struct timespec ts;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_CLOCK_NANOSLEEP)
|
||||
ts.tv_sec = ks_time_sec(microsec);
|
||||
ts.tv_nsec = ks_time_nsec(microsec);
|
||||
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
|
||||
#elif defined(__APPLE__)
|
||||
ts.tv_sec = ks_time_sec(microsec);
|
||||
ts.tv_nsec = ks_time_usec(microsec) * 850;
|
||||
nanosleep(&ts, NULL);
|
||||
#else
|
||||
generic_sleep(microsec);
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
sched_yield();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_H__
|
||||
#define __UTP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "utp_types.h"
|
||||
|
||||
typedef struct UTPSocket utp_socket;
|
||||
typedef struct struct_utp_context utp_context;
|
||||
|
||||
enum {
|
||||
UTP_UDP_DONTFRAG = 2, // Used to be a #define as UDP_IP_DONTFRAG
|
||||
};
|
||||
|
||||
enum {
|
||||
// socket has reveived syn-ack (notification only for outgoing connection completion)
|
||||
// this implies writability
|
||||
UTP_STATE_CONNECT = 1,
|
||||
|
||||
// socket is able to send more data
|
||||
UTP_STATE_WRITABLE = 2,
|
||||
|
||||
// connection closed
|
||||
UTP_STATE_EOF = 3,
|
||||
|
||||
// socket is being destroyed, meaning all data has been sent if possible.
|
||||
// it is not valid to refer to the socket after this state change occurs
|
||||
UTP_STATE_DESTROYING = 4,
|
||||
};
|
||||
|
||||
extern const char *utp_state_names[];
|
||||
|
||||
// Errors codes that can be passed to UTP_ON_ERROR callback
|
||||
enum {
|
||||
UTP_ECONNREFUSED = 0,
|
||||
UTP_ECONNRESET,
|
||||
UTP_ETIMEDOUT,
|
||||
};
|
||||
|
||||
extern const char *utp_error_code_names[];
|
||||
|
||||
enum {
|
||||
// callback names
|
||||
UTP_ON_FIREWALL = 0,
|
||||
UTP_ON_ACCEPT,
|
||||
UTP_ON_CONNECT,
|
||||
UTP_ON_ERROR,
|
||||
UTP_ON_READ,
|
||||
UTP_ON_OVERHEAD_STATISTICS,
|
||||
UTP_ON_STATE_CHANGE,
|
||||
UTP_GET_READ_BUFFER_SIZE,
|
||||
UTP_ON_DELAY_SAMPLE,
|
||||
UTP_GET_UDP_MTU,
|
||||
UTP_GET_UDP_OVERHEAD,
|
||||
UTP_GET_MILLISECONDS,
|
||||
UTP_GET_MICROSECONDS,
|
||||
UTP_GET_RANDOM,
|
||||
UTP_LOG,
|
||||
UTP_SENDTO,
|
||||
|
||||
// context and socket options that may be set/queried
|
||||
UTP_LOG_NORMAL,
|
||||
UTP_LOG_MTU,
|
||||
UTP_LOG_DEBUG,
|
||||
UTP_SNDBUF,
|
||||
UTP_RCVBUF,
|
||||
UTP_TARGET_DELAY,
|
||||
|
||||
UTP_ARRAY_SIZE, // must be last
|
||||
};
|
||||
|
||||
extern const char *utp_callback_names[];
|
||||
|
||||
typedef struct {
|
||||
utp_context *context;
|
||||
utp_socket *socket;
|
||||
size_t len;
|
||||
uint32 flags;
|
||||
int callback_type;
|
||||
const byte *buf;
|
||||
|
||||
union {
|
||||
const struct sockaddr *address;
|
||||
int send;
|
||||
int sample_ms;
|
||||
int error_code;
|
||||
int state;
|
||||
};
|
||||
|
||||
union {
|
||||
socklen_t address_len;
|
||||
int type;
|
||||
};
|
||||
} utp_callback_arguments;
|
||||
|
||||
typedef uint64 utp_callback_t(utp_callback_arguments *);
|
||||
|
||||
// Returned by utp_get_context_stats()
|
||||
typedef struct {
|
||||
uint32 _nraw_recv[5]; // total packets recieved less than 300/600/1200/MTU bytes fpr all connections (context-wide)
|
||||
uint32 _nraw_send[5]; // total packets sent less than 300/600/1200/MTU bytes for all connections (context-wide)
|
||||
} utp_context_stats;
|
||||
|
||||
// Returned by utp_get_stats()
|
||||
typedef struct {
|
||||
uint64 nbytes_recv; // total bytes received
|
||||
uint64 nbytes_xmit; // total bytes transmitted
|
||||
uint32 rexmit; // retransmit counter
|
||||
uint32 fastrexmit; // fast retransmit counter
|
||||
uint32 nxmit; // transmit counter
|
||||
uint32 nrecv; // receive counter (total)
|
||||
uint32 nduprecv; // duplicate receive counter
|
||||
uint32 mtu_guess; // Best guess at MTU
|
||||
} utp_socket_stats;
|
||||
|
||||
#define UTP_IOV_MAX 1024
|
||||
|
||||
// For utp_writev, to writes data from multiple buffers
|
||||
struct utp_iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
// Public Functions
|
||||
utp_context* utp_init (int version);
|
||||
void utp_destroy (utp_context *ctx);
|
||||
void utp_set_callback (utp_context *ctx, int callback_name, utp_callback_t *proc);
|
||||
void* utp_context_set_userdata (utp_context *ctx, void *userdata);
|
||||
void* utp_context_get_userdata (utp_context *ctx);
|
||||
int utp_context_set_option (utp_context *ctx, int opt, int val);
|
||||
int utp_context_get_option (utp_context *ctx, int opt);
|
||||
int utp_process_udp (utp_context *ctx, const byte *buf, size_t len, const struct sockaddr *to, socklen_t tolen);
|
||||
int utp_process_icmp_error (utp_context *ctx, const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen);
|
||||
int utp_process_icmp_fragmentation (utp_context *ctx, const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen, uint16 next_hop_mtu);
|
||||
void utp_check_timeouts (utp_context *ctx);
|
||||
void utp_issue_deferred_acks (utp_context *ctx);
|
||||
utp_context_stats* utp_get_context_stats (utp_context *ctx);
|
||||
utp_socket* utp_create_socket (utp_context *ctx);
|
||||
void* utp_set_userdata (utp_socket *s, void *userdata);
|
||||
void* utp_get_userdata (utp_socket *s);
|
||||
int utp_setsockopt (utp_socket *s, int opt, int val);
|
||||
int utp_getsockopt (utp_socket *s, int opt);
|
||||
int utp_connect (utp_socket *s, const struct sockaddr *to, socklen_t tolen);
|
||||
ssize_t utp_write (utp_socket *s, void *buf, size_t count);
|
||||
ssize_t utp_writev (utp_socket *s, struct utp_iovec *iovec, size_t num_iovecs);
|
||||
int utp_getpeername (utp_socket *s, struct sockaddr *addr, socklen_t *addrlen);
|
||||
void utp_read_drained (utp_socket *s);
|
||||
int utp_get_delays (utp_socket *s, uint32 *ours, uint32 *theirs, uint32 *age);
|
||||
utp_socket_stats* utp_get_stats (utp_socket *s);
|
||||
utp_context* utp_get_context (utp_socket *s);
|
||||
void utp_close (utp_socket *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //__UTP_H__
|
|
@ -0,0 +1,139 @@
|
|||
// vim:set ts=4 sw=4 ai:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "utp_internal.h"
|
||||
#include "utp_utils.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
const char * utp_callback_names[] = {
|
||||
"UTP_ON_FIREWALL",
|
||||
"UTP_ON_ACCEPT",
|
||||
"UTP_ON_CONNECT",
|
||||
"UTP_ON_ERROR",
|
||||
"UTP_ON_READ",
|
||||
"UTP_ON_OVERHEAD_STATISTICS",
|
||||
"UTP_ON_STATE_CHANGE",
|
||||
"UTP_GET_READ_BUFFER_SIZE",
|
||||
"UTP_ON_DELAY_SAMPLE",
|
||||
"UTP_GET_UDP_MTU",
|
||||
"UTP_GET_UDP_OVERHEAD",
|
||||
"UTP_GET_MILLISECONDS",
|
||||
"UTP_GET_MICROSECONDS",
|
||||
"UTP_GET_RANDOM",
|
||||
"UTP_LOG",
|
||||
"UTP_SENDTO",
|
||||
};
|
||||
|
||||
const char * utp_error_code_names[] = {
|
||||
"UTP_ECONNREFUSED",
|
||||
"UTP_ECONNRESET",
|
||||
"UTP_ETIMEDOUT",
|
||||
};
|
||||
|
||||
const char *utp_state_names[] = {
|
||||
NULL,
|
||||
"UTP_STATE_CONNECT",
|
||||
"UTP_STATE_WRITABLE",
|
||||
"UTP_STATE_EOF",
|
||||
"UTP_STATE_DESTROYING",
|
||||
};
|
||||
|
||||
struct_utp_context::struct_utp_context()
|
||||
: userdata(NULL)
|
||||
, current_ms(0)
|
||||
, last_utp_socket(NULL)
|
||||
, log_normal(false)
|
||||
, log_mtu(false)
|
||||
, log_debug(false)
|
||||
{
|
||||
memset(&context_stats, 0, sizeof(context_stats));
|
||||
memset(callbacks, 0, sizeof(callbacks));
|
||||
target_delay = CCONTROL_TARGET;
|
||||
utp_sockets = new UTPSocketHT;
|
||||
|
||||
callbacks[UTP_GET_UDP_MTU] = &utp_default_get_udp_mtu;
|
||||
callbacks[UTP_GET_UDP_OVERHEAD] = &utp_default_get_udp_overhead;
|
||||
callbacks[UTP_GET_MILLISECONDS] = &utp_default_get_milliseconds;
|
||||
callbacks[UTP_GET_MICROSECONDS] = &utp_default_get_microseconds;
|
||||
callbacks[UTP_GET_RANDOM] = &utp_default_get_random;
|
||||
|
||||
// 1 MB of receive buffer (i.e. max bandwidth delay product)
|
||||
// means that from a peer with 200 ms RTT, we cannot receive
|
||||
// faster than 5 MB/s
|
||||
// from a peer with 10 ms RTT, we cannot receive faster than
|
||||
// 100 MB/s. This is assumed to be good enough, since bandwidth
|
||||
// often is proportional to RTT anyway
|
||||
// when setting a download rate limit, all sockets should have
|
||||
// their receive buffer set much lower, to say 60 kiB or so
|
||||
opt_rcvbuf = opt_sndbuf = 1024 * 1024;
|
||||
last_check = 0;
|
||||
}
|
||||
|
||||
struct_utp_context::~struct_utp_context() {
|
||||
delete this->utp_sockets;
|
||||
}
|
||||
|
||||
utp_context* utp_init (int version)
|
||||
{
|
||||
assert(version == 2);
|
||||
if (version != 2)
|
||||
return NULL;
|
||||
utp_context *ctx = new utp_context;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void utp_destroy(utp_context *ctx) {
|
||||
assert(ctx);
|
||||
if (ctx) delete ctx;
|
||||
}
|
||||
|
||||
void utp_set_callback(utp_context *ctx, int callback_name, utp_callback_t *proc) {
|
||||
assert(ctx);
|
||||
if (ctx) ctx->callbacks[callback_name] = proc;
|
||||
}
|
||||
|
||||
void* utp_context_set_userdata(utp_context *ctx, void *userdata) {
|
||||
assert(ctx);
|
||||
if (ctx) ctx->userdata = userdata;
|
||||
return ctx ? ctx->userdata : NULL;
|
||||
}
|
||||
|
||||
void* utp_context_get_userdata(utp_context *ctx) {
|
||||
assert(ctx);
|
||||
return ctx ? ctx->userdata : NULL;
|
||||
}
|
||||
|
||||
utp_context_stats* utp_get_context_stats(utp_context *ctx) {
|
||||
assert(ctx);
|
||||
return ctx ? &ctx->context_stats : NULL;
|
||||
}
|
||||
|
||||
ssize_t utp_write(utp_socket *socket, void *buf, size_t len) {
|
||||
struct utp_iovec iovec = { buf, len };
|
||||
return utp_writev(socket, &iovec, 1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
// vim:set ts=4 sw=4 ai:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "utp_callbacks.h"
|
||||
|
||||
int utp_call_on_firewall(utp_context *ctx, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_FIREWALL]) return 0;
|
||||
args.callback_type = UTP_ON_FIREWALL;
|
||||
args.context = ctx;
|
||||
args.socket = NULL;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
return (int)ctx->callbacks[UTP_ON_FIREWALL](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_accept(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_ACCEPT]) return;
|
||||
args.callback_type = UTP_ON_ACCEPT;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
ctx->callbacks[UTP_ON_ACCEPT](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_connect(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_CONNECT]) return;
|
||||
args.callback_type = UTP_ON_CONNECT;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
ctx->callbacks[UTP_ON_CONNECT](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_error(utp_context *ctx, utp_socket *socket, int error_code)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_ERROR]) return;
|
||||
args.callback_type = UTP_ON_ERROR;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.error_code = error_code;
|
||||
ctx->callbacks[UTP_ON_ERROR](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_read(utp_context *ctx, utp_socket *socket, const byte *buf, size_t len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_READ]) return;
|
||||
args.callback_type = UTP_ON_READ;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.buf = buf;
|
||||
args.len = len;
|
||||
ctx->callbacks[UTP_ON_READ](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_overhead_statistics(utp_context *ctx, utp_socket *socket, int send, size_t len, int type)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_OVERHEAD_STATISTICS]) return;
|
||||
args.callback_type = UTP_ON_OVERHEAD_STATISTICS;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.send = send;
|
||||
args.len = len;
|
||||
args.type = type;
|
||||
ctx->callbacks[UTP_ON_OVERHEAD_STATISTICS](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_delay_sample(utp_context *ctx, utp_socket *socket, int sample_ms)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_DELAY_SAMPLE]) return;
|
||||
args.callback_type = UTP_ON_DELAY_SAMPLE;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.sample_ms = sample_ms;
|
||||
ctx->callbacks[UTP_ON_DELAY_SAMPLE](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_state_change(utp_context *ctx, utp_socket *socket, int state)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_STATE_CHANGE]) return;
|
||||
args.callback_type = UTP_ON_STATE_CHANGE;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.state = state;
|
||||
ctx->callbacks[UTP_ON_STATE_CHANGE](&args);
|
||||
}
|
||||
|
||||
uint16 utp_call_get_udp_mtu(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_UDP_MTU]) return 0;
|
||||
args.callback_type = UTP_GET_UDP_MTU;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
return (uint16)ctx->callbacks[UTP_GET_UDP_MTU](&args);
|
||||
}
|
||||
|
||||
uint16 utp_call_get_udp_overhead(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_UDP_OVERHEAD]) return 0;
|
||||
args.callback_type = UTP_GET_UDP_OVERHEAD;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
return (uint16)ctx->callbacks[UTP_GET_UDP_OVERHEAD](&args);
|
||||
}
|
||||
|
||||
uint64 utp_call_get_milliseconds(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_MILLISECONDS]) return 0;
|
||||
args.callback_type = UTP_GET_MILLISECONDS;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return ctx->callbacks[UTP_GET_MILLISECONDS](&args);
|
||||
}
|
||||
|
||||
uint64 utp_call_get_microseconds(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_MICROSECONDS]) return 0;
|
||||
args.callback_type = UTP_GET_MICROSECONDS;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return ctx->callbacks[UTP_GET_MICROSECONDS](&args);
|
||||
}
|
||||
|
||||
uint32 utp_call_get_random(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_RANDOM]) return 0;
|
||||
args.callback_type = UTP_GET_RANDOM;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return (uint32)ctx->callbacks[UTP_GET_RANDOM](&args);
|
||||
}
|
||||
|
||||
size_t utp_call_get_read_buffer_size(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_READ_BUFFER_SIZE]) return 0;
|
||||
args.callback_type = UTP_GET_READ_BUFFER_SIZE;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return (size_t)ctx->callbacks[UTP_GET_READ_BUFFER_SIZE](&args);
|
||||
}
|
||||
|
||||
void utp_call_log(utp_context *ctx, utp_socket *socket, const byte *buf)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_LOG]) return;
|
||||
args.callback_type = UTP_LOG;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.buf = buf;
|
||||
ctx->callbacks[UTP_LOG](&args);
|
||||
}
|
||||
|
||||
void utp_call_sendto(utp_context *ctx, utp_socket *socket, const byte *buf, size_t len, const struct sockaddr *address, socklen_t address_len, uint32 flags)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_SENDTO]) return;
|
||||
args.callback_type = UTP_SENDTO;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.buf = buf;
|
||||
args.len = len;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
args.flags = flags;
|
||||
ctx->callbacks[UTP_SENDTO](&args);
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_CALLBACKS_H__
|
||||
#define __UTP_CALLBACKS_H__
|
||||
|
||||
#include "utp.h"
|
||||
#include "utp_internal.h"
|
||||
|
||||
// Generated by running: grep ^[a-z] utp_callbacks.cpp | sed 's/$/;/'
|
||||
int utp_call_on_firewall(utp_context *ctx, const struct sockaddr *address, socklen_t address_len);
|
||||
void utp_call_on_accept(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
|
||||
void utp_call_on_connect(utp_context *ctx, utp_socket *s);
|
||||
void utp_call_on_error(utp_context *ctx, utp_socket *s, int error_code);
|
||||
void utp_call_on_read(utp_context *ctx, utp_socket *s, const byte *buf, size_t len);
|
||||
void utp_call_on_overhead_statistics(utp_context *ctx, utp_socket *s, int send, size_t len, int type);
|
||||
void utp_call_on_delay_sample(utp_context *ctx, utp_socket *s, int sample_ms);
|
||||
void utp_call_on_state_change(utp_context *ctx, utp_socket *s, int state);
|
||||
uint16 utp_call_get_udp_mtu(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
|
||||
uint16 utp_call_get_udp_overhead(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
|
||||
uint64 utp_call_get_milliseconds(utp_context *ctx, utp_socket *s);
|
||||
uint64 utp_call_get_microseconds(utp_context *ctx, utp_socket *s);
|
||||
uint32 utp_call_get_random(utp_context *ctx, utp_socket *s);
|
||||
size_t utp_call_get_read_buffer_size(utp_context *ctx, utp_socket *s);
|
||||
void utp_call_log(utp_context *ctx, utp_socket *s, const byte *buf);
|
||||
void utp_call_sendto(utp_context *ctx, utp_socket *s, const byte *buf, size_t len, const struct sockaddr *address, socklen_t address_len, uint32 flags);
|
||||
|
||||
#endif // __UTP_CALLBACKS_H__
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "utp_hash.h"
|
||||
#include "utp_types.h"
|
||||
|
||||
#define LIBUTP_HASH_UNUSED ((utp_link_t)-1)
|
||||
|
||||
#ifdef STRICT_ALIGN
|
||||
inline uint32 Read32(const void *p)
|
||||
{
|
||||
uint32 tmp;
|
||||
memcpy(&tmp, p, sizeof tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#else
|
||||
inline uint32 Read32(const void *p) { return *(uint32*)p; }
|
||||
#endif
|
||||
|
||||
|
||||
// Get the amount of memory required for the hash parameters and the bucket set
|
||||
// Waste a space for an unused bucket in order to ensure the following managed memory have 32-bit aligned addresses
|
||||
// TODO: make this 64-bit clean
|
||||
#define BASE_SIZE(bc) (sizeof(utp_hash_t) + sizeof(utp_link_t) * ((bc) + 1))
|
||||
|
||||
// Get a pointer to the base of the structure array managed by the hash table
|
||||
#define get_bep(h) ((byte*)(h)) + BASE_SIZE((h)->N)
|
||||
|
||||
// Get the address of the information associated with a specific structure in the array,
|
||||
// given the address of the base of the structure.
|
||||
// This assumes a utp_link_t link member is at the end of the structure.
|
||||
// Given compilers filling out the memory to a 32-bit clean value, this may mean that
|
||||
// the location named in the structure may not be the location actually used by the hash table,
|
||||
// since the compiler may have padded the end of the structure with 2 bytes after the utp_link_t member.
|
||||
// TODO: this macro should not require that the variable pointing at the hash table be named 'hash'
|
||||
#define ptr_to_link(p) (utp_link_t *) (((byte *) (p)) + hash->E - sizeof(utp_link_t))
|
||||
|
||||
// Calculate how much to allocate for a hash table with bucket count, total size, and structure count
|
||||
// TODO: make this 64-bit clean
|
||||
#define ALLOCATION_SIZE(bc, ts, sc) (BASE_SIZE((bc)) + (ts) * (sc))
|
||||
|
||||
utp_hash_t *utp_hash_create(int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun, utp_hash_equal_t compfun)
|
||||
{
|
||||
// Must have odd number of hash buckets (prime number is best)
|
||||
assert(N % 2);
|
||||
// Ensure structures will be at aligned memory addresses
|
||||
// TODO: make this 64-bit clean
|
||||
assert(0 == (total_size % 4));
|
||||
|
||||
int size = ALLOCATION_SIZE(N, total_size, initial);
|
||||
utp_hash_t *hash = (utp_hash_t *) malloc( size );
|
||||
memset( hash, 0, size );
|
||||
|
||||
for (int i = 0; i < N + 1; ++i)
|
||||
hash->inits[i] = LIBUTP_HASH_UNUSED;
|
||||
hash->N = N;
|
||||
hash->K = key_size;
|
||||
hash->E = total_size;
|
||||
hash->hash_compute = hashfun;
|
||||
hash->hash_equal = compfun;
|
||||
hash->allocated = initial;
|
||||
hash->count = 0;
|
||||
hash->used = 0;
|
||||
hash->free = LIBUTP_HASH_UNUSED;
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint utp_hash_mem(const void *keyp, size_t keysize)
|
||||
{
|
||||
uint hash = 0;
|
||||
uint n = keysize;
|
||||
while (n >= 4) {
|
||||
hash ^= Read32(keyp);
|
||||
keyp = (byte*)keyp + sizeof(uint32);
|
||||
hash = (hash << 13) | (hash >> 19);
|
||||
n -= 4;
|
||||
}
|
||||
while (n != 0) {
|
||||
hash ^= *(byte*)keyp;
|
||||
keyp = (byte*)keyp + sizeof(byte);
|
||||
hash = (hash << 8) | (hash >> 24);
|
||||
n--;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint utp_hash_mkidx(utp_hash_t *hash, const void *keyp)
|
||||
{
|
||||
// Generate a key from the hash
|
||||
return hash->hash_compute(keyp, hash->K) % hash->N;
|
||||
}
|
||||
|
||||
static inline bool compare(byte *a, byte *b,int n)
|
||||
{
|
||||
assert(n >= 4);
|
||||
if (Read32(a) != Read32(b)) return false;
|
||||
return memcmp(a+4, b+4, n-4) == 0;
|
||||
}
|
||||
|
||||
#define COMPARE(h,k1,k2,ks) (((h)->hash_equal) ? (h)->hash_equal((void*)k1,(void*)k2,ks) : compare(k1,k2,ks))
|
||||
|
||||
// Look-up a key in the hash table.
|
||||
// Returns NULL if not found
|
||||
void *utp_hash_lookup(utp_hash_t *hash, const void *key)
|
||||
{
|
||||
utp_link_t idx = utp_hash_mkidx(hash, key);
|
||||
|
||||
// base pointer
|
||||
byte *bep = get_bep(hash);
|
||||
|
||||
utp_link_t cur = hash->inits[idx];
|
||||
while (cur != LIBUTP_HASH_UNUSED) {
|
||||
byte *key2 = bep + (cur * hash->E);
|
||||
if (COMPARE(hash, (byte*)key, key2, hash->K))
|
||||
return key2;
|
||||
cur = *ptr_to_link(key2);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add a new element to the hash table.
|
||||
// Returns a pointer to the new element.
|
||||
// This assumes the element is not already present!
|
||||
void *utp_hash_add(utp_hash_t **hashp, const void *key)
|
||||
{
|
||||
//Allocate a new entry
|
||||
byte *elemp;
|
||||
utp_link_t elem;
|
||||
utp_hash_t *hash = *hashp;
|
||||
utp_link_t idx = utp_hash_mkidx(hash, key);
|
||||
|
||||
if ((elem=hash->free) == LIBUTP_HASH_UNUSED) {
|
||||
utp_link_t all = hash->allocated;
|
||||
if (hash->used == all) {
|
||||
utp_hash_t *nhash;
|
||||
if (all <= (LIBUTP_HASH_UNUSED/2)) {
|
||||
all *= 2;
|
||||
} else if (all != LIBUTP_HASH_UNUSED) {
|
||||
all = LIBUTP_HASH_UNUSED;
|
||||
} else {
|
||||
// too many items! can't grow!
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
// otherwise need to allocate.
|
||||
nhash = (utp_hash_t*)realloc(hash, ALLOCATION_SIZE(hash->N, hash->E, all));
|
||||
if (!nhash) {
|
||||
// out of memory (or too big to allocate)
|
||||
assert(nhash);
|
||||
return NULL;
|
||||
}
|
||||
hash = *hashp = nhash;
|
||||
hash->allocated = all;
|
||||
}
|
||||
|
||||
elem = hash->used++;
|
||||
elemp = get_bep(hash) + elem * hash->E;
|
||||
} else {
|
||||
elemp = get_bep(hash) + elem * hash->E;
|
||||
hash->free = *ptr_to_link(elemp);
|
||||
}
|
||||
|
||||
*ptr_to_link(elemp) = hash->inits[idx];
|
||||
hash->inits[idx] = elem;
|
||||
hash->count++;
|
||||
|
||||
// copy key into it
|
||||
memcpy(elemp, key, hash->K);
|
||||
return elemp;
|
||||
}
|
||||
|
||||
// Delete an element from the utp_hash_t
|
||||
// Returns a pointer to the already deleted element.
|
||||
void *utp_hash_del(utp_hash_t *hash, const void *key)
|
||||
{
|
||||
utp_link_t idx = utp_hash_mkidx(hash, key);
|
||||
|
||||
// base pointer
|
||||
byte *bep = get_bep(hash);
|
||||
|
||||
utp_link_t *curp = &hash->inits[idx];
|
||||
utp_link_t cur;
|
||||
while ((cur=*curp) != LIBUTP_HASH_UNUSED) {
|
||||
byte *key2 = bep + (cur * hash->E);
|
||||
if (COMPARE(hash,(byte*)key,(byte*)key2, hash->K )) {
|
||||
// found an item that matched. unlink it
|
||||
*curp = *ptr_to_link(key2);
|
||||
// Insert into freelist
|
||||
*ptr_to_link(key2) = hash->free;
|
||||
hash->free = cur;
|
||||
hash->count--;
|
||||
return key2;
|
||||
}
|
||||
curp = ptr_to_link(key2);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *utp_hash_iterate(utp_hash_t *hash, utp_hash_iterator_t *iter)
|
||||
{
|
||||
utp_link_t elem;
|
||||
|
||||
if ((elem=iter->elem) == LIBUTP_HASH_UNUSED) {
|
||||
// Find a bucket with an element
|
||||
utp_link_t buck = iter->bucket + 1;
|
||||
for(;;) {
|
||||
if (buck >= hash->N)
|
||||
return NULL;
|
||||
if ((elem = hash->inits[buck]) != LIBUTP_HASH_UNUSED)
|
||||
break;
|
||||
buck++;
|
||||
}
|
||||
iter->bucket = buck;
|
||||
}
|
||||
|
||||
byte *elemp = get_bep(hash) + (elem * hash->E);
|
||||
iter->elem = *ptr_to_link(elemp);
|
||||
return elemp;
|
||||
}
|
||||
|
||||
void utp_hash_free_mem(utp_hash_t* hash)
|
||||
{
|
||||
free(hash);
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_HASH_H__
|
||||
#define __UTP_HASH_H__
|
||||
|
||||
#include <string.h> // memset
|
||||
#include <stdlib.h> // malloc
|
||||
|
||||
#include "utp_types.h"
|
||||
#include "utp_templates.h"
|
||||
|
||||
// TODO: make utp_link_t a template parameter to HashTable
|
||||
typedef uint32 utp_link_t;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Silence the warning about the C99-compliant zero-length array at the end of the structure
|
||||
#pragma warning (disable: 4200)
|
||||
#endif
|
||||
|
||||
typedef uint32 (*utp_hash_compute_t)(const void *keyp, size_t keysize);
|
||||
typedef uint (*utp_hash_equal_t)(const void *key_a, const void *key_b, size_t keysize);
|
||||
|
||||
// In memory the HashTable is laid out as follows:
|
||||
// ---------------------------- low
|
||||
// | hash table data members |
|
||||
// ---------------------------- _
|
||||
// | indices | ^
|
||||
// | . | | utp_link_t indices into the key-values.
|
||||
// | . | .
|
||||
// ---------------------------- - <----- bep
|
||||
// | keys and values | each key-value pair has size total_size
|
||||
// | . |
|
||||
// | . |
|
||||
// ---------------------------- high
|
||||
//
|
||||
// The code depends on the ability of the compiler to pad the length
|
||||
// of the hash table data members structure to
|
||||
// a length divisible by 32-bits with no remainder.
|
||||
//
|
||||
// Since the number of hash buckets (indices) should be odd, the code
|
||||
// asserts this and adds one to the hash bucket count to ensure that the
|
||||
// following key-value pairs array starts on a 32-bit boundary.
|
||||
//
|
||||
// The key-value pairs array should start on a 32-bit boundary, otherwise
|
||||
// processors like the ARM will silently mangle 32-bit data in these structures
|
||||
// (e.g., turning 0xABCD into 0XCDAB when moving a value from memory to register
|
||||
// when the memory address is 16 bits offset from a 32-bit boundary),
|
||||
// also, the value will be stored at an address two bytes lower than the address
|
||||
// value would ordinarily indicate.
|
||||
//
|
||||
// The key-value pair is of type T. The first field in T must
|
||||
// be the key, i.e., the first K bytes of T contains the key.
|
||||
// total_size = sizeof(T) and thus sizeof(T) >= sizeof(K)
|
||||
//
|
||||
// N is the number of buckets.
|
||||
//
|
||||
struct utp_hash_t {
|
||||
utp_link_t N;
|
||||
byte K;
|
||||
byte E;
|
||||
size_t count;
|
||||
utp_hash_compute_t hash_compute;
|
||||
utp_hash_equal_t hash_equal;
|
||||
utp_link_t allocated;
|
||||
utp_link_t used;
|
||||
utp_link_t free;
|
||||
utp_link_t inits[0];
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (default: 4200)
|
||||
#endif
|
||||
|
||||
struct utp_hash_iterator_t {
|
||||
utp_link_t bucket;
|
||||
utp_link_t elem;
|
||||
|
||||
utp_hash_iterator_t() : bucket(0xffffffff), elem(0xffffffff) {}
|
||||
};
|
||||
|
||||
uint utp_hash_mem(const void *keyp, size_t keysize);
|
||||
uint utp_hash_comp(const void *key_a, const void *key_b, size_t keysize);
|
||||
|
||||
utp_hash_t *utp_hash_create(int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun = utp_hash_mem, utp_hash_equal_t eqfun = NULL);
|
||||
void *utp_hash_lookup(utp_hash_t *hash, const void *key);
|
||||
void *utp_hash_add(utp_hash_t **hashp, const void *key);
|
||||
void *utp_hash_del(utp_hash_t *hash, const void *key);
|
||||
|
||||
void *utp_hash_iterate(utp_hash_t *hash, utp_hash_iterator_t *iter);
|
||||
void utp_hash_free_mem(utp_hash_t *hash);
|
||||
|
||||
/*
|
||||
This HashTable requires that T have at least sizeof(K)+sizeof(utp_link_t) bytes.
|
||||
Usually done like this:
|
||||
|
||||
struct K {
|
||||
int whatever;
|
||||
};
|
||||
|
||||
struct T {
|
||||
K wtf;
|
||||
utp_link_t link; // also wtf
|
||||
};
|
||||
*/
|
||||
|
||||
template<typename K, typename T> class utpHashTable {
|
||||
utp_hash_t *hash;
|
||||
public:
|
||||
static uint compare(const void *k1, const void *k2, size_t ks) {
|
||||
return *((K*)k1) == *((K*)k2);
|
||||
}
|
||||
static uint32 compute_hash(const void *k, size_t ks) {
|
||||
return ((K*)k)->compute_hash();
|
||||
}
|
||||
void Init() { hash = NULL; }
|
||||
bool Allocated() { return (hash != NULL); }
|
||||
void Free() { utp_hash_free_mem(hash); hash = NULL; }
|
||||
void Create(int N, int initial) { hash = utp_hash_create(N, sizeof(K), sizeof(T), initial, &compute_hash, &compare); }
|
||||
T *Lookup(const K &key) { return (T*)utp_hash_lookup(hash, &key); }
|
||||
T *Add(const K &key) { return (T*)utp_hash_add(&hash, &key); }
|
||||
T *Delete(const K &key) { return (T*)utp_hash_del(hash, &key); }
|
||||
T *Iterate(utp_hash_iterator_t &iterator) { return (T*)utp_hash_iterate(hash, &iterator); }
|
||||
size_t GetCount() { return hash->count; }
|
||||
};
|
||||
|
||||
#endif //__UTP_HASH_H__
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_INTERNAL_H__
|
||||
#define __UTP_INTERNAL_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utp.h"
|
||||
#include "utp_callbacks.h"
|
||||
#include "utp_templates.h"
|
||||
#include "utp_hash.h"
|
||||
#include "utp_hash.h"
|
||||
#include "utp_packedsockaddr.h"
|
||||
|
||||
/* These originally lived in utp_config.h */
|
||||
#define CCONTROL_TARGET (100 * 1000) // us
|
||||
|
||||
enum bandwidth_type_t {
|
||||
payload_bandwidth, connect_overhead,
|
||||
close_overhead, ack_overhead,
|
||||
header_overhead, retransmit_overhead
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _MSC_VER
|
||||
#include "libutp_inet_ntop.h"
|
||||
#endif
|
||||
|
||||
// newer versions of MSVC define these in errno.h
|
||||
#ifndef ECONNRESET
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct PACKED_ATTRIBUTE RST_Info {
|
||||
PackedSockAddr addr;
|
||||
uint32 connid;
|
||||
uint16 ack_nr;
|
||||
uint64 timestamp;
|
||||
};
|
||||
|
||||
// It's really important that we don't have duplicate keys in the hash table.
|
||||
// If we do, we'll eventually crash. if we try to remove the second instance
|
||||
// of the key, we'll accidentally remove the first instead. then later,
|
||||
// checkTimeouts will try to access the second one's already freed memory.
|
||||
void UTP_FreeAll(struct UTPSocketHT *utp_sockets);
|
||||
|
||||
struct UTPSocketKey {
|
||||
PackedSockAddr addr;
|
||||
uint32 recv_id; // "conn_seed", "conn_id"
|
||||
|
||||
UTPSocketKey(const PackedSockAddr& _addr, uint32 _recv_id) {
|
||||
memset(this, 0, sizeof(*this));
|
||||
addr = _addr;
|
||||
recv_id = _recv_id;
|
||||
}
|
||||
|
||||
bool operator == (const UTPSocketKey &other) const {
|
||||
return recv_id == other.recv_id && addr == other.addr;
|
||||
}
|
||||
|
||||
uint32 compute_hash() const {
|
||||
return recv_id ^ addr.compute_hash();
|
||||
}
|
||||
};
|
||||
|
||||
struct UTPSocketKeyData {
|
||||
UTPSocketKey key;
|
||||
UTPSocket *socket;
|
||||
utp_link_t link;
|
||||
};
|
||||
|
||||
#define UTP_SOCKET_BUCKETS 79
|
||||
#define UTP_SOCKET_INIT 15
|
||||
|
||||
struct UTPSocketHT : utpHashTable<UTPSocketKey, UTPSocketKeyData> {
|
||||
UTPSocketHT() {
|
||||
const int buckets = UTP_SOCKET_BUCKETS;
|
||||
const int initial = UTP_SOCKET_INIT;
|
||||
this->Create(buckets, initial);
|
||||
}
|
||||
~UTPSocketHT() {
|
||||
UTP_FreeAll(this);
|
||||
this->Free();
|
||||
}
|
||||
};
|
||||
|
||||
struct struct_utp_context {
|
||||
void *userdata;
|
||||
utp_callback_t* callbacks[UTP_ARRAY_SIZE];
|
||||
|
||||
uint64 current_ms;
|
||||
utp_context_stats context_stats;
|
||||
UTPSocket *last_utp_socket;
|
||||
Array<UTPSocket*> ack_sockets;
|
||||
Array<RST_Info> rst_info;
|
||||
UTPSocketHT *utp_sockets;
|
||||
size_t target_delay;
|
||||
size_t opt_sndbuf;
|
||||
size_t opt_rcvbuf;
|
||||
uint64 last_check;
|
||||
|
||||
struct_utp_context();
|
||||
~struct_utp_context();
|
||||
|
||||
void log(int level, utp_socket *socket, char const *fmt, ...);
|
||||
|
||||
bool log_normal:1; // log normal events?
|
||||
bool log_mtu:1; // log MTU related events?
|
||||
bool log_debug:1; // log debugging events? (Must also compile with UTP_DEBUG_LOGGING defined)
|
||||
};
|
||||
|
||||
#endif //__UTP_INTERNAL_H__
|
|
@ -0,0 +1,139 @@
|
|||
// vim:set ts=4 sw=4 ai:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utp_types.h"
|
||||
#include "utp_hash.h"
|
||||
#include "utp_packedsockaddr.h"
|
||||
|
||||
//#include "libutp_inet_ntop.h"
|
||||
|
||||
byte PackedSockAddr::get_family() const
|
||||
{
|
||||
#if defined(__sh__)
|
||||
return ((_sin6d[0] == 0) && (_sin6d[1] == 0) && (_sin6d[2] == htonl(0xffff)) != 0) ?
|
||||
AF_INET : AF_INET6;
|
||||
#else
|
||||
return (IN6_IS_ADDR_V4MAPPED(&_in._in6addr) != 0) ? AF_INET : AF_INET6;
|
||||
#endif // defined(__sh__)
|
||||
}
|
||||
|
||||
bool PackedSockAddr::operator==(const PackedSockAddr& rhs) const
|
||||
{
|
||||
if (&rhs == this)
|
||||
return true;
|
||||
if (_port != rhs._port)
|
||||
return false;
|
||||
return memcmp(_sin6, rhs._sin6, sizeof(_sin6)) == 0;
|
||||
}
|
||||
|
||||
bool PackedSockAddr::operator!=(const PackedSockAddr& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
uint32 PackedSockAddr::compute_hash() const {
|
||||
return utp_hash_mem(&_in, sizeof(_in)) ^ _port;
|
||||
}
|
||||
|
||||
void PackedSockAddr::set(const SOCKADDR_STORAGE* sa, socklen_t len)
|
||||
{
|
||||
if (sa->ss_family == AF_INET) {
|
||||
assert(len >= sizeof(sockaddr_in));
|
||||
const sockaddr_in *sin = (sockaddr_in*)sa;
|
||||
_sin6w[0] = 0;
|
||||
_sin6w[1] = 0;
|
||||
_sin6w[2] = 0;
|
||||
_sin6w[3] = 0;
|
||||
_sin6w[4] = 0;
|
||||
_sin6w[5] = 0xffff;
|
||||
_sin4 = sin->sin_addr.s_addr;
|
||||
_port = ntohs(sin->sin_port);
|
||||
} else {
|
||||
assert(len >= sizeof(sockaddr_in6));
|
||||
const sockaddr_in6 *sin6 = (sockaddr_in6*)sa;
|
||||
_in._in6addr = sin6->sin6_addr;
|
||||
_port = ntohs(sin6->sin6_port);
|
||||
}
|
||||
}
|
||||
|
||||
PackedSockAddr::PackedSockAddr(const SOCKADDR_STORAGE* sa, socklen_t len)
|
||||
{
|
||||
set(sa, len);
|
||||
}
|
||||
|
||||
PackedSockAddr::PackedSockAddr(void)
|
||||
{
|
||||
SOCKADDR_STORAGE sa;
|
||||
socklen_t len = sizeof(SOCKADDR_STORAGE);
|
||||
memset(&sa, 0, len);
|
||||
sa.ss_family = AF_INET;
|
||||
set(&sa, len);
|
||||
}
|
||||
|
||||
SOCKADDR_STORAGE PackedSockAddr::get_sockaddr_storage(socklen_t *len = NULL) const
|
||||
{
|
||||
SOCKADDR_STORAGE sa;
|
||||
const byte family = get_family();
|
||||
if (family == AF_INET) {
|
||||
sockaddr_in *sin = (sockaddr_in*)&sa;
|
||||
if (len) *len = sizeof(sockaddr_in);
|
||||
memset(sin, 0, sizeof(sockaddr_in));
|
||||
sin->sin_family = family;
|
||||
sin->sin_port = htons(_port);
|
||||
sin->sin_addr.s_addr = _sin4;
|
||||
} else {
|
||||
sockaddr_in6 *sin6 = (sockaddr_in6*)&sa;
|
||||
memset(sin6, 0, sizeof(sockaddr_in6));
|
||||
if (len) *len = sizeof(sockaddr_in6);
|
||||
sin6->sin6_family = family;
|
||||
sin6->sin6_addr = _in._in6addr;
|
||||
sin6->sin6_port = htons(_port);
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
|
||||
// #define addrfmt(x, s) x.fmt(s, sizeof(s))
|
||||
cstr PackedSockAddr::fmt(str s, size_t len) const
|
||||
{
|
||||
memset(s, 0, len);
|
||||
const byte family = get_family();
|
||||
str i;
|
||||
if (family == AF_INET) {
|
||||
inet_ntop(family, (uint32*)&_sin4, s, len);
|
||||
i = s;
|
||||
while (*++i) {}
|
||||
} else {
|
||||
i = s;
|
||||
*i++ = '[';
|
||||
inet_ntop(family, (in6_addr*)&_in._in6addr, i, len-1);
|
||||
while (*++i) {}
|
||||
*i++ = ']';
|
||||
}
|
||||
snprintf(i, len - (i-s), ":%u", _port);
|
||||
return s;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_PACKEDSOCKADDR_H__
|
||||
#define __UTP_PACKEDSOCKADDR_H__
|
||||
|
||||
#include "utp_types.h"
|
||||
|
||||
struct PACKED_ATTRIBUTE PackedSockAddr {
|
||||
// The values are always stored here in network byte order
|
||||
union {
|
||||
byte _in6[16]; // IPv6
|
||||
uint16 _in6w[8]; // IPv6, word based (for convenience)
|
||||
uint32 _in6d[4]; // Dword access
|
||||
in6_addr _in6addr; // For convenience
|
||||
} _in;
|
||||
|
||||
// Host byte order
|
||||
uint16 _port;
|
||||
|
||||
#define _sin4 _in._in6d[3] // IPv4 is stored where it goes if mapped
|
||||
|
||||
#define _sin6 _in._in6
|
||||
#define _sin6w _in._in6w
|
||||
#define _sin6d _in._in6d
|
||||
|
||||
byte get_family() const;
|
||||
bool operator==(const PackedSockAddr& rhs) const;
|
||||
bool operator!=(const PackedSockAddr& rhs) const;
|
||||
void set(const SOCKADDR_STORAGE* sa, socklen_t len);
|
||||
|
||||
PackedSockAddr(const SOCKADDR_STORAGE* sa, socklen_t len);
|
||||
PackedSockAddr(void);
|
||||
|
||||
SOCKADDR_STORAGE get_sockaddr_storage(socklen_t *len) const;
|
||||
cstr fmt(str s, size_t len) const;
|
||||
|
||||
uint32 compute_hash() const;
|
||||
} ALIGNED_ATTRIBUTE(4);
|
||||
|
||||
#endif //__UTP_PACKEDSOCKADDR_H__
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __TEMPLATES_H__
|
||||
#define __TEMPLATES_H__
|
||||
|
||||
#include "utp_types.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(POSIX)
|
||||
/* Allow over-writing FORCEINLINE from makefile because gcc 3.4.4 for buffalo
|
||||
doesn't seem to support __attribute__((always_inline)) in -O0 build
|
||||
(strangely, it works in -Os build) */
|
||||
#ifndef FORCEINLINE
|
||||
// The always_inline attribute asks gcc to inline the function even if no optimization is being requested.
|
||||
// This macro should be used exclusive-or with the inline directive (use one or the other but not both)
|
||||
// since Microsoft uses __forceinline to also mean inline,
|
||||
// and this code is following a Microsoft compatibility model.
|
||||
// Just setting the attribute without also specifying the inline directive apparently won't inline the function,
|
||||
// as evidenced by multiply-defined symbols found at link time.
|
||||
#define FORCEINLINE inline __attribute__((always_inline))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Utility templates
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
template <typename T> static inline T min(T a, T b) { if (a < b) return a; return b; }
|
||||
template <typename T> static inline T max(T a, T b) { if (a > b) return a; return b; }
|
||||
|
||||
template <typename T> static inline T min(T a, T b, T c) { return min(min(a,b),c); }
|
||||
template <typename T> static inline T max(T a, T b, T c) { return max(max(a,b),c); }
|
||||
template <typename T> static inline T clamp(T v, T mi, T ma)
|
||||
{
|
||||
if (v > ma) v = ma;
|
||||
if (v < mi) v = mi;
|
||||
return v;
|
||||
}
|
||||
|
||||
#if (defined(__SVR4) && defined(__sun))
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push,1)
|
||||
#endif
|
||||
|
||||
|
||||
namespace aux
|
||||
{
|
||||
FORCEINLINE uint16 host_to_network(uint16 i) { return htons(i); }
|
||||
FORCEINLINE uint32 host_to_network(uint32 i) { return htonl(i); }
|
||||
FORCEINLINE int32 host_to_network(int32 i) { return htonl(i); }
|
||||
FORCEINLINE uint16 network_to_host(uint16 i) { return ntohs(i); }
|
||||
FORCEINLINE uint32 network_to_host(uint32 i) { return ntohl(i); }
|
||||
FORCEINLINE int32 network_to_host(int32 i) { return ntohl(i); }
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct PACKED_ATTRIBUTE big_endian
|
||||
{
|
||||
T operator=(T i) { m_integer = aux::host_to_network(i); return i; }
|
||||
operator T() const { return aux::network_to_host(m_integer); }
|
||||
private:
|
||||
T m_integer;
|
||||
};
|
||||
|
||||
typedef big_endian<int32> int32_big;
|
||||
typedef big_endian<uint32> uint32_big;
|
||||
typedef big_endian<uint16> uint16_big;
|
||||
|
||||
#if (defined(__SVR4) && defined(__sun))
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
template<typename T> static inline void zeromem(T *a, size_t count = 1) { memset(a, 0, count * sizeof(T)); }
|
||||
|
||||
typedef int SortCompareProc(const void *, const void *);
|
||||
|
||||
template<typename T> static FORCEINLINE void QuickSortT(T *base, size_t num, int (*comp)(const T *, const T *)) { qsort(base, num, sizeof(T), (SortCompareProc*)comp); }
|
||||
|
||||
|
||||
// WARNING: The template parameter MUST be a POD type!
|
||||
template <typename T, size_t minsize = 16> class Array {
|
||||
protected:
|
||||
T *mem;
|
||||
size_t alloc,count;
|
||||
|
||||
public:
|
||||
Array(size_t init) { Init(init); }
|
||||
Array() { Init(); }
|
||||
~Array() { Free(); }
|
||||
|
||||
void inline Init() { mem = NULL; alloc = count = 0; }
|
||||
void inline Init(size_t init) { Init(); if (init) Resize(init); }
|
||||
size_t inline GetCount() const { return count; }
|
||||
size_t inline GetAlloc() const { return alloc; }
|
||||
void inline SetCount(size_t c) { count = c; }
|
||||
|
||||
inline T& operator[](size_t offset) { assert(offset ==0 || offset<alloc); return mem[offset]; }
|
||||
inline const T& operator[](size_t offset) const { assert(offset ==0 || offset<alloc); return mem[offset]; }
|
||||
|
||||
void inline Resize(size_t a) {
|
||||
if (a == 0) { free(mem); Init(); }
|
||||
else { mem = (T*)realloc(mem, (alloc=a) * sizeof(T)); }
|
||||
}
|
||||
|
||||
void Grow() { Resize(::max<size_t>(minsize, alloc * 2)); }
|
||||
|
||||
inline size_t Append(const T &t) {
|
||||
if (count >= alloc) Grow();
|
||||
size_t r=count++;
|
||||
mem[r] = t;
|
||||
return r;
|
||||
}
|
||||
|
||||
T inline &Append() {
|
||||
if (count >= alloc) Grow();
|
||||
return mem[count++];
|
||||
}
|
||||
|
||||
void inline Compact() {
|
||||
Resize(count);
|
||||
}
|
||||
|
||||
void inline Free() {
|
||||
free(mem);
|
||||
Init();
|
||||
}
|
||||
|
||||
void inline Clear() {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
bool inline MoveUpLast(size_t index) {
|
||||
assert(index < count);
|
||||
size_t c = --count;
|
||||
if (index != c) {
|
||||
mem[index] = mem[c];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool inline MoveUpLastExist(const T &v) {
|
||||
return MoveUpLast(LookupElementExist(v));
|
||||
}
|
||||
|
||||
size_t inline LookupElement(const T &v) const {
|
||||
for(size_t i = 0; i != count; i++)
|
||||
if (mem[i] == v)
|
||||
return i;
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
bool inline HasElement(const T &v) const {
|
||||
return LookupElement(v) != -1;
|
||||
}
|
||||
|
||||
typedef int SortCompareProc(const T *a, const T *b);
|
||||
|
||||
void Sort(SortCompareProc* proc, size_t start, size_t end) {
|
||||
QuickSortT(&mem[start], end - start, proc);
|
||||
}
|
||||
|
||||
void Sort(SortCompareProc* proc, size_t start) {
|
||||
Sort(proc, start, count);
|
||||
}
|
||||
|
||||
void Sort(SortCompareProc* proc) {
|
||||
Sort(proc, 0, count);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //__TEMPLATES_H__
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_TYPES_H__
|
||||
#define __UTP_TYPES_H__
|
||||
|
||||
#ifdef __GNUC__
|
||||
// Used for gcc tool chains accepting but not supporting pragma pack
|
||||
// See http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html
|
||||
#define PACKED_ATTRIBUTE __attribute__((__packed__))
|
||||
#else
|
||||
#define PACKED_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ALIGNED_ATTRIBUTE(x) __attribute__((aligned (x)))
|
||||
#else
|
||||
#define ALIGNED_ATTRIBUTE(x)
|
||||
#endif
|
||||
|
||||
// hash.cpp needs socket definitions, which is why this networking specific
|
||||
// code is inclued in utypes.h
|
||||
#ifdef WIN32
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define IP_OPT_DONTFRAG IP_DONTFRAGMENT
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef IP_DONTFRAG
|
||||
#define IP_OPT_DONTFRAG IP_DONTFRAG
|
||||
#elif defined IP_DONTFRAGMENT
|
||||
#define IP_OPT_DONTFRAG IP_DONTFRAGMENT
|
||||
#else
|
||||
//#warning "I don't know how to set DF bit on this system"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
|
||||
#ifdef POSIX
|
||||
typedef struct sockaddr_storage SOCKADDR_STORAGE;
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define I64u "%I64u"
|
||||
#else
|
||||
#define I64u "%Lu"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
// standard types
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned char uint8;
|
||||
typedef signed char int8;
|
||||
typedef unsigned short uint16;
|
||||
typedef signed short int16;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned int uint32;
|
||||
typedef signed int int32;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef signed __int64 int64;
|
||||
#else
|
||||
typedef unsigned long long uint64;
|
||||
typedef long long int64;
|
||||
#endif
|
||||
|
||||
/* compile-time assert */
|
||||
#ifndef CASSERT
|
||||
#define CASSERT( exp, name ) typedef int is_not_##name [ (exp ) ? 1 : -1 ];
|
||||
#endif
|
||||
|
||||
CASSERT(8 == sizeof(uint64), sizeof_uint64_is_8)
|
||||
CASSERT(8 == sizeof(int64), sizeof_int64_is_8)
|
||||
|
||||
#ifndef INT64_MAX
|
||||
#define INT64_MAX 0x7fffffffffffffffLL
|
||||
#endif
|
||||
|
||||
// always ANSI
|
||||
typedef const char * cstr;
|
||||
typedef char * str;
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef uint8 bool;
|
||||
#endif
|
||||
|
||||
#endif //__UTP_TYPES_H__
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "utp.h"
|
||||
#include "utp_types.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else //!WIN32
|
||||
#include <time.h>
|
||||
#include <sys/time.h> // Linux needs both time.h and sys/time.h
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#include "utp_utils.h"
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
typedef ULONGLONG (WINAPI GetTickCount64Proc)(void);
|
||||
static GetTickCount64Proc *pt2GetTickCount64;
|
||||
static GetTickCount64Proc *pt2RealGetTickCount;
|
||||
|
||||
static uint64 startPerformanceCounter;
|
||||
static uint64 startGetTickCount;
|
||||
// MSVC 6 standard doesn't like division with uint64s
|
||||
static double counterPerMicrosecond;
|
||||
|
||||
static uint64 UTGetTickCount64()
|
||||
{
|
||||
if (pt2GetTickCount64) {
|
||||
return pt2GetTickCount64();
|
||||
}
|
||||
if (pt2RealGetTickCount) {
|
||||
uint64 v = pt2RealGetTickCount();
|
||||
// fix return value from GetTickCount
|
||||
return (DWORD)v | ((v >> 0x18) & 0xFFFFFFFF00000000);
|
||||
}
|
||||
return (uint64)GetTickCount();
|
||||
}
|
||||
|
||||
static void Time_Initialize()
|
||||
{
|
||||
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
|
||||
pt2GetTickCount64 = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount64");
|
||||
// not a typo. GetTickCount actually returns 64 bits
|
||||
pt2RealGetTickCount = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount");
|
||||
|
||||
uint64 frequency;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&startPerformanceCounter);
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
|
||||
counterPerMicrosecond = (double)frequency / 1000000.0f;
|
||||
startGetTickCount = UTGetTickCount64();
|
||||
}
|
||||
|
||||
static int64 abs64(int64 x) { return x < 0 ? -x : x; }
|
||||
|
||||
static uint64 __GetMicroseconds()
|
||||
{
|
||||
static bool time_init = false;
|
||||
if (!time_init) {
|
||||
time_init = true;
|
||||
Time_Initialize();
|
||||
}
|
||||
|
||||
uint64 counter;
|
||||
uint64 tick;
|
||||
|
||||
QueryPerformanceCounter((LARGE_INTEGER*) &counter);
|
||||
tick = UTGetTickCount64();
|
||||
|
||||
// unfortunately, QueryPerformanceCounter is not guaranteed
|
||||
// to be monotonic. Make it so.
|
||||
int64 ret = (int64)(((int64)counter - (int64)startPerformanceCounter) / counterPerMicrosecond);
|
||||
// if the QPC clock leaps more than one second off GetTickCount64()
|
||||
// something is seriously fishy. Adjust QPC to stay monotonic
|
||||
int64 tick_diff = tick - startGetTickCount;
|
||||
if (abs64(ret / 100000 - tick_diff / 100) > 10) {
|
||||
startPerformanceCounter -= (uint64)((int64)(tick_diff * 1000 - ret) * counterPerMicrosecond);
|
||||
ret = (int64)((counter - startPerformanceCounter) / counterPerMicrosecond);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64 UTP_GetMilliseconds()
|
||||
{
|
||||
return GetTickCount();
|
||||
}
|
||||
|
||||
#else //!WIN32
|
||||
|
||||
static inline uint64 UTP_GetMicroseconds(void);
|
||||
static inline uint64 UTP_GetMilliseconds()
|
||||
{
|
||||
return UTP_GetMicroseconds() / 1000;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
static uint64 __GetMicroseconds()
|
||||
{
|
||||
// http://developer.apple.com/mac/library/qa/qa2004/qa1398.html
|
||||
// http://www.macresearch.org/tutorial_performance_and_time
|
||||
static mach_timebase_info_data_t sTimebaseInfo;
|
||||
static uint64_t start_tick = 0;
|
||||
uint64_t tick;
|
||||
// Returns a counter in some fraction of a nanoseconds
|
||||
tick = mach_absolute_time();
|
||||
if (sTimebaseInfo.denom == 0) {
|
||||
// Get the timer ratio to convert mach_absolute_time to nanoseconds
|
||||
mach_timebase_info(&sTimebaseInfo);
|
||||
start_tick = tick;
|
||||
}
|
||||
// Calculate the elapsed time, convert it to microseconds and return it.
|
||||
return ((tick - start_tick) * sTimebaseInfo.numer) / (sTimebaseInfo.denom * 1000);
|
||||
}
|
||||
|
||||
#else // !__APPLE__
|
||||
|
||||
#if ! (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC))
|
||||
#warning "Using non-monotonic function gettimeofday() in UTP_GetMicroseconds()"
|
||||
#endif
|
||||
|
||||
/* Unfortunately, #ifdef CLOCK_MONOTONIC is not enough to make sure that
|
||||
POSIX clocks work -- we could be running a recent libc with an ancient
|
||||
kernel (think OpenWRT). -- jch */
|
||||
|
||||
static uint64_t __GetMicroseconds()
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC)
|
||||
static int have_posix_clocks = -1;
|
||||
int rc;
|
||||
|
||||
if (have_posix_clocks < 0) {
|
||||
struct timespec ts;
|
||||
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
if (rc < 0) {
|
||||
have_posix_clocks = 0;
|
||||
} else {
|
||||
have_posix_clocks = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (have_posix_clocks) {
|
||||
struct timespec ts;
|
||||
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return uint64(ts.tv_sec) * 1000000 + uint64(ts.tv_nsec) / 1000;
|
||||
}
|
||||
#endif
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
return uint64(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
}
|
||||
|
||||
#endif //!__APPLE__
|
||||
|
||||
#endif //!WIN32
|
||||
|
||||
/*
|
||||
* Whew. Okay. After that #ifdef maze above, we now know we have a working
|
||||
* __GetMicroseconds() implementation on all platforms.
|
||||
*
|
||||
* Because there are a number of assertions in libutp that will cause a crash
|
||||
* if monotonic time isn't monotonic, now apply some safety checks. While in
|
||||
* principle we're already protecting ourselves in cases where non-monotonic
|
||||
* time is likely to happen, this protects all versions.
|
||||
*/
|
||||
|
||||
static inline uint64 UTP_GetMicroseconds()
|
||||
{
|
||||
static uint64 offset = 0, previous = 0;
|
||||
|
||||
uint64 now = __GetMicroseconds() + offset;
|
||||
if (previous > now) {
|
||||
/* Eek! */
|
||||
offset += previous - now;
|
||||
now = previous;
|
||||
}
|
||||
previous = now;
|
||||
return now;
|
||||
}
|
||||
|
||||
#define ETHERNET_MTU 1500
|
||||
#define IPV4_HEADER_SIZE 20
|
||||
#define IPV6_HEADER_SIZE 40
|
||||
#define UDP_HEADER_SIZE 8
|
||||
#define GRE_HEADER_SIZE 24
|
||||
#define PPPOE_HEADER_SIZE 8
|
||||
#define MPPE_HEADER_SIZE 2
|
||||
// packets have been observed in the wild that were fragmented
|
||||
// with a payload of 1416 for the first fragment
|
||||
// There are reports of routers that have MTU sizes as small as 1392
|
||||
#define FUDGE_HEADER_SIZE 36
|
||||
#define TEREDO_MTU 1280
|
||||
|
||||
#define UDP_IPV4_OVERHEAD (IPV4_HEADER_SIZE + UDP_HEADER_SIZE)
|
||||
#define UDP_IPV6_OVERHEAD (IPV6_HEADER_SIZE + UDP_HEADER_SIZE)
|
||||
#define UDP_TEREDO_OVERHEAD (UDP_IPV4_OVERHEAD + UDP_IPV6_OVERHEAD)
|
||||
|
||||
#define UDP_IPV4_MTU (ETHERNET_MTU - IPV4_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
|
||||
#define UDP_IPV6_MTU (ETHERNET_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
|
||||
#define UDP_TEREDO_MTU (TEREDO_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE)
|
||||
|
||||
uint64 utp_default_get_udp_mtu(utp_callback_arguments *args) {
|
||||
// Since we don't know the local address of the interface,
|
||||
// be conservative and assume all IPv6 connections are Teredo.
|
||||
return (args->address->sa_family == AF_INET6) ? UDP_TEREDO_MTU : UDP_IPV4_MTU;
|
||||
}
|
||||
|
||||
uint64 utp_default_get_udp_overhead(utp_callback_arguments *args) {
|
||||
// Since we don't know the local address of the interface,
|
||||
// be conservative and assume all IPv6 connections are Teredo.
|
||||
return (args->address->sa_family == AF_INET6) ? UDP_TEREDO_OVERHEAD : UDP_IPV4_OVERHEAD;
|
||||
}
|
||||
|
||||
uint64 utp_default_get_random(utp_callback_arguments *args) {
|
||||
return rand();
|
||||
}
|
||||
|
||||
uint64 utp_default_get_milliseconds(utp_callback_arguments *args) {
|
||||
return UTP_GetMilliseconds();
|
||||
}
|
||||
|
||||
uint64 utp_default_get_microseconds(utp_callback_arguments *args) {
|
||||
return UTP_GetMicroseconds();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
uint64 utp_default_get_udp_mtu(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_udp_overhead(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_random(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_milliseconds(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_microseconds(utp_callback_arguments *args);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue