diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000000..2099840756 --- /dev/null +++ b/INSTALL @@ -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 `' 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. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000000..ff8790fbe2 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,46 @@ +## Process this file with automake to produce Makefile.in + +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = lib src + +bin_PROGRAMS = cellwired + +dist_cellwired_SOURCES = main.c symtbl.h +nodist_cellwired_SOURCES = symtbl.c + +cellwired_LDADD = \ + $(top_srcdir)/src/libcellwire.la \ + $(top_srcdir)/lib/core/src/libcore.la \ + $(top_srcdir)/lib/logger/liblogger.la \ + -lpthread -lm -lsctp @OSLIBS@ + +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib/core/include \ + -I$(top_srcdir)/lib/logger \ + -I$(top_srcdir)/src + +CLEANFILES = symtbl.c +DISTCLEANFILES = $(DIST_ARCHIVES) +MAINTAINERCLEANFILES = \ + configure config.in \ + aclocal.m4 m4/ltsugar.m4 m4/libtool.m4 m4/ltversion.m4 \ + m4/lt~obsolete.m4 m4/ltoptions.m4 \ + build-aux/depcomp build-aux/missing build-aux/config.guess \ + build-aux/config.sub build-aux/ltmain.sh build-aux/install-sh \ + .cscope.out .cscope.out.in .cscope.files .cscope.out.po \ + Makefile.in +MOSTLYCLEANFILES = core *.stackdump + +EXTRA_DIST = symtbl.sh + +NM_TMP_FILE = nm.tmp +.INTERMEDIATE: symtbl.c +symtbl.c: $(bsd_DEPENDENCIES) + @for las in $<; do \ + lib=`echo $$las | sed -e "s|\(.*\)/lib\([^/].*\)\.la|\1/.libs/lib\2.a|g"`; \ + echo $$lib; \ + nm $$lib >> $(NM_TMP_FILE); \ + done; \ + $(top_srcdir)/symtbl.sh $(NM_TMP_FILE) $@; \ + rm -f $(NM_TMP_FILE) diff --git a/NEWS b/NEWS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/README b/README new file mode 100644 index 0000000000..a1ecdd75d4 --- /dev/null +++ b/README @@ -0,0 +1,64 @@ +* Git Config +user@host:~/git/cellwire$ sudo apt-get install git +user@host:~/git/cellwire$ git config --global user.name "Sukchan Lee" +user@host:~/git/cellwire$ git config --global user.email acetcom@gmail.com +user@host:~/git/cellwire$ git config --global core.editor vi +user@host:~/git/cellwire$ git clone https://github.com/acetcom/cellwire.git + +* Initial Setup +user@host:~/git/cellwire$ sudo apt-get install autoconf libtool m4 libsctp-dev +cscope gdb +user@host:~/git/cellwire$ autoreconf -iv +user@host:~/git/cellwire$ \ + CFLAGS='-g3' ./configure --prefix=$HOME/Documents/git/cellwire/install +user@host:~/git/cellwire$ make OR make install + +* Install SCTP for Mac OS X 10.11(El Captian) + - Reference : https://github.com/sctplab/SCTP_NKE_ElCapitan + - Start up in OS X Recovery by holding down Command-R while the Mac is starting up + Choose Terminal from the Utilities menu. + Type 'csrutil disable' in Terminal and Reboot + - Download SCTP_NKE_ElCapitan_Install_01.dmg + xcode-select --install + sudo cp -R /Volumes/SCTP_NKE_ElCapitan_01/SCTPSupport.kext /Library/Extensions + sudo cp -R /Volumes/SCTP_NKE_ElCapitan_01/SCTP.kext /Library/Extensions + sudo cp /Volumes/SCTP_NKE_ElCapitan_01/socket.h /usr/include/sys/ + sudo cp /Volumes/SCTP_NKE_ElCapitan_01/sctp.h /usr/include/netinet/ + sudo cp /Volumes/SCTP_NKE_ElCapitan_01/sctp_uio.h /usr/include/netinet/ + sudo cp /Volumes/SCTP_NKE_ElCapitan_01/libsctp.dylib /usr/lib/ + sudo kextload /Library/Extensions/SCTP.kext + +* Git in Development +user@host:~/git/cellwire$ git status -uno +user@host:~/git/cellwire$ git add README +user@host:~/git/cellwire$ git commit +user@host:~/git/cellwire$ git push -u orgin master +user@host:~/git/cellwire$ git pull +user@host:~/git/cellwire$ git reset --hard HEAD +user@host:~/git/cellwire$ git checkout README + +* CSCOPE +Download ViM plugin to user@host:~/.vim/plugin/cscope_maps.vim +CSCOPE_DB="/home/acetcom/git/cellwire/.cscope.out" +export CSCOPE_DB +user@host:~/git/cellwire$ ./mkcscope.sh + +* Reconfigure Build +user@host:~/git/cellwire$ ./config.nice +## config.nice sample script +CFLAGS='-g3' \ +'./configure' \ +'--prefix=/home/acetcom/Documents/git/install' \ +"$@" + +* Testing +user@host:~/git/cellwire$ ./lib/core/test/testcore + +* Running +user@host:~/git/cellwire$ sudo ./cellwired + +* Cleaning +user@host:~/git/cellwire$ make clean +user@host:~/git/cellwire$ make distclean +user@host:~/git/cellwire$ make maintainer-clean + diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000000..b16858d4cb --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,74 @@ +dnl +dnl CORE_SUBST(varname) +dnl +dnl Adds variable with it's value into Makefile, e.g.: +dnl CC = gcc +dnl +AC_DEFUN([CORE_SUBST],[ + CORE_VAR_SUBST="$CORE_VAR_SUBST $1" +]) + +dnl +dnl CORE_SUBST_OLD(varname) +dnl +dnl Same as CORE_SUBST() but also substitutes all @VARNAME@ +dnl instances in every file passed to AC_OUTPUT() +dnl +AC_DEFUN([CORE_SUBST_OLD],[ + CORE_SUBST($1) + AC_SUBST($1) +]) + +dnl +dnl CORE_CONFIG_NICE(filename) +dnl +dnl Generates the config.nice file +dnl +AC_DEFUN([CORE_CONFIG_NICE],[ + AC_REQUIRE([AC_PROG_EGREP]) + AC_REQUIRE([LT_AC_PROG_SED]) + CORE_SUBST_OLD(EGREP) + CORE_SUBST_OLD(SED) + test -f $1 && mv $1 $1.old + rm -f $1.old + cat >$1<> $1 + fi + done + + echo "'[$]0' \\" >> $1 + if test `expr -- [$]0 : "'.*"` = 0; then + CONFIGURE_COMMAND="$CONFIGURE_COMMAND '[$]0'" + else + CONFIGURE_COMMAND="$CONFIGURE_COMMAND [$]0" + fi + for arg in $ac_configure_args; do + if test `expr -- $arg : "'.*"` = 0; then + if test `expr -- $arg : "--.*"` = 0; then + break; + fi + echo "'[$]arg' \\" >> $1 + CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS '[$]arg'" + else + if test `expr -- $arg : "'--.*"` = 0; then + break; + fi + echo "[$]arg \\" >> $1 + CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS [$]arg" + fi + done + echo '"[$]@"' >> $1 + chmod +x $1 + CONFIGURE_COMMAND="$CONFIGURE_COMMAND $CONFIGURE_OPTIONS" + CORE_SUBST_OLD(CONFIGURE_COMMAND) + CORE_SUBST_OLD(CONFIGURE_OPTIONS) +]) diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000000..22c1236577 --- /dev/null +++ b/configure.ac @@ -0,0 +1,272 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl This file is free software; as a special exception the author gives +dnl unlimited permission to copy and/or distribute it, with or without +dnl modifications, as long as this notice is preserved. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +AC_INIT([CELLWIRE], [0.1.0], [acetcom@gmail.com]) + +CORE_CONFIG_NICE(config.nice) + +dnl Must come before AM_INIT_AUTOMAKE. +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([1.10 -Wall -Werror]) + +# Minimum Autoconf version required. +AC_PREREQ(2.63) + +# Where to generate output; srcdir location. +AC_CONFIG_HEADERS([config.h:config.in])dnl Keep filename to 8.3 for MS-DOS. +AC_CONFIG_SRCDIR([main.c]) +AC_CANONICAL_HOST + +case $host in + *linux*) + OSDIR="unix" + OSCFLAGS="-DLINUX=1" + ;; + *) + OSDIR="unix" + ;; +esac +AC_SUBST(OSCFLAGS) +AC_SUBST(OSDIR) + +AH_TOP([ +#ifndef __CELLWIRE_CONFIG_H__ +#define __CELLWIRE_CONFIG_H__ +/* need this, because some autoconf tests rely on this (e.g. stpcpy) + * and it should be used for new programs */ +#define _GNU_SOURCE 1 +]) + +AH_BOTTOM([ +#endif /* __CELLWIRE_CONFIG_H__ */ +]) + +AH_VERBATIM([_REENTRANT], +[/* To allow the use of core in multithreaded programs we have to use + special features from the library. */ +#ifndef _REENTRANT +# define _REENTRANT 1 +#endif +]) + +dnl Checks for programs. +# We need a C compiler. +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_AWK +AM_PROG_AR +AM_PROG_LIBTOOL + +dnl Checks for pointer size +AC_CHECK_SIZEOF(void*, 4) + +if test "x$ac_cv_sizeof_voidp" != "x"; then + voidp_size=$ac_cv_sizeof_voidp +else + AC_ERROR([Cannot determine size of void*]) +fi + +dnl Checks for integer size +AC_CHECK_SIZEOF(char, 1) +AC_CHECK_SIZEOF(int, 4) +AC_CHECK_SIZEOF(long, 4) +AC_CHECK_SIZEOF(short, 2) +AC_CHECK_SIZEOF(long long, 8) + +if test "$ac_cv_sizeof_short" = "2"; then + short_value=short +fi +if test "$ac_cv_sizeof_int" = "4"; then + int_value=int +fi +# Now we need to find what c_int64_t (sizeof == 8) will be. +# The first match is our preference. +if test "$ac_cv_sizeof_int" = "8"; then + int64_literal='#define C_INT64_C(val) (val)' + uint64_literal='#define C_UINT64_C(val) (val##U)' + int64_t_fmt='#define C_INT64_T_FMT "d"' + uint64_t_fmt='#define C_UINT64_T_FMT "u"' + uint64_t_hex_fmt='#define C_UINT64_T_HEX_FMT "x"' + int64_value="int" + long_value=int + int64_strfn="strtoi" +elif test "$ac_cv_sizeof_long" = "8"; then + int64_literal='#define C_INT64_C(val) (val##L)' + uint64_literal='#define C_UINT64_C(val) (val##UL)' + int64_t_fmt='#define C_INT64_T_FMT "ld"' + uint64_t_fmt='#define C_UINT64_T_FMT "lu"' + uint64_t_hex_fmt='#define C_UINT64_T_HEX_FMT "lx"' + int64_value="long" + long_value=long + int64_strfn="strtol" +elif test "$ac_cv_sizeof_long_long" = "8"; then + int64_literal='#define C_INT64_C(val) (val##LL)' + uint64_literal='#define C_UINT64_C(val) (val##ULL)' + # Linux, Solaris, FreeBSD all support ll with printf. + # BSD 4.4 originated 'q'. Solaris is more popular and + # doesn't support 'q'. Solaris wins. Exceptions can + # go to the OS-dependent section. + int64_t_fmt='#define C_INT64_T_FMT "lld"' + uint64_t_fmt='#define C_UINT64_T_FMT "llu"' + uint64_t_hex_fmt='#define C_UINT64_T_HEX_FMT "llx"' + int64_value="long long" + long_value="long long" + int64_strfn="strtoll" +elif test "$ac_cv_sizeof_longlong" = "8"; then + int64_literal='#define C_INT64_C(val) (val##LL)' + uint64_literal='#define C_UINT64_C(val) (val##ULL)' + int64_t_fmt='#define C_INT64_T_FMT "qd"' + uint64_t_fmt='#define C_UINT64_T_FMT "qu"' + uint64_t_hex_fmt='#define C_UINT64_T_HEX_FMT "qx"' + int64_value="__int64" + long_value="__int64" + int64_strfn="strtoll" +else + # int64_literal may be overriden if your compiler thinks you have + # a 64-bit value but CORE does not agree. + AC_ERROR([could not detect a 64-bit integer type]) +fi + +AC_SUBST(voidp_size) +AC_SUBST(short_value) +AC_SUBST(int_value) +AC_SUBST(long_value) +AC_SUBST(int64_value) +AC_SUBST(int64_t_fmt) +AC_SUBST(uint64_t_fmt) +AC_SUBST(uint64_t_hex_fmt) +AC_SUBST(int64_literal) +AC_SUBST(uint64_literal) + +AC_DEFINE_UNQUOTED([PACKAGE_VERSION_MAJOR], + [`echo $PACKAGE_VERSION | sed 's/^\([[^\.]]\+\)\.\([[^\.]]\+\)\.\([[^\.]]\+\).*/\1/'`], + [Major version of this package]) +AC_DEFINE_UNQUOTED([PACKAGE_VERSION_MINOR], + [`echo $PACKAGE_VERSION | sed 's/^\([[^\.]]\+\)\.\([[^\.]]\+\)\.\([[^\.]]\+\).*/\2/'`], + [Minor version of this package]) +AC_DEFINE_UNQUOTED([PACKAGE_VERSION_PATCHLEVEL], + [`echo $PACKAGE_VERSION | sed 's/^\([[^\.]]\+\)\.\([[^\.]]\+\)\.\([[^\.]]\+\).*/\3/'`], + [Patch version of this package]) + +################################## +#### Checks for header files. #### +################################## + +AC_HEADER_STDC +AC_CHECK_HEADERS( \ + arpa/inet.h \ + ctype.h \ + errno.h \ + fcntl.h \ + ifaddrs.h \ + limits.h \ + netdb.h \ + pthread.h \ + regex.h \ + semaphore.h \ + signal.h \ + stdarg.h \ + stdio.h \ + stdint.h \ + stdlib.h \ + string.h \ + strings.h \ + time.h \ + unistd.h \ + net/if_dl.h \ + netinet/ether.h \ + netinet/in.h \ + netinet/sctp.h \ + sys/ioctl.h \ + sys/param.h \ + sys/socket.h \ + sys/stat.h \ + sys/syslimits.h \ + sys/types.h \ + sys/time.h \ + sys/wait.h \ + sys/uio.h \ +) + +########################################## +#### Checks for typedefs, structures, #### +#### and compiler characteristics. #### +########################################## + +AC_C_BIGENDIAN + +AC_CHECK_MEMBERS([struct tm.tm_gmtoff, struct tm.__tm_gmtoff],,,[ +#include +#include ]) + +AC_CHECK_FILE(/dev/random, + AC_DEFINE([HAVE_DEV_RANDOM], [1], + [Define to 1 if you have the /dev/random file.])) + +####################################### +#### Checks for library functions. #### +####################################### + +AC_FUNC_VPRINTF +AC_CHECK_FUNCS(\ + atexit \ + gettimeofday \ + inet_ntop \ + inet_pton \ + inet_aton \ + memmove \ + sigaction \ + sigwait \ + sigsuspend \ + stpcpy \ + strcasecmp \ + strtoul \ + stricmp \ + strerror \ + writev \ + utime \ + utimes \ + sem_timedwait \ +) + +AC_CHECK_LIB([crypt], [crypt], [OSLIBS="-lcrypt"]) +AC_SUBST(OSLIBS) + +##################### +#### Conclusion. #### +##################### + +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([src/Makefile]) +AC_CONFIG_FILES([lib/Makefile]) +AC_CONFIG_FILES([lib/core/include/core.h]) +AC_CONFIG_FILES([lib/core/Makefile]) +AC_CONFIG_FILES([lib/core/src/Makefile]) +case $host in + *) + AC_CONFIG_FILES([lib/core/src/unix/Makefile]) + ;; +esac +AC_CONFIG_FILES([lib/core/test/Makefile]) +AC_CONFIG_FILES([lib/logger/Makefile]) +AC_OUTPUT + +echo " +CellWire configuration +-------------------- +version : ${PACKAGE_VERSION} +host : ${host} +source code location : ${srcdir} +compiler : ${CC} +compiler flags : ${CFLAGS} +linker flags : ${LDFLAGS} ${LIBS} +config file directory : `eval echo \`echo ${sysconfdir}\`` +" diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000000..daf6814646 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = core logger + +MAINTAINERCLEANFILES = Makefile.in +MOSTLYCLEANFILES = *.stackdump diff --git a/lib/core/Makefile.am b/lib/core/Makefile.am new file mode 100644 index 0000000000..101a51422c --- /dev/null +++ b/lib/core/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = src test + +MAINTAINERCLEANFILES = Makefile.in +MOSTLYCLEANFILES = core *.stackdump diff --git a/lib/core/include/arch/core_private_common.h b/lib/core/include/arch/core_private_common.h new file mode 100644 index 0000000000..141c047895 --- /dev/null +++ b/lib/core/include/arch/core_private_common.h @@ -0,0 +1,4 @@ +#ifndef CORE_PRIVATE_COMMON_H +#define CORE_PRIVATE_COMMON_H + +#endif /*CORE_PRIVATE_COMMON_H*/ diff --git a/lib/core/include/arch/unix/core_arch_file.h b/lib/core/include/arch/unix/core_arch_file.h new file mode 100644 index 0000000000..76cc8b1dcf --- /dev/null +++ b/lib/core/include/arch/unix/core_arch_file.h @@ -0,0 +1,29 @@ +#ifndef __CORE_ARCH_FILE_H__ +#define __CORE_ARCH_FILE_H__ + +#include "core.h" +#include "core_time.h" +#include "core_file.h" + +#define FILE_DEFAULT_BUFSIZE 4096 +/* For backwards-compat */ +#define FILE_BUFSIZE FILE_DEFAULT_BUFSIZE + +typedef int os_file_t; /**< native file */ + +struct file_t { + os_file_t filedes; + char fname[MAX_FILENAME_SIZE]; + c_int32_t flags; + int eof_hit; + c_time_t timeout; + off_t filePtr; /* position in file of handle */ +}; + +typedef struct stat struct_stat; + +mode_t unix_perms2mode(file_perms_t perms); +file_perms_t unix_mode2perms(mode_t mode); + +#endif /* ! __CORE_ARCH_FILE_H__ */ + diff --git a/lib/core/include/arch/unix/core_arch_mutex.h b/lib/core/include/arch/unix/core_arch_mutex.h new file mode 100644 index 0000000000..38d67803a2 --- /dev/null +++ b/lib/core/include/arch/unix/core_arch_mutex.h @@ -0,0 +1,12 @@ +#ifndef __CORE_ARCH_MUTEX_H__ +#define __CORE_ARCH_MUTEX_H__ + +#include "core.h" +#include "core_mutex.h" + +typedef struct _mutex_t { + pthread_mutex_t mutex; +} mutex_t; + +#endif /* __CORE_ARCH_MUTEX_H__ */ + diff --git a/lib/core/include/arch/unix/core_arch_semaphore.h b/lib/core/include/arch/unix/core_arch_semaphore.h new file mode 100644 index 0000000000..fcbae58b9a --- /dev/null +++ b/lib/core/include/arch/unix/core_arch_semaphore.h @@ -0,0 +1,12 @@ +#ifndef __CORE_ARCH_SEMAPHORE_H__ +#define __CORE_ARCH_SEMAPHORE_H__ + +#include "core.h" +#include "core_semaphore.h" + +typedef struct _semaphore_t { + sem_t *semaphore; +} semaphore_t; + +#endif /* __CORE_ARCH_SEMAPHORE_H__ */ + diff --git a/lib/core/include/core.h.in b/lib/core/include/core.h.in new file mode 100644 index 0000000000..e458c164a2 --- /dev/null +++ b/lib/core/include/core.h.in @@ -0,0 +1,366 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __CORE_H__ +#define __CORE_H__ + +/* GENERATED FILE WARNING! DO NOT EDIT core.h + * + * You must modify core.h.in instead. + * + * And please, make an effort to stub core.hw and core.hnw in the process. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/** + * @file core.h + * @brief CORE Platform Definitions + */ + +/** + * @defgroup CORE Core Runtime library + * @{ + */ + +#if HAVE_SYS_TYPES_H +#include +#endif + +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) +/* C99 7.18.4 requires that stdint.h only exposes INT64_C + * and UINT64_C for C++ implementations if this is defined: */ +#define __STDC_CONSTANT_MACROS +#endif + +#if HAVE_CTYPE_H +#include +#endif + +#if HAVE_ERRNO_H +#include +#endif + +#if HAVE_FCNTL_H +#include +#endif + +#if HAVE_NET_IF_H_ +#include +#endif + +#if HAVE_PTHREAD_H +#include +#endif + +#if HAVE_SIGNAL_H +#include +#endif + +#if HAVE_SEMAPHORE_H +#include +#endif + +#if HAVE_STDARG_H +#include +#endif + +#if HAVE_STDIO_H +#include +#endif + +#if HAVE_STDINT_H +#include +#endif + +#if HAVE_STDLIB_H +#include +#endif + +#if HAVE_STRING_H +#include +#endif + +#if HAVE_STRINGS_H +#include +#endif + +#if HAVE_TIME_H +#include +#endif + +#if HAVE_UNISTD_H +#include +#endif + +#if HAVE_NET_IF_DL_H +#include +#endif + +#if HAVE_NETINET_ETHER_H +#include +#endif + +#if HAVE_NETINET_IN_H +#include +#endif + +#if HAVE_NETINET_SCTP_H +#include +#endif + +#if HAVE_SYS_IOCTL_H +#include +#endif + +#if HAVE_SYS_PARAM_H +#include +#endif + +#if HAVE_SYS_STAT_H +#include +#endif + +#if HAVE_SYS_TIME_H +#include +#endif + +#if HAVE_SYS_WAIT_H +#include +#endif + +/* header files for PATH_MAX, _POSIX_PATH_MAX */ +#if HAVE_LIMITS_H +#include +#else +#if HAVE_SYS_SYSLIMITS_H +#include +#endif +#endif + +#if HAVE_SYS_UIO_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Typedefs that CORE needs. */ + +typedef char c_int8_t; +typedef unsigned char c_uint8_t; + +typedef @short_value@ c_int16_t; +typedef unsigned @short_value@ c_uint16_t; + +typedef @int_value@ c_int32_t; +typedef unsigned @int_value@ c_uint32_t; + +#define C_SIZEOF_VOIDP @voidp_size@ + +typedef @long_value@ c_int64_t; +typedef unsigned @long_value@ c_uint64_t; + +#if C_SIZEOF_VOIDP == 8 +typedef c_uint64_t c_uintptr_t; +typedef c_int64_t c_intptr_t; +#else +typedef c_uint32_t c_uintptr_t; +typedef c_int32_t c_intptr_t; +#endif + +/* Mechanisms to properly type numeric literals */ +@int64_literal@ +@uint64_literal@ + +@int64_t_fmt@ +@uint64_t_fmt@ +@uint64_t_hex_fmt@ + +#ifdef INT16_MIN +#define C_INT16_MIN INT16_MIN +#else +#define C_INT16_MIN (-0x7fff - 1) +#endif + +#ifdef INT16_MAX +#define C_INT16_MAX INT16_MAX +#else +#define C_INT16_MAX (0x7fff) +#endif + +#ifdef UINT16_MAX +#define C_UINT16_MAX UINT16_MAX +#else +#define C_UINT16_MAX (0xffff) +#endif + +#ifdef INT32_MIN +#define C_INT32_MIN INT32_MIN +#else +#define C_INT32_MIN (-0x7fffffff - 1) +#endif + +#ifdef INT32_MAX +#define C_INT32_MAX INT32_MAX +#else +#define C_INT32_MAX 0x7fffffff +#endif + +#ifdef UINT32_MAX +#define C_UINT32_MAX UINT32_MAX +#else +#define C_UINT32_MAX (0xffffffffU) +#endif + +#ifdef INT64_MIN +#define C_INT64_MIN INT64_MIN +#else +#define C_INT64_MIN (C_INT64_C(-0x7fffffffffffffff) - 1) +#endif + +#ifdef INT64_MAX +#define C_INT64_MAX INT64_MAX +#else +#define C_INT64_MAX C_INT64_C(0x7fffffffffffffff) +#endif + +#ifdef UINT64_MAX +#define C_UINT64_MAX UINT64_MAX +#else +#define C_UINT64_MAX C_UINT64_C(0xffffffffffffffff) +#endif + +/* Definitions that CORE programs need to work properly. */ + +/** + * Thread callbacks from CORE functions must be declared with THREAD_FUNC, + * so that they follow the platform's calling convention. + *
+ *
+ * void* THREAD_FUNC my_thread_entry_fn(core_thread_t *thd, void *data);
+ *
+ * 
+ */ +#define THREAD_FUNC + +/** + * The public CORE functions are declared with CORE_DECLARE(), so they may + * use the most appropriate calling convention. Public CORE functions with + * variable arguments must use CORE_DECLARE_NONSTD(). + * + * @remark Both the declaration and implementations must use the same macro. + * + *
+ * CORE_DECLARE(rettype) core_func(args)
+ * 
+ * @see CORE_DECLARE_NONSTD @see CORE_DECLARE_DATA + * @remark Note that when CORE compiles the library itself, it passes the + * symbol -DCORE_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) + * to export public symbols from the dynamic library build.\n + * The user must define the CORE_DECLARE_STATIC when compiling to target + * the static CORE library on some platforms (e.g. Win32.) The public symbols + * are neither exported nor imported when CORE_DECLARE_STATIC is defined.\n + * By default, compiling an application and including the CORE public + * headers, without defining CORE_DECLARE_STATIC, will prepare the code to be + * linked to the dynamic library. + */ +#define CORE_DECLARE(type) type + +/** + * The public CORE functions using variable arguments are declared with + * CORE_DECLARE_NONSTD(), as they must follow the C language calling convention. + * @see CORE_DECLARE @see CORE_DECLARE_DATA + * @remark Both the declaration and implementations must use the same macro. + *
+ *
+ * CORE_DECLARE_NONSTD(rettype) core_func(args, ...);
+ *
+ * 
+ */ +#define CORE_DECLARE_NONSTD(type) type + +/** + * The public CORE variables are declared with CORE_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * @see CORE_DECLARE @see CORE_DECLARE_NONSTD + * @remark Note that the declaration and implementations use different forms, + * but both must include the macro. + * + *
+ *
+ * extern CORE_DECLARE_DATA type core_variable;\n
+ * CORE_DECLARE_DATA type core_variable = value;
+ *
+ * 
+ */ +#define CORE_DECLARE_DATA + +#if defined(PATH_MAX) +#define C_PATH_MAX PATH_MAX +#elif defined(_POSIX_PATH_MAX) +#define C_PATH_MAX _POSIX_PATH_MAX +#else +#error no decision has been made on C_PATH_MAX for your platform +#endif + +/** @} */ + +/* Definitions that only Win32 programs need to compile properly. */ + +#if WORDS_BIGENDIAN +#define ED2(x1, x2) x1 x2 +#define ED3(x1, x2, x3) x1 x2 x3 +#define ED4(x1, x2, x3, x4) x1 x2 x3 x4 +#define ED5(x1, x2, x3, x4, x5) x1 x2 x3 x4 x5 +#define ED6(x1, x2, x3, x4, x5, x6) x1 x2 x3 x4 x5 x6 +#define ED7(x1, x2, x3, x4, x5, x6, x7) x1 x2 x3 x4 x5 x6 x7 +#define ED8(x1, x2, x3, x4, x5, x6, x7, x8) x1 x2 x3 x4 x5 x6 x7 x8 +#else +#define ED2(x1, x2) x2 x1 +#define ED3(x1, x2, x3) x3 x2 x1 +#define ED4(x1, x2, x3, x4) x4 x3 x2 x1 +#define ED5(x1, x2, x3, x4, x5) x5 x4 x3 x2 x1 +#define ED6(x1, x2, x3, x4, x5, x6) x6 x5 x4 x3 x2 x1 +#define ED7(x1, x2, x3, x4, x5, x6, x7) x7 x6 x5 x4 x3 x2 x1 +#define ED8(x1, x2, x3, x4, x5, x6, x7, x8) x8 x7 x6 x5 x4 x3 x2 x1 +#endif + +/** FALSE */ +#ifndef FALSE +#define FALSE 0 +#endif +/** TRUE */ +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +/* CORE_ALIGN() is only to be used to align on a power of 2 boundary */ +#define CORE_ALIGN(size, boundary) \ + (((size) + ((boundary) - 1)) & ~((boundary) - 1)) + +/** Default alignment */ +#define CORE_ALIGN_DEFAULT(size) CORE_ALIGN(size, 4) + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_H */ diff --git a/lib/core/include/core_aes.h b/lib/core/include/core_aes.h new file mode 100644 index 0000000000..afec811b1a --- /dev/null +++ b/lib/core/include/core_aes.h @@ -0,0 +1,42 @@ +#ifndef _CORE_AES_H__ +#define _CORE_AES_H__ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define AES_BLOCK_SIZE 16 +#define MAX_KEY_BITS 256 + +#define KEYLENGTH(keybits) ((keybits)/8) +#define RKLENGTH(keybits) ((keybits)/8+28) +#define NROUNDS(keybits) ((keybits)/32+6) + +CORE_DECLARE(int) aes_setup_enc(c_uint32_t *rk, const c_uint8_t *key, + int keybits); +CORE_DECLARE(int) aes_setup_dec(c_uint32_t *rk, const c_uint8_t *key, + int keybits); + +CORE_DECLARE(void) aes_encrypt(const c_uint32_t *rk, int nrounds, + const c_uint8_t plaintext[16], c_uint8_t ciphertext[16]); +CORE_DECLARE(void) aes_decrypt(const c_uint32_t *rk, int nrounds, + const c_uint8_t ciphertext[16], c_uint8_t plaintext[16]); + +CORE_DECLARE(status_t) aes_cbc_encrypt(const c_uint8_t *key, + const c_uint32_t keybits, c_uint8_t *ivec, + const c_uint8_t *in, const c_uint32_t inlen, + c_uint8_t *out, c_uint32_t *outlen); +CORE_DECLARE(status_t) aes_cbc_decrypt(const c_uint8_t *key, + const c_uint32_t keybits, c_uint8_t *ivec, + const c_uint8_t *in, const c_uint32_t inlen, + c_uint8_t *out, c_uint32_t *outlen); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/lib/core/include/core_aes_cmac.h b/lib/core/include/core_aes_cmac.h new file mode 100644 index 0000000000..d2dd36abbd --- /dev/null +++ b/lib/core/include/core_aes_cmac.h @@ -0,0 +1,46 @@ +#ifndef _CORE_AES_CMAC_H +#define _CORE_AES_CMAC_H + +#include "core_aes.h" + +#define AES_CMAC_DIGEST_LEN 16 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Caculate CMAC value + * + * @param cmac + * @param key + * @param msg + * @param len + * + * @return CORE_OK + * CORE_ERROR + */ +CORE_DECLARE(status_t) aes_cmac_calculate(c_uint8_t *cmac, const c_uint8_t *key, + const c_uint8_t *msg, const c_uint32_t len); + +/** + * Verify CMAC value + * + * @param cmac + * @param key + * @param msg + * @param len + * + * @return CORE_OK + * CORE_ERROR + * ERR_INVALID_CMAC + */ +#define ERR_INVALID_CMAC -2 +CORE_DECLARE(status_t) aes_cmac_verify(c_uint8_t *cmac, const c_uint8_t *key, + const c_uint8_t *msg, const c_uint32_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* ! _CORE_AES_CMAC_H */ diff --git a/lib/core/include/core_cond.h b/lib/core/include/core_cond.h new file mode 100644 index 0000000000..e5486e3f5f --- /dev/null +++ b/lib/core/include/core_cond.h @@ -0,0 +1,118 @@ +#ifndef __CORE_COND_H__ +#define __CORE_COND_H__ + +/** + * @file cond.h + * @brief CORE Condition Variable Routines + */ + +#include "core.h" +#include "core_errno.h" +#include "core_time.h" +#include "core_mutex.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup cond Condition Variable Routines + * @ingroup CORE + * @{ + */ + +/** Opaque structure for thread condition variables */ +typedef c_uintptr_t cond_id; + +/** + * Initialize Conditional Pool + */ +CORE_DECLARE(status_t) cond_init(void); + +/** + * Finalize Conditional Pool + */ +CORE_DECLARE(status_t) cond_final(void); + +/** + * Note: destroying a condition variable (or likewise, destroying or + * clearing the pool from which a condition variable was allocated) if + * any threads are blocked waiting on it gives undefined results. + */ + +/** + * Create and initialize a condition variable that can be used to signal + * and schedule threads in a single process. + * @param id the memory address where the newly created condition variable + * will be stored. + */ +CORE_DECLARE(status_t) cond_create(cond_id *id); + +/** + * Put the active calling thread to sleep until signaled to wake up. Each + * condition variable must be associated with a mutex, and that mutex must + * be locked before calling this function, or the behavior will be + * undefined. As the calling thread is put to sleep, the given mutex + * will be simultaneously released; and as this thread wakes up the lock + * is again simultaneously acquired. + * @param id the condition variable on which to block. + * @param mid the mutex that must be locked upon entering this function, + * is released while the thread is asleep, and is again acquired before + * returning from this function. + * @remark Spurious wakeups may occur. Before and after every call to wait on + * a condition variable, the caller should test whether the condition is already + * met. + */ +CORE_DECLARE(status_t) cond_wait(cond_id id, mutex_id mid); + +/** + * Put the active calling thread to sleep until signaled to wake up or + * the timeout is reached. Each condition variable must be associated + * with a mutex, and that mutex must be locked before calling this + * function, or the behavior will be undefined. As the calling thread + * is put to sleep, the given mutex will be simultaneously released; + * and as this thread wakes up the lock is again simultaneously acquired. + * @param id the condition variable on which to block. + * @param mid the mutex that must be locked upon entering this function, + * is released while the thread is asleep, and is again acquired before + * returning from this function. + * @param timeout The amount of time in microseconds to wait. This is + * a maximum, not a minimum. If the condition is signaled, we + * will wake up before this time, otherwise the error CORE_TIMEUP + * is returned. + */ +CORE_DECLARE(status_t) cond_timedwait( + cond_id id, mutex_id mid, c_time_t timeout); + +/** + * Signals a single thread, if one exists, that is blocking on the given + * condition variable. That thread is then scheduled to wake up and acquire + * the associated mutex. Although it is not required, if predictable scheduling + * is desired, that mutex must be locked while calling this function. + * @param id the condition variable on which to produce the signal. + * @remark If no threads are waiting on the condition variable, nothing happens. + */ +CORE_DECLARE(status_t) cond_signal(cond_id id); + +/** + * Signals all threads blocking on the given condition variable. + * Each thread that was signaled is then scheduled to wake up and acquire + * the associated mutex. This will happen in a serialized manner. + * @param id the condition variable on which to produce the broadcast. + * @remark If no threads are waiting on the condition variable, nothing happens. + */ +CORE_DECLARE(status_t) cond_broadcast(cond_id id); + +/** + * Destroy the condition variable and free the associated memory. + * @param id the condition variable to destroy. + */ +CORE_DECLARE(status_t) cond_delete(cond_id id); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_COND_H__ */ diff --git a/lib/core/include/core_debug.h b/lib/core/include/core_debug.h new file mode 100644 index 0000000000..e778dc447d --- /dev/null +++ b/lib/core/include/core_debug.h @@ -0,0 +1,226 @@ +#ifndef __CORE_DEBUG_H__ +#define __CORE_DEBUG_H__ + +#include "core.h" +#include "core_time.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef TRACE_MODULE +int TRACE_MODULE; +#endif + +extern int g_trace_mask; + +#define trace_level_set(__level) (TRACE_MODULE = __level); + +#define D_MSG_TYPE_NONE 0 +#define D_MSG_TYPE_RAW 1 +#define D_MSG_TYPE_TRACE 2 +#define D_MSG_TYPE_LOG 3 +#define D_MSG_TYPE_ASSERT 4 + +#define D_MSG_TO_CONSOLE 0x00000001 +#define D_MSG_TO_STDOUT 0x00000002 +#define D_MSG_TO_SYSLOG 0x00000004 +#define D_MSG_TO_LOGD 0x00000008 +#define D_MSG_TO_ALL (D_MSG_TO_CONSOLE | D_MSG_TO_STDOUT | \ + D_MSG_TO_SYSLOG | D_MSG_TO_LOGD) + +#define D_LOG_LEVEL_NONE 0 +#define D_LOG_LEVEL_FATAL 1 +#define D_LOG_LEVEL_ERROR 2 +#define D_LOG_LEVEL_WARN 3 +#define D_LOG_LEVEL_INFO 4 +#define D_LOG_LEVEL_FULL D_LOG_LEVEL_INFO + +CORE_DECLARE(int) d_msg(int tp, int lv, c_time_t t, char *fn, int ln, + char *fmt, ...); + +/* if C99 supported */ +#if (defined _ISOC99_SOURCE || defined _ISOC9X_SOURCE \ + || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) + +/** + * Use for printing message. This always print out the message. + */ +#define d_print(fmt, ...) \ + d_msg(D_MSG_TYPE_RAW, 0, 0, NULL, 0, fmt, ## __VA_ARGS__) + +#define __MAX_HEX_BUF 128 + +/** + * Use for printing binary buffer as printable hex string. This always + * print out the message. + */ +#define d_print_hex(__buf, __buflen) do { \ + int __i = 0, __l, __off = 0; \ + char __hex[__MAX_HEX_BUF*2+__MAX_HEX_BUF/4+__MAX_HEX_BUF/32+4], *__p; \ + d_print("%d bytes hex:\r\n", __buflen); \ + while (__off < (__buflen)) { \ + __p = __hex; __p[0] = 0; \ + __l = ((__buflen) - __off) > __MAX_HEX_BUF ? \ + __MAX_HEX_BUF : (__buflen) - __off; \ + for (__i = 0; __i < __l; __i++) { \ + __p += sprintf(__p, "%02x", ((char*)(__buf))[__off+__i] & 0xff); \ + if ((__i & 0x1f) == 31) \ + __p += sprintf(__p, "\r\n"); \ + else if ((__i & 0x3) == 3) \ + __p += sprintf(__p, " "); \ + } \ + __off += __l; \ + d_print(__hex); \ + } \ + if (__i & 0x1f) d_print("\r\n"); \ +} while (0) + +/** + * Use for trace. + * Trace message shall be shown only if trace level is set equal or higher + * than __level. + */ +#define d_trace(__level, fmt, ...) \ + (!g_trace_mask || TRACE_MODULE < __level ? 0 : \ + d_msg(D_MSG_TYPE_TRACE, 0, time_now(), NULL, 0, fmt, ## __VA_ARGS__)) + +/** + * Use for trace binary buffer as printable hex string . + * Trace message shall be shown only if trace level is set equal or higher + * than __level. + */ +#define d_trace_hex(__level, __buf, __buflen) do { \ + if (g_trace_mask && TRACE_MODULE >= __level) \ + d_print_hex(__buf, __buflen); \ +} while (0) + +/** + * Informative log. + * If log level is larger than 4, + * this message is logged with informative format. + */ +#define d_info(fmt, ...) \ + d_msg(D_MSG_TYPE_LOG, D_LOG_LEVEL_INFO, time_now(), \ + __FILE__, __LINE__, fmt, ## __VA_ARGS__) + +/** + * Informative log. + * If log level is larger than 3, + * this message is logged with warning format. + */ +#define d_warn(fmt, ...) \ + d_msg(D_MSG_TYPE_LOG, D_LOG_LEVEL_WARN, time_now(), \ + __FILE__, __LINE__, fmt, ## __VA_ARGS__) + +/** + * Error log. + * If log level is larger than 2, + * this message is logged with error format. + */ +#define d_error(fmt, ...) \ + d_msg(D_MSG_TYPE_LOG, D_LOG_LEVEL_ERROR, time_now(), \ + __FILE__, __LINE__, fmt, ## __VA_ARGS__) + +/** + * Fatal error log. + * If log level is larger than 1, + * this message is logged with fatal error format. + */ +#define d_fatal(fmt, ...) \ + d_msg(D_MSG_TYPE_LOG, D_LOG_LEVEL_FATAL, time_now(), \ + __FILE__, __LINE__, fmt, ## __VA_ARGS__) + +/** + * Assertion + * this message is logged with assertion format. + */ +#define d_assert(cond, expr, fmt, ...) \ + if (!(cond)) { \ + d_msg(D_MSG_TYPE_ASSERT, 0, time_now(), __FILE__, __LINE__, \ + "!("#cond"). "fmt, ## __VA_ARGS__); \ + expr; \ + } + +#else /* C99 */ + +#define d_print + +#define d_trace + +#define d_info +#define d_warn +#define d_error +#define d_fatal + +#define d_assert + +#endif /* C99 */ + +void d_msg_init(); + +void d_msg_final(); + +void d_msg_register_console(int console_fd); + +void d_msg_deregister_console(); + +void d_msg_to(int to, int on_off); + +int d_msg_get_to(); + +/** + * Turn on log partially. + * level 4: d_fatal, d_error, d_warn, d_info + * level 3: d_fatal, d_error, d_warn + * level 2: d_fatal, d_error + * level 1: d_fatal + * level 0: none + */ +void d_log_set_level(int to, int level); + +int d_log_get_level(int to); + +/** + * Turn on log fully. + * All of d_info, d_warn, d_error and d_fatal will be shown. + * Equivalent to log_level(4). + */ +void d_log_full(int to); + +/** + * Turn off log fully. + * All log will not be shown. + * Equivalent to log_level(0). + */ +void d_log_off(int to); + +/** + * Turn on trace mask globally. + */ +void d_trace_global_on(); + +/** + * Turn off trace mask globally. + * Any trace of any module will not be shown although some trace module is + * turned on. + */ +void d_trace_global_off(); + +/** + * Turn on trace of specifed module with level. */ +void d_trace_level(int *mod_name, int level); + +/** + * Turn off trace of specifed module. + * Equivalent to trace_level(0). + */ +void d_trace_off(int *mod_name); + +#define D_LOGD_IPC_PATH "/tmp/dlogmesg" + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_DEBUG_H__ */ diff --git a/lib/core/include/core_errno.h b/lib/core/include/core_errno.h new file mode 100644 index 0000000000..593d6fab79 --- /dev/null +++ b/lib/core/include/core_errno.h @@ -0,0 +1,1309 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CORE_ERRNO_H__ +#define __CORE_ERRNO_H__ + +/** + * @file core_errno.h + * @brief CORE Error Codes + */ + +#include "core.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup core_errno Error Codes + * @ingroup CORE + * @{ + */ + +/** + * Type for specifying an error or status code. + */ +typedef int status_t; + +/** + * Return a human readable string describing the specified error. + * @param statcode The error code the get a string for. + * @param buf A buffer to hold the error string. + * @param bufsize Size of the buffer to hold the string. + */ +CORE_DECLARE(char *) core_strerror(status_t statcode, char *buf, + size_t bufsize); + +#if defined(DOXYGEN) +/** + * @def FROM_OS_ERROR(os_err_type syserr) + * Fold a platform specific error into an STATUS_T code. + * @return STATUS_T + * @param e The platform os error code. + * @warning macro implementation; the syserr argument may be evaluated + * multiple times. + */ +#define FROM_OS_ERROR(e) (e == 0 ? CORE_OK : e + OS_START_SYSERR) + +/** + * @def TO_OS_ERROR(STATUS_T statcode) + * @return os_err_type + * Fold an STATUS_T code back to the native platform defined error. + * @param e The STATUS_T folded platform os error code. + * @warning macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by get_os_error + * or FROM_OS_ERROR, the results are undefined. + */ +#define TO_OS_ERROR(e) (e == 0 ? CORE_OK : e - OS_START_SYSERR) + +/** @def get_os_error() + * @return STATUS_T the last platform error, folded into STATUS_T, on most platforms + * @remark This retrieves errno, or calls a GetLastError() style function, and + * folds it with FROM_OS_ERROR. Some platforms (such as OS2) have no + * such mechanism, so this call may be unsupported. Do NOT use this + * call for socket errors from socket, send, recv etc! + */ + +/** @def set_os_error(e) + * Reset the last platform error, unfolded from an STATUS_T, on some platforms + * @param e The OS error folded in a prior call to FROM_OS_ERROR() + * @warning This is a macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by get_os_error + * or FROM_OS_ERROR, the results are undefined. This macro sets + * errno, or calls a SetLastError() style function, unfolding statcode + * with TO_OS_ERROR. Some platforms (such as OS2) have no such + * mechanism, so this call may be unsupported. + */ + +/** @def get_netos_error() + * Return the last socket error, folded into STATUS_T, on all platforms + * @remark This retrieves errno or calls a GetLastSocketError() style function, + * and folds it with FROM_OS_ERROR. + */ + +/** @def set_netos_error(e) + * Reset the last socket error, unfolded from an STATUS_T + * @param e The socket error folded in a prior call to FROM_OS_ERROR() + * @warning This is a macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by get_os_error + * or FROM_OS_ERROR, the results are undefined. This macro sets + * errno, or calls a WSASetLastError() style function, unfolding + * socketcode with TO_OS_ERROR. + */ + +#endif /* defined(DOXYGEN) */ + +/** + * OS_START_ERROR is where the CORE specific error values start. + */ +#define OS_START_ERROR 20000 +/** + * OS_ERRSPACE_SIZE is the maximum number of errors you can fit + * into one of the error/status ranges below -- except for + * OS_START_USERERR, which see. + */ +#define OS_ERRSPACE_SIZE 50000 +/** + * UTIL_ERRSPACE_SIZE is the size of the space that is reserved for + * use within core-util. This space is reserved above that used by CORE + * internally. + * @note This number MUST be smaller than OS_ERRSPACE_SIZE by a + * large enough amount that CORE has sufficient room for it's + * codes. + */ +#define UTIL_ERRSPACE_SIZE 20000 +/** + * OS_START_STATUS is where the CORE specific status codes start. + */ +#define OS_START_STATUS (OS_START_ERROR + OS_ERRSPACE_SIZE) +/** + * UTIL_START_STATUS is where CORE-Util starts defining it's + * status codes. + */ +#define UTIL_START_STATUS (OS_START_STATUS + \ + (OS_ERRSPACE_SIZE - UTIL_ERRSPACE_SIZE)) +/** + * OS_START_USERERR are reserved for applications that use CORE that + * layer their own error codes along with CORE's. Note that the + * error immediately following this one is set ten times farther + * away than usual, so that users of core have a lot of room in + * which to declare custom error codes. + * + * In general applications should try and create unique error codes. To try + * and assist in finding suitable ranges of numbers to use, the following + * ranges are known to be used by the listed applications. If your + * application defines error codes please advise the range of numbers it + * uses to dev@core.apache.org for inclusion in this list. + * + * Ranges shown are in relation to OS_START_USERERR + * + * Subversion - Defined ranges, of less than 100, at intervals of 5000 + * starting at an offset of 5000, e.g. + * +5000 to 5100, +10000 to 10100 + */ +#define OS_START_USERERR (OS_START_STATUS + OS_ERRSPACE_SIZE) +/** + * OS_START_USEERR is obsolete, defined for compatibility only. + * Use OS_START_USERERR instead. + */ +#define OS_START_USEERR OS_START_USERERR +/** + * OS_START_CANONERR is where CORE versions of errno values are defined + * on systems which don't have the corresponding errno. + */ +#define OS_START_CANONERR (OS_START_USERERR \ + + (OS_ERRSPACE_SIZE * 10)) +/** + * OS_START_EAIERR folds EAI_ error codes from getaddrinfo() into + * STATUS_T values. + */ +#define OS_START_EAIERR (OS_START_CANONERR + OS_ERRSPACE_SIZE) +/** + * OS_START_SYSERR folds platform-specific system error values into + * STATUS_T values. + */ +#define OS_START_SYSERR (OS_START_EAIERR + OS_ERRSPACE_SIZE) + +/** + * @defgroup CORE_ERROR_map CORE Error Space + *
+ * The following attempts to show the relation of the various constants
+ * used for mapping CORE Status codes.
+ *
+ *       0
+ *
+ *  20,000     OS_START_ERROR
+ *
+ *         + OS_ERRSPACE_SIZE (50,000)
+ *
+ *  70,000      OS_START_STATUS
+ *
+ *         + OS_ERRSPACE_SIZE - UTIL_ERRSPACE_SIZE (30,000)
+ *
+ * 100,000      UTIL_START_STATUS
+ *
+ *         + UTIL_ERRSPACE_SIZE (20,000)
+ *
+ * 120,000      OS_START_USERERR
+ *
+ *         + 10 x OS_ERRSPACE_SIZE (50,000 * 10)
+ *
+ * 620,000      OS_START_CANONERR
+ *
+ *         + OS_ERRSPACE_SIZE (50,000)
+ *
+ * 670,000      OS_START_EAIERR
+ *
+ *         + OS_ERRSPACE_SIZE (50,000)
+ *
+ * 720,000      OS_START_SYSERR
+ *
+ * 
+ */ + +/** no error. */ +#define CORE_OK 0 +#define CORE_ERROR -1 + +/** + * @defgroup CORE_Error CORE Error Values + *
+ * CORE ERROR VALUES
+ * CORE_ENOSTAT      CORE was unable to perform a stat on the file
+ * CORE_ENOPOOL      CORE was not provided a pool with which to allocate memory
+ * CORE_EBADDATE     CORE was given an invalid date
+ * CORE_EINVALSOCK   CORE was given an invalid socket
+ * CORE_ENOPROC      CORE was not given a process structure
+ * CORE_ENOTIME      CORE was not given a time structure
+ * CORE_ENODIR       CORE was not given a directory structure
+ * CORE_ENOLOCK      CORE was not given a lock structure
+ * CORE_ENOPOLL      CORE was not given a poll structure
+ * CORE_ENOSOCKET    CORE was not given a socket
+ * CORE_ENOTHREAD    CORE was not given a thread structure
+ * CORE_ENOTHDKEY    CORE was not given a thread key structure
+ * CORE_ENOSHMAVAIL  There is no more shared memory available
+ * CORE_EDSOOPEN     CORE was unable to open the dso object.  For more
+ *                  information call dso_error().
+ * CORE_EGENERAL     General failure (specific information not available)
+ * CORE_EBADIP       The specified IP address is invalid
+ * CORE_EBADMASK     The specified netmask is invalid
+ * CORE_ESYMNOTFOUND Could not find the requested symbol
+ * CORE_ENOTENOUGHENTROPY Not enough entropy to continue
+ * 
+ * + *
+ * CORE STATUS VALUES
+ * CORE_INCHILD        Program is currently executing in the child
+ * CORE_INPARENT       Program is currently executing in the parent
+ * CORE_DETACH         The thread is detached
+ * CORE_NOTDETACH      The thread is not detached
+ * CORE_CHILD_DONE     The child has finished executing
+ * CORE_CHILD_NOTDONE  The child has not finished executing
+ * CORE_TIMEUP         The operation did not finish before the timeout
+ * CORE_INCOMPLETE     The operation was incomplete although some processing
+ *                    was performed and the results are partially valid
+ * CORE_BADCH          Getopt found an option not in the option string
+ * CORE_BADARG         Getopt found an option that is missing an argument
+ *                    and an argument was specified in the option string
+ * CORE_EOF            CORE has encountered the end of the file
+ * CORE_NOTFOUND       CORE was unable to find the socket in the poll structure
+ * CORE_ANONYMOUS      CORE is using anonymous shared memory
+ * CORE_FILEBASED      CORE is using a file name as the key to the shared memory
+ * CORE_KEYBASED       CORE is using a shared key as the key to the shared memory
+ * CORE_EINIT          Ininitalizer value.  If no option has been found, but
+ *                    the status variable requires a value, this should be used
+ * CORE_ENOTIMPL       The CORE function has not been implemented on this
+ *                    platform, either because nobody has gotten to it yet,
+ *                    or the function is impossible on this platform.
+ * CORE_EMISMATCH      Two passwords do not match.
+ * CORE_EABSOLUTE      The given path was absolute.
+ * CORE_ERELATIVE      The given path was relative.
+ * CORE_EINCOMPLETE    The given path was neither relative nor absolute.
+ * CORE_EABOVEROOT     The given path was above the root path.
+ * CORE_EBUSY          The given lock was busy.
+ * CORE_EPROC_UNKNOWN  The given process wasn't recognized by CORE
+ * 
+ * @{ + */ +/** @see STATUS_IS_ENOSTAT */ +#define CORE_ENOSTAT (OS_START_ERROR + 1) +/** @see STATUS_IS_ENOPOOL */ +#define CORE_ENOPOOL (OS_START_ERROR + 2) +/* empty slot: +3 */ +/** @see STATUS_IS_EBADDATE */ +#define CORE_EBADDATE (OS_START_ERROR + 4) +/** @see STATUS_IS_EINVALSOCK */ +#define CORE_EINVALSOCK (OS_START_ERROR + 5) +/** @see STATUS_IS_ENOPROC */ +#define CORE_ENOPROC (OS_START_ERROR + 6) +/** @see STATUS_IS_ENOTIME */ +#define CORE_ENOTIME (OS_START_ERROR + 7) +/** @see STATUS_IS_ENODIR */ +#define CORE_ENODIR (OS_START_ERROR + 8) +/** @see STATUS_IS_ENOLOCK */ +#define CORE_ENOLOCK (OS_START_ERROR + 9) +/** @see STATUS_IS_ENOPOLL */ +#define CORE_ENOPOLL (OS_START_ERROR + 10) +/** @see STATUS_IS_ENOSOCKET */ +#define CORE_ENOSOCKET (OS_START_ERROR + 11) +/** @see STATUS_IS_ENOTHREAD */ +#define CORE_ENOTHREAD (OS_START_ERROR + 12) +/** @see STATUS_IS_ENOTHDKEY */ +#define CORE_ENOTHDKEY (OS_START_ERROR + 13) +/** @see STATUS_IS_EGENERAL */ +#define CORE_EGENERAL (OS_START_ERROR + 14) +/** @see STATUS_IS_ENOSHMAVAIL */ +#define CORE_ENOSHMAVAIL (OS_START_ERROR + 15) +/** @see STATUS_IS_EBADIP */ +#define CORE_EBADIP (OS_START_ERROR + 16) +/** @see STATUS_IS_EBADMASK */ +#define CORE_EBADMASK (OS_START_ERROR + 17) +/* empty slot: +18 */ +/** @see STATUS_IS_EDSOPEN */ +#define CORE_EDSOOPEN (OS_START_ERROR + 19) +/** @see STATUS_IS_EABSOLUTE */ +#define CORE_EABSOLUTE (OS_START_ERROR + 20) +/** @see STATUS_IS_ERELATIVE */ +#define CORE_ERELATIVE (OS_START_ERROR + 21) +/** @see STATUS_IS_EINCOMPLETE */ +#define CORE_EINCOMPLETE (OS_START_ERROR + 22) +/** @see STATUS_IS_EABOVEROOT */ +#define CORE_EABOVEROOT (OS_START_ERROR + 23) +/** @see STATUS_IS_EBADPATH */ +#define CORE_EBADPATH (OS_START_ERROR + 24) +/** @see STATUS_IS_EPATHWILD */ +#define CORE_EPATHWILD (OS_START_ERROR + 25) +/** @see STATUS_IS_ESYMNOTFOUND */ +#define CORE_ESYMNOTFOUND (OS_START_ERROR + 26) +/** @see STATUS_IS_EPROC_UNKNOWN */ +#define CORE_EPROC_UNKNOWN (OS_START_ERROR + 27) +/** @see STATUS_IS_ENOTENOUGHENTROPY */ +#define CORE_ENOTENOUGHENTROPY (OS_START_ERROR + 28) +/** @} */ + +/** + * @defgroup STATUS_IS Status Value Tests + * @warning For any particular error condition, more than one of these tests + * may match. This is because platform-specific error codes may not + * always match the semantics of the POSIX codes these tests (and the + * corresponding CORE error codes) are named after. A notable example + * are the STATUS_IS_ENOENT and STATUS_IS_ENOTDIR tests on + * Win32 platforms. The programmer should always be aware of this and + * adjust the order of the tests accordingly. + * @{ + */ +/** + * CORE was unable to perform a stat on the file + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_ENOSTAT(s) ((s) == CORE_ENOSTAT) +/** + * CORE was not provided a pool with which to allocate memory + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_ENOPOOL(s) ((s) == CORE_ENOPOOL) +/** CORE was given an invalid date */ +#define STATUS_IS_EBADDATE(s) ((s) == CORE_EBADDATE) +/** CORE was given an invalid socket */ +#define STATUS_IS_EINVALSOCK(s) ((s) == CORE_EINVALSOCK) +/** CORE was not given a process structure */ +#define STATUS_IS_ENOPROC(s) ((s) == CORE_ENOPROC) +/** CORE was not given a time structure */ +#define STATUS_IS_ENOTIME(s) ((s) == CORE_ENOTIME) +/** CORE was not given a directory structure */ +#define STATUS_IS_ENODIR(s) ((s) == CORE_ENODIR) +/** CORE was not given a lock structure */ +#define STATUS_IS_ENOLOCK(s) ((s) == CORE_ENOLOCK) +/** CORE was not given a poll structure */ +#define STATUS_IS_ENOPOLL(s) ((s) == CORE_ENOPOLL) +/** CORE was not given a socket */ +#define STATUS_IS_ENOSOCKET(s) ((s) == CORE_ENOSOCKET) +/** CORE was not given a thread structure */ +#define STATUS_IS_ENOTHREAD(s) ((s) == CORE_ENOTHREAD) +/** CORE was not given a thread key structure */ +#define STATUS_IS_ENOTHDKEY(s) ((s) == CORE_ENOTHDKEY) +/** Generic Error which can not be put into another spot */ +#define STATUS_IS_EGENERAL(s) ((s) == CORE_EGENERAL) +/** There is no more shared memory available */ +#define STATUS_IS_ENOSHMAVAIL(s) ((s) == CORE_ENOSHMAVAIL) +/** The specified IP address is invalid */ +#define STATUS_IS_EBADIP(s) ((s) == CORE_EBADIP) +/** The specified netmask is invalid */ +#define STATUS_IS_EBADMASK(s) ((s) == CORE_EBADMASK) +/* empty slot: +18 */ +/** + * CORE was unable to open the dso object. + * For more information call dso_error(). + */ +#if defined(WIN32) +#define STATUS_IS_EDSOOPEN(s) ((s) == CORE_EDSOOPEN \ + || TO_OS_ERROR(s) == ERROR_MOD_NOT_FOUND) +#else +#define STATUS_IS_EDSOOPEN(s) ((s) == CORE_EDSOOPEN) +#endif +/** The given path was absolute. */ +#define STATUS_IS_EABSOLUTE(s) ((s) == CORE_EABSOLUTE) +/** The given path was relative. */ +#define STATUS_IS_ERELATIVE(s) ((s) == CORE_ERELATIVE) +/** The given path was neither relative nor absolute. */ +#define STATUS_IS_EINCOMPLETE(s) ((s) == CORE_EINCOMPLETE) +/** The given path was above the root path. */ +#define STATUS_IS_EABOVEROOT(s) ((s) == CORE_EABOVEROOT) +/** The given path was bad. */ +#define STATUS_IS_EBADPATH(s) ((s) == CORE_EBADPATH) +/** The given path contained wildcards. */ +#define STATUS_IS_EPATHWILD(s) ((s) == CORE_EPATHWILD) +/** Could not find the requested symbol. + * For more information call dso_error(). + */ +#if defined(WIN32) +#define STATUS_IS_ESYMNOTFOUND(s) ((s) == CORE_ESYMNOTFOUND \ + || TO_OS_ERROR(s) == ERROR_PROC_NOT_FOUND) +#else +#define STATUS_IS_ESYMNOTFOUND(s) ((s) == CORE_ESYMNOTFOUND) +#endif +/** The given process was not recognized by CORE. */ +#define STATUS_IS_EPROC_UNKNOWN(s) ((s) == CORE_EPROC_UNKNOWN) +/** CORE could not gather enough entropy to continue. */ +#define STATUS_IS_ENOTENOUGHENTROPY(s) ((s) == CORE_ENOTENOUGHENTROPY) + +/** @} */ + +/** + * @addtogroup CORE_Error + * @{ + */ +/** @see STATUS_IS_INCHILD */ +#define CORE_INCHILD (OS_START_STATUS + 1) +/** @see STATUS_IS_INPARENT */ +#define CORE_INPARENT (OS_START_STATUS + 2) +/** @see STATUS_IS_DETACH */ +#define CORE_DETACH (OS_START_STATUS + 3) +/** @see STATUS_IS_NOTDETACH */ +#define CORE_NOTDETACH (OS_START_STATUS + 4) +/** @see STATUS_IS_CHILD_DONE */ +#define CORE_CHILD_DONE (OS_START_STATUS + 5) +/** @see STATUS_IS_CHILD_NOTDONE */ +#define CORE_CHILD_NOTDONE (OS_START_STATUS + 6) +/** @see STATUS_IS_TIMEUP */ +#define CORE_TIMEUP (OS_START_STATUS + 7) +/** @see STATUS_IS_INCOMPLETE */ +#define CORE_INCOMPLETE (OS_START_STATUS + 8) +/* empty slot: +9 */ +/* empty slot: +10 */ +/* empty slot: +11 */ +/** @see STATUS_IS_BADCH */ +#define CORE_BADCH (OS_START_STATUS + 12) +/** @see STATUS_IS_BADARG */ +#define CORE_BADARG (OS_START_STATUS + 13) +/** @see STATUS_IS_EOF */ +#define CORE_EOF (OS_START_STATUS + 14) +/** @see STATUS_IS_NOTFOUND */ +#define CORE_NOTFOUND (OS_START_STATUS + 15) +/* empty slot: +16 */ +/* empty slot: +17 */ +/* empty slot: +18 */ +/** @see STATUS_IS_ANONYMOUS */ +#define CORE_ANONYMOUS (OS_START_STATUS + 19) +/** @see STATUS_IS_FILEBASED */ +#define CORE_FILEBASED (OS_START_STATUS + 20) +/** @see STATUS_IS_KEYBASED */ +#define CORE_KEYBASED (OS_START_STATUS + 21) +/** @see STATUS_IS_EINIT */ +#define CORE_EINIT (OS_START_STATUS + 22) +/** @see STATUS_IS_ENOTIMPL */ +#define CORE_ENOTIMPL (OS_START_STATUS + 23) +/** @see STATUS_IS_EMISMATCH */ +#define CORE_EMISMATCH (OS_START_STATUS + 24) +/** @see STATUS_IS_EBUSY */ +#define CORE_EBUSY (OS_START_STATUS + 25) +/** @} */ + +/** + * @addtogroup STATUS_IS + * @{ + */ +/** + * Program is currently executing in the child + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code */ +#define STATUS_IS_INCHILD(s) ((s) == CORE_INCHILD) +/** + * Program is currently executing in the parent + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_INPARENT(s) ((s) == CORE_INPARENT) +/** + * The thread is detached + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_DETACH(s) ((s) == CORE_DETACH) +/** + * The thread is not detached + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_NOTDETACH(s) ((s) == CORE_NOTDETACH) +/** + * The child has finished executing + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_CHILD_DONE(s) ((s) == CORE_CHILD_DONE) +/** + * The child has not finished executing + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_CHILD_NOTDONE(s) ((s) == CORE_CHILD_NOTDONE) +/** + * The operation did not finish before the timeout + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_TIMEUP(s) ((s) == CORE_TIMEUP) +/** + * The operation was incomplete although some processing was performed + * and the results are partially valid. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_INCOMPLETE(s) ((s) == CORE_INCOMPLETE) +/* empty slot: +9 */ +/* empty slot: +10 */ +/* empty slot: +11 */ +/** + * Getopt found an option not in the option string + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_BADCH(s) ((s) == CORE_BADCH) +/** + * Getopt found an option not in the option string and an argument was + * specified in the option string + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_BADARG(s) ((s) == CORE_BADARG) +/** + * CORE has encountered the end of the file + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_EOF(s) ((s) == CORE_EOF) +/** + * CORE was unable to find the socket in the poll structure + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_NOTFOUND(s) ((s) == CORE_NOTFOUND) +/* empty slot: +16 */ +/* empty slot: +17 */ +/* empty slot: +18 */ +/** + * CORE is using anonymous shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_ANONYMOUS(s) ((s) == CORE_ANONYMOUS) +/** + * CORE is using a file name as the key to the shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_FILEBASED(s) ((s) == CORE_FILEBASED) +/** + * CORE is using a shared key as the key to the shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_KEYBASED(s) ((s) == CORE_KEYBASED) +/** + * Ininitalizer value. If no option has been found, but + * the status variable requires a value, this should be used + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_EINIT(s) ((s) == CORE_EINIT) +/** + * The CORE function has not been implemented on this + * platform, either because nobody has gotten to it yet, + * or the function is impossible on this platform. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_ENOTIMPL(s) ((s) == CORE_ENOTIMPL) +/** + * Two passwords do not match. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_EMISMATCH(s) ((s) == CORE_EMISMATCH) +/** + * The given lock was busy + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define STATUS_IS_EBUSY(s) ((s) == CORE_EBUSY) + +/** @} */ + +/** + * @addtogroup CORE_Error CORE Error Values + * @{ + */ +/* CORE CANONICAL ERROR VALUES */ +/** @see STATUS_IS_EACCES */ +#ifdef EACCES +#define CORE_EACCES EACCES +#else +#define CORE_EACCES (OS_START_CANONERR + 1) +#endif + +/** @see STATUS_IS_EEXIST */ +#ifdef EEXIST +#define CORE_EEXIST EEXIST +#else +#define CORE_EEXIST (OS_START_CANONERR + 2) +#endif + +/** @see STATUS_IS_ENAMETOOLONG */ +#ifdef ENAMETOOLONG +#define CORE_ENAMETOOLONG ENAMETOOLONG +#else +#define CORE_ENAMETOOLONG (OS_START_CANONERR + 3) +#endif + +/** @see STATUS_IS_ENOENT */ +#ifdef ENOENT +#define CORE_ENOENT ENOENT +#else +#define CORE_ENOENT (OS_START_CANONERR + 4) +#endif + +/** @see STATUS_IS_ENOTDIR */ +#ifdef ENOTDIR +#define CORE_ENOTDIR ENOTDIR +#else +#define CORE_ENOTDIR (OS_START_CANONERR + 5) +#endif + +/** @see STATUS_IS_ENOSPC */ +#ifdef ENOSPC +#define CORE_ENOSPC ENOSPC +#else +#define CORE_ENOSPC (OS_START_CANONERR + 6) +#endif + +/** @see STATUS_IS_ENOMEM */ +#ifdef ENOMEM +#define CORE_ENOMEM ENOMEM +#else +#define CORE_ENOMEM (OS_START_CANONERR + 7) +#endif + +/** @see STATUS_IS_EMFILE */ +#ifdef EMFILE +#define CORE_EMFILE EMFILE +#else +#define CORE_EMFILE (OS_START_CANONERR + 8) +#endif + +/** @see STATUS_IS_ENFILE */ +#ifdef ENFILE +#define CORE_ENFILE ENFILE +#else +#define CORE_ENFILE (OS_START_CANONERR + 9) +#endif + +/** @see STATUS_IS_EBADF */ +#ifdef EBADF +#define CORE_EBADF EBADF +#else +#define CORE_EBADF (OS_START_CANONERR + 10) +#endif + +/** @see STATUS_IS_EINVAL */ +#ifdef EINVAL +#define CORE_EINVAL EINVAL +#else +#define CORE_EINVAL (OS_START_CANONERR + 11) +#endif + +/** @see STATUS_IS_ESPIPE */ +#ifdef ESPIPE +#define CORE_ESPIPE ESPIPE +#else +#define CORE_ESPIPE (OS_START_CANONERR + 12) +#endif + +/** + * @see STATUS_IS_EAGAIN + * @warning use STATUS_IS_EAGAIN instead of just testing this value + */ +#ifdef EAGAIN +#define CORE_EAGAIN EAGAIN +#elif defined(EWOULDBLOCK) +#define CORE_EAGAIN EWOULDBLOCK +#else +#define CORE_EAGAIN (OS_START_CANONERR + 13) +#endif + +/** @see STATUS_IS_EINTR */ +#ifdef EINTR +#define CORE_EINTR EINTR +#else +#define CORE_EINTR (OS_START_CANONERR + 14) +#endif + +/** @see STATUS_IS_ENOTSOCK */ +#ifdef ENOTSOCK +#define CORE_ENOTSOCK ENOTSOCK +#else +#define CORE_ENOTSOCK (OS_START_CANONERR + 15) +#endif + +/** @see STATUS_IS_ECONNREFUSED */ +#ifdef ECONNREFUSED +#define CORE_ECONNREFUSED ECONNREFUSED +#else +#define CORE_ECONNREFUSED (OS_START_CANONERR + 16) +#endif + +/** @see STATUS_IS_EINPROGRESS */ +#ifdef EINPROGRESS +#define CORE_EINPROGRESS EINPROGRESS +#else +#define CORE_EINPROGRESS (OS_START_CANONERR + 17) +#endif + +/** + * @see STATUS_IS_ECONNABORTED + * @warning use STATUS_IS_ECONNABORTED instead of just testing this value + */ + +#ifdef ECONNABORTED +#define CORE_ECONNABORTED ECONNABORTED +#else +#define CORE_ECONNABORTED (OS_START_CANONERR + 18) +#endif + +/** @see STATUS_IS_ECONNRESET */ +#ifdef ECONNRESET +#define CORE_ECONNRESET ECONNRESET +#else +#define CORE_ECONNRESET (OS_START_CANONERR + 19) +#endif + +/** @see STATUS_IS_ETIMEDOUT + * @deprecated */ +#ifdef ETIMEDOUT +#define CORE_ETIMEDOUT ETIMEDOUT +#else +#define CORE_ETIMEDOUT (OS_START_CANONERR + 20) +#endif + +/** @see STATUS_IS_EHOSTUNREACH */ +#ifdef EHOSTUNREACH +#define CORE_EHOSTUNREACH EHOSTUNREACH +#else +#define CORE_EHOSTUNREACH (OS_START_CANONERR + 21) +#endif + +/** @see STATUS_IS_ENETUNREACH */ +#ifdef ENETUNREACH +#define CORE_ENETUNREACH ENETUNREACH +#else +#define CORE_ENETUNREACH (OS_START_CANONERR + 22) +#endif + +/** @see STATUS_IS_EFTYPE */ +#ifdef EFTYPE +#define CORE_EFTYPE EFTYPE +#else +#define CORE_EFTYPE (OS_START_CANONERR + 23) +#endif + +/** @see STATUS_IS_EPIPE */ +#ifdef EPIPE +#define CORE_EPIPE EPIPE +#else +#define CORE_EPIPE (OS_START_CANONERR + 24) +#endif + +/** @see STATUS_IS_EXDEV */ +#ifdef EXDEV +#define CORE_EXDEV EXDEV +#else +#define CORE_EXDEV (OS_START_CANONERR + 25) +#endif + +/** @see STATUS_IS_ENOTEMPTY */ +#ifdef ENOTEMPTY +#define CORE_ENOTEMPTY ENOTEMPTY +#else +#define CORE_ENOTEMPTY (OS_START_CANONERR + 26) +#endif + +/** @see STATUS_IS_EAFNOSUPPORT */ +#ifdef EAFNOSUPPORT +#define CORE_EAFNOSUPPORT EAFNOSUPPORT +#else +#define CORE_EAFNOSUPPORT (OS_START_CANONERR + 27) +#endif + +/** @} */ + +#if defined(OS2) && !defined(DOXYGEN) + +#define FROM_OS_ERROR(e) (e == 0 ? CORE_OK : e + OS_START_SYSERR) +#define TO_OS_ERROR(e) (e == 0 ? CORE_OK : e - OS_START_SYSERR) + +#define INCL_DOSERRORS +#define INCL_DOS + +/* Leave these undefined. + * OS2 doesn't rely on the errno concept. + * The API calls always return a result codes which + * should be filtered through FROM_OS_ERROR(). + * + * #define get_os_error() (FROM_OS_ERROR(GetLastError())) + * #define set_os_error(e) (SetLastError(TO_OS_ERROR(e))) + */ + +/* A special case, only socket calls require this; + */ +#define get_netos_error() (FROM_OS_ERROR(errno)) +#define set_netos_error(e) (errno = TO_OS_ERROR(e)) + +/* And this needs to be greped away for good: + */ +#define OS2_STATUS(e) (FROM_OS_ERROR(e)) + +/* These can't sit in a private header, so in spite of the extra size, + * they need to be made available here. + */ +#define SOCBASEERR 10000 +#define SOCEPERM (SOCBASEERR+1) /* Not owner */ +#define SOCESRCH (SOCBASEERR+3) /* No such process */ +#define SOCEINTR (SOCBASEERR+4) /* Interrupted system call */ +#define SOCENXIO (SOCBASEERR+6) /* No such device or address */ +#define SOCEBADF (SOCBASEERR+9) /* Bad file number */ +#define SOCEACCES (SOCBASEERR+13) /* Permission denied */ +#define SOCEFAULT (SOCBASEERR+14) /* Bad address */ +#define SOCEINVAL (SOCBASEERR+22) /* Invalid argument */ +#define SOCEMFILE (SOCBASEERR+24) /* Too many open files */ +#define SOCEPIPE (SOCBASEERR+32) /* Broken pipe */ +#define SOCEOS2ERR (SOCBASEERR+100) /* OS/2 Error */ +#define SOCEWOULDBLOCK (SOCBASEERR+35) /* Operation would block */ +#define SOCEINPROGRESS (SOCBASEERR+36) /* Operation now in progress */ +#define SOCEALREADY (SOCBASEERR+37) /* Operation already in progress */ +#define SOCENOTSOCK (SOCBASEERR+38) /* Socket operation on non-socket */ +#define SOCEDESTADDRREQ (SOCBASEERR+39) /* Destination address required */ +#define SOCEMSGSIZE (SOCBASEERR+40) /* Message too long */ +#define SOCEPROTOTYPE (SOCBASEERR+41) /* Protocol wrong type for socket */ +#define SOCENOPROTOOPT (SOCBASEERR+42) /* Protocol not available */ +#define SOCEPROTONOSUPPORT (SOCBASEERR+43) /* Protocol not supported */ +#define SOCESOCKTNOSUPPORT (SOCBASEERR+44) /* Socket type not supported */ +#define SOCEOPNOTSUPP (SOCBASEERR+45) /* Operation not supported on socket */ +#define SOCEPFNOSUPPORT (SOCBASEERR+46) /* Protocol family not supported */ +#define SOCEAFNOSUPPORT (SOCBASEERR+47) /* Address family not supported by protocol family */ +#define SOCEADDRINUSE (SOCBASEERR+48) /* Address already in use */ +#define SOCEADDRNOTAVAIL (SOCBASEERR+49) /* Can't assign requested address */ +#define SOCENETDOWN (SOCBASEERR+50) /* Network is down */ +#define SOCENETUNREACH (SOCBASEERR+51) /* Network is unreachable */ +#define SOCENETRESET (SOCBASEERR+52) /* Network dropped connection on reset */ +#define SOCECONNABORTED (SOCBASEERR+53) /* Software caused connection abort */ +#define SOCECONNRESET (SOCBASEERR+54) /* Connection reset by peer */ +#define SOCENOBUFS (SOCBASEERR+55) /* No buffer space available */ +#define SOCEISCONN (SOCBASEERR+56) /* Socket is already connected */ +#define SOCENOTCONN (SOCBASEERR+57) /* Socket is not connected */ +#define SOCESHUTDOWN (SOCBASEERR+58) /* Can't send after socket shutdown */ +#define SOCETOOMANYREFS (SOCBASEERR+59) /* Too many references: can't splice */ +#define SOCETIMEDOUT (SOCBASEERR+60) /* Connection timed out */ +#define SOCECONNREFUSED (SOCBASEERR+61) /* Connection refused */ +#define SOCELOOP (SOCBASEERR+62) /* Too many levels of symbolic links */ +#define SOCENAMETOOLONG (SOCBASEERR+63) /* File name too long */ +#define SOCEHOSTDOWN (SOCBASEERR+64) /* Host is down */ +#define SOCEHOSTUNREACH (SOCBASEERR+65) /* No route to host */ +#define SOCENOTEMPTY (SOCBASEERR+66) /* Directory not empty */ + +/* CORE CANONICAL ERROR TESTS */ +#define STATUS_IS_EACCES(s) ((s) == CORE_EACCES \ + || (s) == OS_START_SYSERR + ERROR_ACCESS_DENIED \ + || (s) == OS_START_SYSERR + ERROR_SHARING_VIOLATION) +#define STATUS_IS_EEXIST(s) ((s) == CORE_EEXIST \ + || (s) == OS_START_SYSERR + ERROR_OPEN_FAILED \ + || (s) == OS_START_SYSERR + ERROR_FILE_EXISTS \ + || (s) == OS_START_SYSERR + ERROR_ALREADY_EXISTS \ + || (s) == OS_START_SYSERR + ERROR_ACCESS_DENIED) +#define STATUS_IS_ENAMETOOLONG(s) ((s) == CORE_ENAMETOOLONG \ + || (s) == OS_START_SYSERR + ERROR_FILENAME_EXCED_RANGE \ + || (s) == OS_START_SYSERR + SOCENAMETOOLONG) +#define STATUS_IS_ENOENT(s) ((s) == CORE_ENOENT \ + || (s) == OS_START_SYSERR + ERROR_FILE_NOT_FOUND \ + || (s) == OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == OS_START_SYSERR + ERROR_NO_MORE_FILES \ + || (s) == OS_START_SYSERR + ERROR_OPEN_FAILED) +#define STATUS_IS_ENOTDIR(s) ((s) == CORE_ENOTDIR) +#define STATUS_IS_ENOSPC(s) ((s) == CORE_ENOSPC \ + || (s) == OS_START_SYSERR + ERROR_DISK_FULL) +#define STATUS_IS_ENOMEM(s) ((s) == CORE_ENOMEM) +#define STATUS_IS_EMFILE(s) ((s) == CORE_EMFILE \ + || (s) == OS_START_SYSERR + ERROR_TOO_MANY_OPEN_FILES) +#define STATUS_IS_ENFILE(s) ((s) == CORE_ENFILE) +#define STATUS_IS_EBADF(s) ((s) == CORE_EBADF \ + || (s) == OS_START_SYSERR + ERROR_INVALID_HANDLE) +#define STATUS_IS_EINVAL(s) ((s) == CORE_EINVAL \ + || (s) == OS_START_SYSERR + ERROR_INVALID_PARAMETER \ + || (s) == OS_START_SYSERR + ERROR_INVALID_FUNCTION) +#define STATUS_IS_ESPIPE(s) ((s) == CORE_ESPIPE \ + || (s) == OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define STATUS_IS_EAGAIN(s) ((s) == CORE_EAGAIN \ + || (s) == OS_START_SYSERR + ERROR_NO_DATA \ + || (s) == OS_START_SYSERR + SOCEWOULDBLOCK \ + || (s) == OS_START_SYSERR + ERROR_LOCK_VIOLATION) +#define STATUS_IS_EINTR(s) ((s) == CORE_EINTR \ + || (s) == OS_START_SYSERR + SOCEINTR) +#define STATUS_IS_ENOTSOCK(s) ((s) == CORE_ENOTSOCK \ + || (s) == OS_START_SYSERR + SOCENOTSOCK) +#define STATUS_IS_ECONNREFUSED(s) ((s) == CORE_ECONNREFUSED \ + || (s) == OS_START_SYSERR + SOCECONNREFUSED) +#define STATUS_IS_EINPROGRESS(s) ((s) == CORE_EINPROGRESS \ + || (s) == OS_START_SYSERR + SOCEINPROGRESS) +#define STATUS_IS_ECONNABORTED(s) ((s) == CORE_ECONNABORTED \ + || (s) == OS_START_SYSERR + SOCECONNABORTED) +#define STATUS_IS_ECONNRESET(s) ((s) == CORE_ECONNRESET \ + || (s) == OS_START_SYSERR + SOCECONNRESET) +/* XXX deprecated */ +#define STATUS_IS_ETIMEDOUT(s) ((s) == CORE_ETIMEDOUT \ + || (s) == OS_START_SYSERR + SOCETIMEDOUT) +#undef STATUS_IS_TIMEUP +#define STATUS_IS_TIMEUP(s) ((s) == CORE_TIMEUP \ + || (s) == OS_START_SYSERR + SOCETIMEDOUT) +#define STATUS_IS_EHOSTUNREACH(s) ((s) == CORE_EHOSTUNREACH \ + || (s) == OS_START_SYSERR + SOCEHOSTUNREACH) +#define STATUS_IS_ENETUNREACH(s) ((s) == CORE_ENETUNREACH \ + || (s) == OS_START_SYSERR + SOCENETUNREACH) +#define STATUS_IS_EFTYPE(s) ((s) == CORE_EFTYPE) +#define STATUS_IS_EPIPE(s) ((s) == CORE_EPIPE \ + || (s) == OS_START_SYSERR + ERROR_BROKEN_PIPE \ + || (s) == OS_START_SYSERR + SOCEPIPE) +#define STATUS_IS_EXDEV(s) ((s) == CORE_EXDEV \ + || (s) == OS_START_SYSERR + ERROR_NOT_SAME_DEVICE) +#define STATUS_IS_ENOTEMPTY(s) ((s) == CORE_ENOTEMPTY \ + || (s) == OS_START_SYSERR + ERROR_DIR_NOT_EMPTY \ + || (s) == OS_START_SYSERR + ERROR_ACCESS_DENIED) +#define STATUS_IS_EAFNOSUPPORT(s) ((s) == CORE_AFNOSUPPORT \ + || (s) == OS_START_SYSERR + SOCEAFNOSUPPORT) + +/* + Sorry, too tired to wrap this up for OS2... feel free to + fit the following into their best matches. + + { ERROR_NO_SIGNAL_SENT, ESRCH }, + { SOCEALREADY, EALREADY }, + { SOCEDESTADDRREQ, EDESTADDRREQ }, + { SOCEMSGSIZE, EMSGSIZE }, + { SOCEPROTOTYPE, EPROTOTYPE }, + { SOCENOPROTOOPT, ENOPROTOOPT }, + { SOCEPROTONOSUPPORT, EPROTONOSUPPORT }, + { SOCESOCKTNOSUPPORT, ESOCKTNOSUPPORT }, + { SOCEOPNOTSUPP, EOPNOTSUPP }, + { SOCEPFNOSUPPORT, EPFNOSUPPORT }, + { SOCEADDRINUSE, EADDRINUSE }, + { SOCEADDRNOTAVAIL, EADDRNOTAVAIL }, + { SOCENETDOWN, ENETDOWN }, + { SOCENETRESET, ENETRESET }, + { SOCENOBUFS, ENOBUFS }, + { SOCEISCONN, EISCONN }, + { SOCENOTCONN, ENOTCONN }, + { SOCESHUTDOWN, ESHUTDOWN }, + { SOCETOOMANYREFS, ETOOMANYREFS }, + { SOCELOOP, ELOOP }, + { SOCEHOSTDOWN, EHOSTDOWN }, + { SOCENOTEMPTY, ENOTEMPTY }, + { SOCEPIPE, EPIPE } +*/ + +#elif defined(WIN32) && !defined(DOXYGEN) /* !defined(OS2) */ + +#define FROM_OS_ERROR(e) (e == 0 ? CORE_OK : e + OS_START_SYSERR) +#define TO_OS_ERROR(e) (e == 0 ? CORE_OK : e - OS_START_SYSERR) + +#define get_os_error() (FROM_OS_ERROR(GetLastError())) +#define set_os_error(e) (SetLastError(TO_OS_ERROR(e))) + +/* A special case, only socket calls require this: + */ +#define get_netos_error() (FROM_OS_ERROR(WSAGetLastError())) +#define set_netos_error(e) (WSASetLastError(TO_OS_ERROR(e))) + +/* CORE CANONICAL ERROR TESTS */ +#define STATUS_IS_EACCES(s) ((s) == CORE_EACCES \ + || (s) == OS_START_SYSERR + ERROR_ACCESS_DENIED \ + || (s) == OS_START_SYSERR + ERROR_CANNOT_MAKE \ + || (s) == OS_START_SYSERR + ERROR_CURRENT_DIRECTORY \ + || (s) == OS_START_SYSERR + ERROR_DRIVE_LOCKED \ + || (s) == OS_START_SYSERR + ERROR_FAIL_I24 \ + || (s) == OS_START_SYSERR + ERROR_LOCK_VIOLATION \ + || (s) == OS_START_SYSERR + ERROR_LOCK_FAILED \ + || (s) == OS_START_SYSERR + ERROR_NOT_LOCKED \ + || (s) == OS_START_SYSERR + ERROR_NETWORK_ACCESS_DENIED \ + || (s) == OS_START_SYSERR + ERROR_SHARING_VIOLATION) +#define STATUS_IS_EEXIST(s) ((s) == CORE_EEXIST \ + || (s) == OS_START_SYSERR + ERROR_FILE_EXISTS \ + || (s) == OS_START_SYSERR + ERROR_ALREADY_EXISTS) +#define STATUS_IS_ENAMETOOLONG(s) ((s) == CORE_ENAMETOOLONG \ + || (s) == OS_START_SYSERR + ERROR_FILENAME_EXCED_RANGE \ + || (s) == OS_START_SYSERR + WSAENAMETOOLONG) +#define STATUS_IS_ENOENT(s) ((s) == CORE_ENOENT \ + || (s) == OS_START_SYSERR + ERROR_FILE_NOT_FOUND \ + || (s) == OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == OS_START_SYSERR + ERROR_OPEN_FAILED \ + || (s) == OS_START_SYSERR + ERROR_NO_MORE_FILES) +#define STATUS_IS_ENOTDIR(s) ((s) == CORE_ENOTDIR \ + || (s) == OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == OS_START_SYSERR + ERROR_BAD_NETPATH \ + || (s) == OS_START_SYSERR + ERROR_BAD_NET_NAME \ + || (s) == OS_START_SYSERR + ERROR_BAD_PATHNAME \ + || (s) == OS_START_SYSERR + ERROR_INVALID_DRIVE) +#define STATUS_IS_ENOSPC(s) ((s) == CORE_ENOSPC \ + || (s) == OS_START_SYSERR + ERROR_DISK_FULL) +#define STATUS_IS_ENOMEM(s) ((s) == CORE_ENOMEM \ + || (s) == OS_START_SYSERR + ERROR_ARENA_TRASHED \ + || (s) == OS_START_SYSERR + ERROR_NOT_ENOUGH_MEMORY \ + || (s) == OS_START_SYSERR + ERROR_INVALID_BLOCK \ + || (s) == OS_START_SYSERR + ERROR_NOT_ENOUGH_QUOTA \ + || (s) == OS_START_SYSERR + ERROR_OUTOFMEMORY) +#define STATUS_IS_EMFILE(s) ((s) == CORE_EMFILE \ + || (s) == OS_START_SYSERR + ERROR_TOO_MANY_OPEN_FILES) +#define STATUS_IS_ENFILE(s) ((s) == CORE_ENFILE) +#define STATUS_IS_EBADF(s) ((s) == CORE_EBADF \ + || (s) == OS_START_SYSERR + ERROR_INVALID_HANDLE \ + || (s) == OS_START_SYSERR + ERROR_INVALID_TARGET_HANDLE) +#define STATUS_IS_EINVAL(s) ((s) == CORE_EINVAL \ + || (s) == OS_START_SYSERR + ERROR_INVALID_ACCESS \ + || (s) == OS_START_SYSERR + ERROR_INVALID_DATA \ + || (s) == OS_START_SYSERR + ERROR_INVALID_FUNCTION \ + || (s) == OS_START_SYSERR + ERROR_INVALID_HANDLE \ + || (s) == OS_START_SYSERR + ERROR_INVALID_PARAMETER \ + || (s) == OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define STATUS_IS_ESPIPE(s) ((s) == CORE_ESPIPE \ + || (s) == OS_START_SYSERR + ERROR_SEEK_ON_DEVICE \ + || (s) == OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define STATUS_IS_EAGAIN(s) ((s) == CORE_EAGAIN \ + || (s) == OS_START_SYSERR + ERROR_NO_DATA \ + || (s) == OS_START_SYSERR + ERROR_NO_PROC_SLOTS \ + || (s) == OS_START_SYSERR + ERROR_NESTING_NOT_ALLOWED \ + || (s) == OS_START_SYSERR + ERROR_MAX_THRDS_REACHED \ + || (s) == OS_START_SYSERR + ERROR_LOCK_VIOLATION \ + || (s) == OS_START_SYSERR + WSAEWOULDBLOCK) +#define STATUS_IS_EINTR(s) ((s) == CORE_EINTR \ + || (s) == OS_START_SYSERR + WSAEINTR) +#define STATUS_IS_ENOTSOCK(s) ((s) == CORE_ENOTSOCK \ + || (s) == OS_START_SYSERR + WSAENOTSOCK) +#define STATUS_IS_ECONNREFUSED(s) ((s) == CORE_ECONNREFUSED \ + || (s) == OS_START_SYSERR + WSAECONNREFUSED) +#define STATUS_IS_EINPROGRESS(s) ((s) == CORE_EINPROGRESS \ + || (s) == OS_START_SYSERR + WSAEINPROGRESS) +#define STATUS_IS_ECONNABORTED(s) ((s) == CORE_ECONNABORTED \ + || (s) == OS_START_SYSERR + WSAECONNABORTED) +#define STATUS_IS_ECONNRESET(s) ((s) == CORE_ECONNRESET \ + || (s) == OS_START_SYSERR + ERROR_NETNAME_DELETED \ + || (s) == OS_START_SYSERR + WSAECONNRESET) +/* XXX deprecated */ +#define STATUS_IS_ETIMEDOUT(s) ((s) == CORE_ETIMEDOUT \ + || (s) == OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == OS_START_SYSERR + WAIT_TIMEOUT) +#undef STATUS_IS_TIMEUP +#define STATUS_IS_TIMEUP(s) ((s) == CORE_TIMEUP \ + || (s) == OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == OS_START_SYSERR + WAIT_TIMEOUT) +#define STATUS_IS_EHOSTUNREACH(s) ((s) == CORE_EHOSTUNREACH \ + || (s) == OS_START_SYSERR + WSAEHOSTUNREACH) +#define STATUS_IS_ENETUNREACH(s) ((s) == CORE_ENETUNREACH \ + || (s) == OS_START_SYSERR + WSAENETUNREACH) +#define STATUS_IS_EFTYPE(s) ((s) == CORE_EFTYPE \ + || (s) == OS_START_SYSERR + ERROR_EXE_MACHINE_TYPE_MISMATCH \ + || (s) == OS_START_SYSERR + ERROR_INVALID_DLL \ + || (s) == OS_START_SYSERR + ERROR_INVALID_MODULETYPE \ + || (s) == OS_START_SYSERR + ERROR_BAD_EXE_FORMAT \ + || (s) == OS_START_SYSERR + ERROR_INVALID_EXE_SIGNATURE \ + || (s) == OS_START_SYSERR + ERROR_FILE_CORRUPT \ + || (s) == OS_START_SYSERR + ERROR_BAD_FORMAT) +#define STATUS_IS_EPIPE(s) ((s) == CORE_EPIPE \ + || (s) == OS_START_SYSERR + ERROR_BROKEN_PIPE) +#define STATUS_IS_EXDEV(s) ((s) == CORE_EXDEV \ + || (s) == OS_START_SYSERR + ERROR_NOT_SAME_DEVICE) +#define STATUS_IS_ENOTEMPTY(s) ((s) == CORE_ENOTEMPTY \ + || (s) == OS_START_SYSERR + ERROR_DIR_NOT_EMPTY) +#define STATUS_IS_EAFNOSUPPORT(s) ((s) == CORE_EAFNOSUPPORT \ + || (s) == OS_START_SYSERR + WSAEAFNOSUPPORT) + +#elif defined(NETWARE) && defined(USE_WINSOCK) && !defined(DOXYGEN) /* !defined(OS2) && !defined(WIN32) */ + +#define FROM_OS_ERROR(e) (e == 0 ? CORE_OK : e + OS_START_SYSERR) +#define TO_OS_ERROR(e) (e == 0 ? CORE_OK : e - OS_START_SYSERR) + +#define get_os_error() (errno) +#define set_os_error(e) (errno = (e)) + +/* A special case, only socket calls require this: */ +#define get_netos_error() (FROM_OS_ERROR(WSAGetLastError())) +#define set_netos_error(e) (WSASetLastError(TO_OS_ERROR(e))) + +/* CORE CANONICAL ERROR TESTS */ +#define STATUS_IS_EACCES(s) ((s) == CORE_EACCES) +#define STATUS_IS_EEXIST(s) ((s) == CORE_EEXIST) +#define STATUS_IS_ENAMETOOLONG(s) ((s) == CORE_ENAMETOOLONG) +#define STATUS_IS_ENOENT(s) ((s) == CORE_ENOENT) +#define STATUS_IS_ENOTDIR(s) ((s) == CORE_ENOTDIR) +#define STATUS_IS_ENOSPC(s) ((s) == CORE_ENOSPC) +#define STATUS_IS_ENOMEM(s) ((s) == CORE_ENOMEM) +#define STATUS_IS_EMFILE(s) ((s) == CORE_EMFILE) +#define STATUS_IS_ENFILE(s) ((s) == CORE_ENFILE) +#define STATUS_IS_EBADF(s) ((s) == CORE_EBADF) +#define STATUS_IS_EINVAL(s) ((s) == CORE_EINVAL) +#define STATUS_IS_ESPIPE(s) ((s) == CORE_ESPIPE) + +#define STATUS_IS_EAGAIN(s) ((s) == CORE_EAGAIN \ + || (s) == EWOULDBLOCK \ + || (s) == OS_START_SYSERR + WSAEWOULDBLOCK) +#define STATUS_IS_EINTR(s) ((s) == CORE_EINTR \ + || (s) == OS_START_SYSERR + WSAEINTR) +#define STATUS_IS_ENOTSOCK(s) ((s) == CORE_ENOTSOCK \ + || (s) == OS_START_SYSERR + WSAENOTSOCK) +#define STATUS_IS_ECONNREFUSED(s) ((s) == CORE_ECONNREFUSED \ + || (s) == OS_START_SYSERR + WSAECONNREFUSED) +#define STATUS_IS_EINPROGRESS(s) ((s) == CORE_EINPROGRESS \ + || (s) == OS_START_SYSERR + WSAEINPROGRESS) +#define STATUS_IS_ECONNABORTED(s) ((s) == CORE_ECONNABORTED \ + || (s) == OS_START_SYSERR + WSAECONNABORTED) +#define STATUS_IS_ECONNRESET(s) ((s) == CORE_ECONNRESET \ + || (s) == OS_START_SYSERR + WSAECONNRESET) +/* XXX deprecated */ +#define STATUS_IS_ETIMEDOUT(s) ((s) == CORE_ETIMEDOUT \ + || (s) == OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == OS_START_SYSERR + WAIT_TIMEOUT) +#undef STATUS_IS_TIMEUP +#define STATUS_IS_TIMEUP(s) ((s) == CORE_TIMEUP \ + || (s) == OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == OS_START_SYSERR + WAIT_TIMEOUT) +#define STATUS_IS_EHOSTUNREACH(s) ((s) == CORE_EHOSTUNREACH \ + || (s) == OS_START_SYSERR + WSAEHOSTUNREACH) +#define STATUS_IS_ENETUNREACH(s) ((s) == CORE_ENETUNREACH \ + || (s) == OS_START_SYSERR + WSAENETUNREACH) +#define STATUS_IS_ENETDOWN(s) ((s) == OS_START_SYSERR + WSAENETDOWN) +#define STATUS_IS_EFTYPE(s) ((s) == CORE_EFTYPE) +#define STATUS_IS_EPIPE(s) ((s) == CORE_EPIPE) +#define STATUS_IS_EXDEV(s) ((s) == CORE_EXDEV) +#define STATUS_IS_ENOTEMPTY(s) ((s) == CORE_ENOTEMPTY) +#define STATUS_IS_EAFNOSUPPORT(s) ((s) == CORE_EAFNOSUPPORT \ + || (s) == OS_START_SYSERR + WSAEAFNOSUPPORT) + +#else /* !defined(NETWARE) && !defined(OS2) && !defined(WIN32) */ + +/* + * os error codes are clib error codes + */ +#define FROM_OS_ERROR(e) (e) +#define TO_OS_ERROR(e) (e) + +#define get_os_error() (errno) +#define set_os_error(e) (errno = (e)) + +/* A special case, only socket calls require this: + */ +#define get_netos_error() (errno) +#define set_netos_error(e) (errno = (e)) + +/** + * @addtogroup STATUS_IS + * @{ + */ + +/** permission denied */ +#define STATUS_IS_EACCES(s) ((s) == CORE_EACCES) +/** file exists */ +#define STATUS_IS_EEXIST(s) ((s) == CORE_EEXIST) +/** path name is too long */ +#define STATUS_IS_ENAMETOOLONG(s) ((s) == CORE_ENAMETOOLONG) +/** + * no such file or directory + * @remark + * EMVSCATLG can be returned by the automounter on z/OS for + * paths which do not exist. + */ +#ifdef EMVSCATLG +#define STATUS_IS_ENOENT(s) ((s) == CORE_ENOENT \ + || (s) == EMVSCATLG) +#else +#define STATUS_IS_ENOENT(s) ((s) == CORE_ENOENT) +#endif +/** not a directory */ +#define STATUS_IS_ENOTDIR(s) ((s) == CORE_ENOTDIR) +/** no space left on device */ +#ifdef EDQUOT +#define STATUS_IS_ENOSPC(s) ((s) == CORE_ENOSPC \ + || (s) == EDQUOT) +#else +#define STATUS_IS_ENOSPC(s) ((s) == CORE_ENOSPC) +#endif +/** not enough memory */ +#define STATUS_IS_ENOMEM(s) ((s) == CORE_ENOMEM) +/** too many open files */ +#define STATUS_IS_EMFILE(s) ((s) == CORE_EMFILE) +/** file table overflow */ +#define STATUS_IS_ENFILE(s) ((s) == CORE_ENFILE) +/** bad file # */ +#define STATUS_IS_EBADF(s) ((s) == CORE_EBADF) +/** invalid argument */ +#define STATUS_IS_EINVAL(s) ((s) == CORE_EINVAL) +/** illegal seek */ +#define STATUS_IS_ESPIPE(s) ((s) == CORE_ESPIPE) + +/** operation would block */ +#if !defined(EWOULDBLOCK) || !defined(EAGAIN) +#define STATUS_IS_EAGAIN(s) ((s) == CORE_EAGAIN) +#elif (EWOULDBLOCK == EAGAIN) +#define STATUS_IS_EAGAIN(s) ((s) == CORE_EAGAIN) +#else +#define STATUS_IS_EAGAIN(s) ((s) == CORE_EAGAIN \ + || (s) == EWOULDBLOCK) +#endif + +/** interrupted system call */ +#define STATUS_IS_EINTR(s) ((s) == CORE_EINTR) +/** socket operation on a non-socket */ +#define STATUS_IS_ENOTSOCK(s) ((s) == CORE_ENOTSOCK) +/** Connection Refused */ +#define STATUS_IS_ECONNREFUSED(s) ((s) == CORE_ECONNREFUSED) +/** operation now in progress */ +#define STATUS_IS_EINPROGRESS(s) ((s) == CORE_EINPROGRESS) + +/** + * Software caused connection abort + * @remark + * EPROTO on certain older kernels really means ECONNABORTED, so we need to + * ignore it for them. See discussion in new-httpd archives nh.9701 & nh.9603 + * + * There is potentially a bug in Solaris 2.x x<6, and other boxes that + * implement tcp sockets in userland (i.e. on top of STREAMS). On these + * systems, EPROTO can actually result in a fatal loop. See PR#981 for + * example. It's hard to handle both uses of EPROTO. + */ +#ifdef EPROTO +#define STATUS_IS_ECONNABORTED(s) ((s) == CORE_ECONNABORTED \ + || (s) == EPROTO) +#else +#define STATUS_IS_ECONNABORTED(s) ((s) == CORE_ECONNABORTED) +#endif + +/** Connection Reset by peer */ +#define STATUS_IS_ECONNRESET(s) ((s) == CORE_ECONNRESET) +/** Operation timed out + * @deprecated */ +#define STATUS_IS_ETIMEDOUT(s) ((s) == CORE_ETIMEDOUT) +/** no route to host */ +#define STATUS_IS_EHOSTUNREACH(s) ((s) == CORE_EHOSTUNREACH) +/** network is unreachable */ +#define STATUS_IS_ENETUNREACH(s) ((s) == CORE_ENETUNREACH) +/** inappropiate file type or format */ +#define STATUS_IS_EFTYPE(s) ((s) == CORE_EFTYPE) +/** broken pipe */ +#define STATUS_IS_EPIPE(s) ((s) == CORE_EPIPE) +/** cross device link */ +#define STATUS_IS_EXDEV(s) ((s) == CORE_EXDEV) +/** Directory Not Empty */ +#define STATUS_IS_ENOTEMPTY(s) ((s) == CORE_ENOTEMPTY || \ + (s) == CORE_EEXIST) +/** Address Family not supported */ +#define STATUS_IS_EAFNOSUPPORT(s) ((s) == CORE_EAFNOSUPPORT) +/** @} */ + +#endif /* !defined(NETWARE) && !defined(OS2) && !defined(WIN32) */ + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_ERRNO_H__ */ diff --git a/lib/core/include/core_file.h b/lib/core/include/core_file.h new file mode 100644 index 0000000000..88ccf13a95 --- /dev/null +++ b/lib/core/include/core_file.h @@ -0,0 +1,652 @@ +#ifndef __CORE_FILE_H__ +#define __CORE_FILE_H__ + +/** + * @file core_file.h + * @brief CORE File I/O Handling + */ + +#include "core.h" +#include "core_time.h" +#include "core_errno.h" +#include "core_param.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup file_io File I/O Handling Functions + * @ingroup CORE + * @{ + */ + +/** filetype_e values for the filetype member of the + * file_info_t structure + * @warning: Not all of the filetypes below can be determined. + * For example, a given platform might not correctly report + * a socket descriptor as CORE_SOCK if that type isn't + * well-identified on that platform. In such cases where + * a filetype exists but cannot be described by the recognized + * flags below, the filetype will be CORE_UNKFILE. If the + * filetype member is not determined, the type will be CORE_NOFILE. + */ + +typedef enum { + FILE_NOFILE = 0, /**< no file type determined */ + FILE_REG, /**< a regular file */ + FILE_DIR, /**< a directory */ + FILE_CHR, /**< a character device */ + FILE_BLK, /**< a block device */ + FILE_PIPE, /**< a FIFO / pipe */ + FILE_LNK, /**< a symbolic link */ + FILE_SOCK, /**< a [unix domain] socket */ + FILE_UNKFILE = 127 /**< a file of some other unknown type */ +} filetype_e; + +/** + * @defgroup file_permissions File Permissions flags + * @{ + */ + +#define FILE_USETID 0x8000 /**< Set user id */ +#define FILE_UREAD 0x0400 /**< Read by user */ +#define FILE_UWRITE 0x0200 /**< Write by user */ +#define FILE_UEXECUTE 0x0100 /**< Execute by user */ + +#define FILE_GSETID 0x4000 /**< Set group id */ +#define FILE_GREAD 0x0040 /**< Read by group */ +#define FILE_GWRITE 0x0020 /**< Write by group */ +#define FILE_GEXECUTE 0x0010 /**< Execute by group */ + +#define FILE_WSTICKY 0x2000 /**< Sticky bit */ +#define FILE_WREAD 0x0004 /**< Read by others */ +#define FILE_WWRITE 0x0002 /**< Write by others */ +#define FILE_WEXECUTE 0x0001 /**< Execute by others */ + +#define FILE_OS_DEFAULT 0x0FFF /**< use OS's default permissions */ + +/* additional permission flags for file_copy and file_append */ +#define FILE_SOURCE_PERMS 0x1000 /**< Copy source file's permissions */ + +/** @} */ + +/** + * @defgroup file_open_flags File Open Flags/Routines + * @{ + */ + +/* Note to implementors: Values in the range 0x00100000--0x80000000 + are reserved for platform-specific values. */ + +#define FILE_READ 0x00001 /**< Open the file for reading */ +#define FILE_WRITE 0x00002 /**< Open the file for writing */ +#define FILE_CREATE 0x00004 /**< Create the file if not there */ +#define FILE_APPEND 0x00008 /**< Append to the end of the file */ +#define FILE_TRUNCATE 0x00010 /**< Open the file and truncate + to 0 length */ +#define FILE_BINARY 0x00020 /**< Open the file in binary mode */ +#define FILE_EXCL 0x00040 /**< Open should fail if FILE_CREATE + and file exists. */ +#define FILE_DELONCLOSE 0x00100 /**< Delete the file after close */ + +/** @} */ + +/** + * @defgroup file_seek_flags File Seek Flags + * @{ + */ + +/* flags for file_seek */ +/** Set the file position */ +#define FILE_SET SEEK_SET +/** Current */ +#define FILE_CUR SEEK_CUR +/** Go to end of file */ +#define FILE_END SEEK_END +/** @} */ + +/** + * @defgroup file_attrs_set_flags File Attribute Flags + * @{ + */ + +/* flags for file_attrs_set */ +#define ATTR_READONLY 0x01 /**< File is read-only */ +#define ATTR_EXECUTABLE 0x02 /**< File is executable */ +#define ATTR_HIDDEN 0x04 /**< File is hidden */ +/** @} */ + +/** + * @defgroup file_writev{_full} max iovec size + * @{ + */ +#if defined(DOXYGEN) +#define MAX_IOVEC_SIZE 1024 /**< System dependent maximum + size of an iovec array */ +#elif defined(IOV_MAX) +#define MAX_IOVEC_SIZE IOV_MAX +#elif defined(MAX_IOVEC) +#define MAX_IOVEC_SIZE MAX_IOVEC +#else +#define MAX_IOVEC_SIZE 1024 +#endif +/** @} */ + +/** File attributes */ +typedef c_uint32_t file_attrs_t; + +/** Type to pass as whence argument to file_seek. */ +typedef int seek_where_t; + +/** + * Structure for referencing files. + */ +typedef struct file_t file_t; + +/** + * Structure for referencing directories. + */ +typedef struct dir_t dir_t; +/** + * Structure for determining file permissions. + */ +typedef c_int32_t file_perms_t; +#if (defined WIN32) || (defined NETWARE) +/** + * Structure for determining the device the file is on. + */ +typedef c_uint32_t dev_t; +#endif + +/** @} */ + +/** + * @defgroup file_stat Stat Functions + * @{ + */ +/** file info structure */ +typedef struct file_info_t file_info_t; + +#define FILE_INFO_LINK 0x00000001 /**< Stat the link not the file itself + if it is a link */ +#define FILE_INFO_MTIME 0x00000010 /**< Modification Time */ +#define FILE_INFO_CTIME 0x00000020 /**< Creation or inode-changed time */ +#define FILE_INFO_ATIME 0x00000040 /**< Access Time */ +#define FILE_INFO_SIZE 0x00000100 /**< Size of the file */ +#define FILE_INFO_CSIZE 0x00000200 /**< Storage size consumed by the file */ +#define FILE_INFO_DEV 0x00001000 /**< Device */ +#define FILE_INFO_INODE 0x00002000 /**< Inode */ +#define FILE_INFO_NLINK 0x00004000 /**< Number of links */ +#define FILE_INFO_TYPE 0x00008000 /**< Type */ +#define FILE_INFO_USER 0x00010000 /**< User */ +#define FILE_INFO_GROUP 0x00020000 /**< Group */ +#define FILE_INFO_UPROT 0x00100000 /**< User protection bits */ +#define FILE_INFO_GPROT 0x00200000 /**< Group protection bits */ +#define FILE_INFO_WPROT 0x00400000 /**< World protection bits */ +#define FILE_INFO_ICASE 0x01000000 /**< if dev is case insensitive */ +#define FILE_INFO_NAME 0x02000000 /**< ->name in proper case */ + +#define FILE_INFO_MIN 0x00008170 /**< type, mtime, ctime, atime, size */ +#define FILE_INFO_IDENT 0x00003000 /**< dev and inode */ +#define FILE_INFO_OWNER 0x00030000 /**< user and group */ +#define FILE_INFO_PROT 0x00700000 /**< all protections */ +#define FILE_INFO_NORM 0x0073b170 /**< an atomic unix file_stat() */ +#define FILE_INFO_DIRENT 0x02000000 /**< an atomic unix dir_read() */ + +/** + * The file information structure. This is analogous to the POSIX + * stat structure. + */ +struct file_info_t { + /** The bitmask describing valid fields of this c_file_info_t structure + * including all available 'wanted' fields and potentially more */ + c_int32_t valid; + /** The access permissions of the file. Mimics Unix access rights. */ + file_perms_t protection; + /** The type of file. One of CORE_REG, CORE_DIR, CORE_CHR, CORE_BLK, + CORE_PIPE, CORE_LNK or CORE_SOCK. If the type is undetermined, + the value is CORE_NOFILE. + * If the type cannot be determined, the value is CORE_UNKFILE. + */ + filetype_e filetype; + /** The user id that owns the file */ + uid_t user; + /** The group id that owns the file */ + gid_t group; + /** The inode of the file. */ + ino_t inode; + /** The id of the device the file is on. */ + dev_t device; + /** The number of hard links to the file. */ + c_int32_t nlink; + /** The size of the file */ + off_t size; + /** The storage size consumed by the file */ + off_t csize; + /** The time the file was last accessed */ + c_time_t atime; + /** The time the file was last modified */ + c_time_t mtime; + /** The time the file was created, or the inode was last changed */ + c_time_t ctime; + /** The pathname of the file (possibly unrooted) */ + char fname[MAX_FILENAME_SIZE]; + /** The file's name (no path) in filesystem case */ + char name[MAX_FILENAME_SIZE]; + /** The file's handle, if accessed (can be submitted to c_duphandle) */ + struct c_file_t *filehand; +}; + +/** @} */ + +/** + * Initialize the file utility. + */ +CORE_DECLARE(status_t) file_init(void); + +/** + * Finalize the file utility. + */ +CORE_DECLARE(status_t) file_final(void); + +/** + * Open the specified file. + * @param newf The opened file descriptor. + * @param fname The full path to the file (using / on all systems) + * @param flag Or'ed value of: + *
+ *         FILE_READ              open for reading
+ *         FILE_WRITE             open for writing
+ *         FILE_CREATE            create the file if not there
+ *         FILE_APPEND            file ptr is set to end prior to all writes
+ *         FILE_TRUNCATE          set length to zero if file exists
+ *         FILE_BINARY            not a text file (This flag is ignored on
+ *                               UNIX because it has no meaning)
+ *         FILE_EXCL              return error if FILE_CREATE and file exists
+ *         FILE_DELONCLOSE        delete the file after closing.
+ * 
+ * @param perm Access permissions for file. + * @remark If perm is FILE_OS_DEFAULT and the file is being created, + * appropriate default permissions will be used. + */ +CORE_DECLARE(status_t) file_open(file_t **newf, + const char *fname, c_int32_t flag, file_perms_t perm); + +/** + * Close the specified file. + * @param file The file descriptor to close. + */ +CORE_DECLARE(status_t) file_close(file_t *file); + +/** + * Delete the specified file. + * @param path The full path to the file (using / on all systems) + * @remark If the file is open, it won't be removed until all + * instances are closed. + */ +CORE_DECLARE(status_t) file_remove(const char *path); + +/** + * Rename the specified file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @warning If a file exists at the new location, then it will be + * overwritten. Moving files or directories across devices may not be + * possible. + */ +CORE_DECLARE(status_t) file_rename(const char *from_path, const char *to_path); + +/** + * Create a hard link to the specified file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @remark Both files must reside on the same device. + */ +CORE_DECLARE(status_t) file_link(const char *from_path, const char *to_path); + +/** + * Copy the specified file to another file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @param perms Access permissions for the new file if it is created. + * In place of the usual or'd combination of file permissions, the + * value CORE_SOURCE_PERMS may be given, in which case the source + * file's permissions are copied. + * @remark The new file does not need to exist, it will be created if required. + * @warning If the new file already exists, its contents will be overwritten. + */ +CORE_DECLARE(status_t) file_copy( + const char *from_path, const char *to_path, file_perms_t perms); + +/** + * Append the specified file to another file. + * @param from_path The full path to the source file (use / on all systems) + * @param to_path The full path to the destination file (use / on all systems) + * @param perms Access permissions for the destination file if it is created. + * In place of the usual or'd combination of file permissions, the + * value CORE_SOURCE_PERMS may be given, in which case the source + * file's permissions are copied. + * @remark The new file does not need to exist, it will be created if required. + */ +CORE_DECLARE(status_t) file_append( + const char *from_path, const char *to_path, file_perms_t perms); + +/** + * Are we at the end of the file + * @param fptr The core file we are testing. + * @remark Returns CORE_EOF if we are at the end of file, + * CORE_OK otherwise. + */ +CORE_DECLARE(status_t) file_eof(file_t *fptr); + +/** + * Read data from the specified file. + * @param thefile The file descriptor to read from. + * @param buf The buffer to store the data to. + * @param nbytes On entry, the number of bytes to read; on exit, the number + * of bytes read. + * + * @remark file_read will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, all of the available data is read. The third + * argument is modified to reflect the number of bytes read. If a + * char was put back into the stream via ungetc, it will be the first + * character returned. + * + * @remark It is not possible for both bytes to be read and an CORE_EOF + * or other error to be returned. CORE_EINTR is never returned. + */ +CORE_DECLARE(status_t) file_read(file_t *thefile, void *buf, size_t *nbytes); + +/** + * Write data to the specified file. + * @param thefile The file descriptor to write to. + * @param buf The buffer which contains the data. + * @param nbytes On entry, the number of bytes to write; on exit, the number + * of bytes written. + * + * @remark file_write will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, it + * will write as many as it can. The third argument is modified to + * reflect the * number of bytes written. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. CORE_EINTR is never returned. + */ +CORE_DECLARE(status_t) file_write( + file_t *thefile, const void *buf, size_t *nbytes); + +/** + * Write data from iovec array to the specified file. + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @param nvec The number of elements in the struct iovec array. This must + * be smaller than MAX_IOVEC_SIZE. If it isn't, the function + * will fail with CORE_EINVAL. + * @param nbytes The number of bytes written. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. CORE_EINTR is never returned. + * + * @remark file_writev is available even if the underlying + * operating system doesn't provide writev(). + */ +CORE_DECLARE(status_t) file_writev(file_t *thefile, + const struct iovec *vec, size_t nvec, size_t *nbytes); + +/** + * Read data from the specified file, ensuring that the buffer is filled + * before returning. + * @param thefile The file descriptor to read from. + * @param buf The buffer to store the data to. + * @param nbytes The number of bytes to read. + * @param bytes_read If non-NULL, this will contain the number of bytes read. + * + * @remark file_read will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, then the process/thread will block until it is + * available or EOF is reached. If a char was put back into the + * stream via ungetc, it will be the first character returned. + * + * @remark It is possible for both bytes to be read and an error to be + * returned. And if *bytes_read is less than nbytes, an accompanying + * error is _always_ returned. + * + * @remark CORE_EINTR is never returned. + */ +CORE_DECLARE(status_t) file_read_full(file_t *thefile, void *buf, + size_t nbytes, size_t *bytes_read); + +/** + * Write data to the specified file, ensuring that all of the data is + * written before returning. + * @param thefile The file descriptor to write to. + * @param buf The buffer which contains the data. + * @param nbytes The number of bytes to write. + * @param bytes_written If non-NULL, set to the number of bytes written. + * + * @remark file_write will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, the + * process/thread will block until they can be written. Exceptional + * error such as "out of space" or "pipe closed" will terminate with + * an error. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. And if *bytes_written is less than nbytes, an + * accompanying error is _always_ returned. + * + * @remark CORE_EINTR is never returned. + */ +CORE_DECLARE(status_t) file_write_full(file_t *thefile, + const void *buf, size_t nbytes, size_t *bytes_written); + + +/** + * Write data from iovec array to the specified file, ensuring that all of the + * data is written before returning. + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @param nvec The number of elements in the struct iovec array. This must + * be smaller than MAX_IOVEC_SIZE. If it isn't, the function + * will fail with CORE_EINVAL. + * @param nbytes The number of bytes written. + * + * @remark file_writev_full is available even if the underlying + * operating system doesn't provide writev(). + */ +CORE_DECLARE(status_t) file_writev_full(file_t *thefile, + const struct iovec *vec, size_t nvec, size_t *nbytes); +/** + * Write a character into the specified file. + * @param ch The character to write. + * @param thefile The file descriptor to write to + */ +CORE_DECLARE(status_t) file_putc(char ch, file_t *thefile); + +/** + * Read a character from the specified file. + * @param ch The character to read into + * @param thefile The file descriptor to read from + */ +CORE_DECLARE(status_t) file_getc(char *ch, file_t *thefile); + +/** + * Put a character back onto a specified stream. + * @param ch The character to write. + * @param thefile The file descriptor to write to + */ +CORE_DECLARE(status_t) file_ungetc(char ch, file_t *thefile); + +/** + * Read a string from the specified file. + * @param str The buffer to store the string in. + * @param len The length of the string + * @param thefile The file descriptor to read from + * @remark The buffer will be NUL-terminated if any characters are stored. + */ +CORE_DECLARE(status_t) file_gets(char *str, int len, file_t *thefile); + +/** + * Write the string into the specified file. + * @param str The string to write. + * @param thefile The file descriptor to write to + */ +CORE_DECLARE(status_t) file_puts(const char *str, file_t *thefile); + +/** + * Transfer all file modified data and metadata to disk. + * @param thefile The file descriptor to sync + */ +CORE_DECLARE(status_t) file_sync(file_t *thefile); + +/** + * Move the read/write file offset to a specified byte within a file. + * @param thefile The file descriptor + * @param where How to move the pointer, one of: + *
+ *            CORE_SET  --  set the offset to offset
+ *            CORE_CUR  --  add the offset to the current position
+ *            CORE_END  --  add the offset to the current file size
+ * 
+ * @param offset The offset to move the pointer to. + * @remark The third argument is modified to be the offset the pointer + was actually moved to. + */ +CORE_DECLARE(status_t) file_seek(file_t *thefile, + seek_where_t where, off_t *offset); + +/**accessor and general file_io functions. */ + +/** + * return the file name of the current file. + * @param new_path The path of the file. + * @param thefile The currently open file. + */ +CORE_DECLARE(status_t) file_name_get(const char **fname, file_t *thefile); + +/** + * set the specified file's permission bits. + * @param fname The file (name) to apply the permissions to. + * @param perms The permission bits to apply to the file. + * + * @warning Some platforms may not be able to apply all of the + * available permission bits; CORE_INCOMPLETE will be returned if some + * permissions are specified which could not be set. + * + * @warning Platforms which do not implement this feature will return + * CORE_ENOTIMPL. + */ +CORE_DECLARE(status_t) file_perms_set(const char *fname, file_perms_t perms); + +/** + * Set attributes of the specified file. + * @param fname The full path to the file (using / on all systems) + * @param attributes Or'd combination of + *
+ *            ATTR_READONLY   - make the file readonly
+ *            ATTR_EXECUTABLE - make the file executable
+ *            ATTR_HIDDEN     - make the file hidden
+ * 
+ * @param attr_mask Mask of valid bits in attributes. + * @remark This function should be used in preference to explict manipulation + * of the file permissions, because the operations to provide these + * attributes are platform specific and may involve more than simply + * setting permission bits. + * @warning Platforms which do not implement this feature will return + * CORE_ENOTIMPL. + */ +CORE_DECLARE(status_t) file_attrs_set(const char *fname, + file_attrs_t attributes, file_attrs_t attr_mask); + +/** + * Set the mtime of the specified file. + * @param fname The full path to the file (using / on all systems) + * @param mtime The mtime to apply to the file. + * @warning Platforms which do not implement this feature will return + * CORE_ENOTIMPL. + */ +CORE_DECLARE(status_t) file_mtime_set(const char *fname, c_time_t mtime); + +/** + * Create a new directory on the file system. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new direcoty. + */ +CORE_DECLARE(status_t) dir_make(const char *path, file_perms_t perm); + +/** Creates a new directory on the file system, but behaves like + * 'mkdir -p'. Creates intermediate directories as required. No error + * will be reported if PATH already exists. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new direcoty. + */ +CORE_DECLARE(status_t) dir_make_recursive(const char *path, file_perms_t perm); + +/** + * Remove directory from the file system. + * @param path the path for the directory to be removed. (use / on all systems) + * @remark Removing a directory which is in-use (e.g., the current working + * directory, or during core_dir_read, or with an open file) is not portable. + */ +CORE_DECLARE(status_t) dir_remove(const char *path); + +/** + * get the specified file's stats. + * @param finfo Where to store the information about the file. + * @param wanted The desired file_info_t fields, as a bit flag of + * CORE_FINFO_ values + * @param thefile The file to get information about. + */ +CORE_DECLARE(status_t) file_info_get(file_info_t *finfo, + c_int32_t wanted, file_t *thefile); + + +/** + * Truncate the file's length to the specified offset + * @param fp The file to truncate + * @param offset The offset to truncate to. + * @remark The read/write file offset is repositioned to offset. + */ +CORE_DECLARE(status_t) file_trunc(file_t *fp, off_t offset); + +/** + * Retrieve the flags that were passed into file_open() + * when the file was opened. + * @return c_int32_t the flags + */ +CORE_DECLARE(c_int32_t) file_flags_get(file_t *f); + +/** + * get the specified file's stats. The file is specified by filename, + * instead of using a pre-opened file. + * @param finfo Where to store the information about the file, which is + * never touched if the call fails. + * @param fname The name of the file to stat. + * @param wanted The desired file_info_t fields, as a bit flag of FILE_INFO_ + values + * + * @note If @c CORE_INCOMPLETE is returned all the fields in @a finfo may + * not be filled in, and you need to check the @c finfo->valid bitmask + * to verify that what you're looking for is there. + */ +CORE_DECLARE(status_t) file_stat(file_info_t *finfo, + const char *fname, c_int32_t wanted); + +/** + * Find an existing directory suitable as a temporary storage location. + * @param temp_dir The temp directory. + * @remark + * This function uses an algorithm to search for a directory that an + * an application can use for temporary storage. + * + */ +CORE_DECLARE(status_t) temp_dir_get(char *temp_dir); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_FILE_H__ */ diff --git a/lib/core/include/core_fsm.h b/lib/core/include/core_fsm.h new file mode 100644 index 0000000000..2bbc0674e4 --- /dev/null +++ b/lib/core/include/core_fsm.h @@ -0,0 +1,48 @@ +#ifndef __CORE_FSM_H__ +#define __CORE_FSM_H__ + +#include "core.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef enum _fsm_signal_t { + FSM_ENTRY_SIG, + FSM_EXIT_SIG, + FSM_USER_SIG +} fsm_signal_t; + +typedef c_uint32_t fsm_event_t; +typedef c_uint32_t fsm_state_t; +typedef void (*fsm_handler_t)(void *s, void *e); + +typedef struct _fsm_t { + fsm_handler_t initial; + fsm_handler_t final; + fsm_handler_t state; +} fsm_t; + +#define fsm_create(__s, __i, __f) \ + (((__s)->initial = (__s)->state = (fsm_handler_t)(__i)), \ + (__s)->final = (fsm_handler_t)(__f)) + +#define fsm_clear(__s) \ + ((__s)->initial = (__s)->state = (__s)->final = NULL) + + +CORE_DECLARE(void) fsm_init(fsm_t *s, fsm_event_t *e); +CORE_DECLARE(void) fsm_dispatch(fsm_t *s, fsm_event_t *e); +CORE_DECLARE(void) fsm_final(fsm_t *s, fsm_event_t *e); + +#define FSM_TRAN(__s, __target) \ + ((fsm_t *)__s)->state = (fsm_handler_t)(__target) + +#define FSM_STATE(__s) \ + (((fsm_t *)__s)->state) + +#ifdef __cplusplus +} +#endif + +#endif /* ! __CORE_FSM_H__ */ diff --git a/lib/core/include/core_general.h b/lib/core/include/core_general.h new file mode 100644 index 0000000000..47559ce089 --- /dev/null +++ b/lib/core/include/core_general.h @@ -0,0 +1,122 @@ +#ifndef __CORE_GENERAL_H__ +#define __CORE_GENERAL_H__ + +/** + * @file core_general.h + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of CORE 1.0. + * @brief CORE Miscellaneous library routines + */ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup core_general Miscellaneous library routines + * @ingroup CORE + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of CORE 1.0. + * @{ + */ + +/** a space */ +#define ASCII_BLANK '\040' +/** a carrige return */ +#define ASCII_CR '\015' +/** a line feed */ +#define ASCII_LF '\012' +/** a tab */ +#define ASCII_TAB '\011' + +/** + * Alignment macros + */ + +/* C_ALIGN() is only to be used to align on a power of 2 boundary */ +#define C_ALIGN(size, boundary) \ + (((size) + ((boundary) - 1)) & ~((boundary) - 1)) + +/** Default alignment */ +#define C_ALIGN_DEFAULT(size) C_ALIGN(size, 8) + + +/** + * String and memory functions + */ + +/* STRINGIFY is defined here, and also in core_release.h, so wrap it */ +#ifndef STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define STRINGIFY(n) STRINGIFY_HELPER(n) +/** Helper macro for STRINGIFY */ +#define STRINGIFY_HELPER(n) #n +#endif + +/** @} */ + +/** + * @defgroup core_library Library initialization and termination + * @{ + */ + +/** + * Setup any CORE internal data structures. This MUST be the first function + * called for any CORE library. + * @remark See core_app_initialize if this is an application, rather than + * a library consumer of core. + */ +CORE_DECLARE(status_t) core_initialize(void); + +/** + * Set up an application with normalized argc, argv (and optionally env) in + * order to deal with platform-specific oddities, such as Win32 services, + * code pages and signals. This must be the first function called for any + * CORE program. + * @param argc Pointer to the argc that may be corrected + * @param argv Pointer to the argv that may be corrected + * @param env Pointer to the env that may be corrected, may be NULL + * @remark See core_initialize if this is a library consumer of core. + * Otherwise, this call is identical to core_initialize, and must be closed + * with a call to core_terminate at the end of program execution. + */ +CORE_DECLARE(status_t) core_app_initialize(int *argc, + char const * const * *argv, + char const * const * *env); + +/** + * Tear down any CORE internal data structures which aren't torn down + * automatically. + * @remark An CORE program must call this function at termination once it + * has stopped using CORE services. The CORE developers suggest using + * atexit to ensure this is called. When using CORE from a language + * other than C that has problems with the calling convention, use + * core_terminate2() instead. + */ +CORE_DECLARE_NONSTD(void) core_terminate(void); + +/** + * Tear down any CORE internal data structures which aren't torn down + * automatically, same as core_terminate + * @remark An CORE program must call either the core_terminate or + * core_terminate2 function once it it has finished using CORE + * services. The CORE developers suggest using atexit(core_terminate) + * to ensure this is done. core_terminate2 exists to allow non-c + * language apps to tear down core, while core_terminate is + * recommended from c language applications. + */ +CORE_DECLARE(void) core_terminate2(void); + +/** @} */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! CORE_GENERAL_H */ diff --git a/lib/core/include/core_index.h b/lib/core/include/core_index.h new file mode 100644 index 0000000000..c4b453fd80 --- /dev/null +++ b/lib/core/include/core_index.h @@ -0,0 +1,67 @@ +#ifndef __CORE_INDEX_H__ +#define __CORE_INDEX_H__ + +#include "core.h" +#include "core_mutex.h" + +#define INVALID_INDEX 0 + +#define index_declare(__name, __size) \ + typedef struct { \ + int head, tail; \ + int size, avail; \ + c_uint32_t free_index[__size]; \ + mutex_id mut; \ + } index_##__name##_t; \ + index_##__name##_t __name + +#define index_init(__pname, __size) do { \ + int __i; \ + mutex_create(&(__pname)->mut, MUTEX_DEFAULT); \ + (__pname)->size = (__pname)->avail = __size; \ + (__pname)->head = (__pname)->tail = 0; \ + for (__i = 0; __i < __size; __i++) \ + (__pname)->free_index[__i] = (__i + 1); \ +} while (0) + +#define index_final(__pname) \ + ((__pname)->mut ? mutex_delete((__pname)->mut) : CORE_OK) + +#define index_init_wo_lock(__pname, __size) do { \ + int __i; \ + (__pname)->mut = 0; \ + (__pname)->size = (__pname)->avail = __size; \ + (__pname)->head = (__pname)->tail = 0; \ + for (__i = 0; __i < __size; __i++) \ + (__pname)->free_index[__i] = (__i + 1); \ +} while (0) + +#define index_alloc(__pname, __index) do { \ + (__index) = INVALID_INDEX; \ + if ((__pname)->mut) mutex_lock((__pname)->mut); \ + if ((__pname)->avail > 0) { \ + (__pname)->avail--; \ + (__index) = (__pname)->free_index[(__pname)->head]; \ + (__pname)->free_index[(__pname)->head] = INVALID_INDEX; \ + (__pname)->head = ((__pname)->head + 1) % ((__pname)->size); \ + } \ + if ((__pname)->mut) mutex_unlock((__pname)->mut); \ +} while (0) + +#define index_free(__pname, __index) do { \ + if ((__pname)->mut) mutex_lock((__pname)->mut); \ + if ((__pname)->avail < (__pname)->size) { \ + (__pname)->avail++; \ + (__pname)->free_index[(__pname)->tail] = (__index); \ + (__pname)->tail = ((__pname)->tail + 1) % ((__pname)->size); \ + } \ + if ((__pname)->mut) mutex_unlock((__pname)->mut); \ +} while (0) + +#define index_size(__pname) ((__pname)->size) + +#define index_avail(__pname) ((__pname)->avail) + +#define index_used(__pname) (index_size(__pname) - index_avail(__pname)) + +#endif /* ! __CORE_INDEX_H__ */ diff --git a/lib/core/include/core_lib.h b/lib/core/include/core_lib.h new file mode 100644 index 0000000000..e00510a488 --- /dev/null +++ b/lib/core/include/core_lib.h @@ -0,0 +1,87 @@ +#ifndef __CORE_LIB_H__ +#define __CORE_LIB_H__ + +/** + * @file c_lib.h + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of CORE 1.0. + * @brief CORE general purpose library routines + */ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup c_lib General Purpose Library Routines + * @ingroup CORE + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of CORE 1.0. + * @{ + */ + +/** A constant representing a 'large' string. */ +#define HUGE_STRING_LEN 8192 + +/* + * Define the structures used by the CORE general-purpose library. + */ + +/** @} */ + +/** + * @defgroup c_ctype ctype functions + * These macros allow correct support of 8-bit characters on systems which + * support 8-bit characters. Pretty dumb how the cast is required, but + * that's legacy libc for ya. These new macros do not support EOF like + * the standard macros do. Tough. + * @{ + */ +/** @see isalnum */ +#define c_isalnum(c) (isalnum(((unsigned char)(c)))) +/** @see isalpha */ +#define c_isalpha(c) (isalpha(((unsigned char)(c)))) +/** @see iscntrl */ +#define c_iscntrl(c) (iscntrl(((unsigned char)(c)))) +/** @see isdigit */ +#define c_isdigit(c) (isdigit(((unsigned char)(c)))) +/** @see isgraph */ +#define c_isgraph(c) (isgraph(((unsigned char)(c)))) +/** @see islower*/ +#define c_islower(c) (islower(((unsigned char)(c)))) +/** @see isascii */ +#ifdef isascii +#define c_isascii(c) (isascii(((unsigned char)(c)))) +#else +#define c_isascii(c) (((c) & ~0x7f)==0) +#endif +/** @see isprint */ +#define c_isprint(c) (isprint(((unsigned char)(c)))) +/** @see ispunct */ +#define c_ispunct(c) (ispunct(((unsigned char)(c)))) +/** @see isspace */ +#define c_isspace(c) (isspace(((unsigned char)(c)))) +/** @see isupper */ +#define c_isupper(c) (isupper(((unsigned char)(c)))) +/** @see isxdigit */ +#define c_isxdigit(c) (isxdigit(((unsigned char)(c)))) +/** @see tolower */ +#define c_tolower(c) (tolower(((unsigned char)(c)))) +/** @see toupper */ +#define c_toupper(c) (toupper(((unsigned char)(c)))) + +#define c_max(x , y) (((x) > (y)) ? (x) : (y)) +#define c_min(x , y) (((x) < (y)) ? (x) : (y)) + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_LIB_H__ */ diff --git a/lib/core/include/core_list.h b/lib/core/include/core_list.h new file mode 100644 index 0000000000..6932256796 --- /dev/null +++ b/lib/core/include/core_list.h @@ -0,0 +1,112 @@ +#ifndef __CORE_LIST_H__ +#define __CORE_LIST_H__ + +#include "core.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct _ln_t { + struct _ln_t *prev; + struct _ln_t *next; +}; + +typedef struct _ln_t ln_t; +typedef struct _ln_t list_t; +typedef struct _ln_t lnode_t; + +#define list_init(__pname) do {\ + (__pname)->prev = NULL; \ + (__pname)->next = NULL; \ +} while (0) + +#define list_first(__pname) ((void*)((__pname)->next)) + +#define list_last(__pname) ((void*)((__pname)->prev)) + +#define list_prev(__ptr_node) ((void*)(((ln_t *)(__ptr_node))->prev)) + +#define list_next(__ptr_node) ((void*)(((ln_t *)(__ptr_node))->next)) + +#define list_is_empty(__pname) ((__pname)->next == NULL) + +#define list_prepend(__pname, __ptr_new) do { \ + ((ln_t*)(__ptr_new))->prev = NULL; \ + ((ln_t*)(__ptr_new))->next = (__pname)->next; \ + if ((__pname)->next) \ + ((__pname)->next)->prev = (ln_t*)(__ptr_new); \ + else \ + (__pname)->prev = (ln_t*)(__ptr_new); \ + (__pname)->next = (ln_t*)(__ptr_new); \ +} while (0) + +#define list_append(__pname, __ptr_new) do { \ + ((ln_t*)(__ptr_new))->prev = (__pname)->prev; \ + ((ln_t*)(__ptr_new))->next = NULL; \ + if ((__pname)->prev) \ + ((__pname)->prev)->next = (ln_t*)(__ptr_new); \ + else \ + (__pname)->next = (ln_t*)(__ptr_new); \ + ((__pname)->prev) = (ln_t*)(__ptr_new); \ +} while (0) + +#define list_insert_prev(__pname, __ptr_node, __ptr_new) do { \ + ((ln_t*)(__ptr_new))->prev = ((ln_t*)(__ptr_node))->prev; \ + ((ln_t*)(__ptr_new))->next = (ln_t*)(__ptr_node); \ + if (((ln_t*)(__ptr_node))->prev) \ + ((ln_t*)(__ptr_node))->prev->next = (ln_t*)(__ptr_new); \ + else \ + (__pname)->next = (ln_t*)(__ptr_new); \ + ((ln_t*)(__ptr_node))->prev = ((ln_t*)(__ptr_new)); \ +} while (0) + +#define list_insert_next(__pname, __ptr_node, __ptr_new) do { \ + ((ln_t*)(__ptr_new))->prev = (ln_t*)(__ptr_node); \ + ((ln_t*)(__ptr_new))->next = ((ln_t*)(__ptr_node))->next; \ + if (((ln_t*)(__ptr_node))->next) \ + ((ln_t*)(__ptr_node))->next->prev = (ln_t*)(__ptr_new); \ + else \ + (__pname)->prev = (ln_t*)(__ptr_new); \ + ((ln_t*)(__ptr_node))->next = ((ln_t*)(__ptr_new)); \ +} while (0) + +#define list_remove(__pname, __ptr_node) do { \ + ln_t *_iter = (__pname)->next; \ + while (_iter) { \ + if (_iter == (ln_t*)(__ptr_node)) { \ + if (_iter->prev) \ + _iter->prev->next = _iter->next; \ + else \ + (__pname)->next = _iter->next; \ + if (_iter->next) \ + _iter->next->prev = _iter->prev; \ + else \ + (__pname)->prev = _iter->prev; \ + break; \ + } \ + _iter = _iter->next; \ + } \ +} while (0) + +typedef int (*ln_cmp_cb)(lnode_t *pnode1, lnode_t *pnode2); + +#define list_insert_sorted(__pname, __ptr_new, __cmp_callback) do { \ + ln_cmp_cb __pcb = (ln_cmp_cb)__cmp_callback; \ + ln_t *_iter = list_first(__pname); \ + while (_iter) { \ + if ((*__pcb)((ln_t*)(__ptr_new), _iter) < 0) { \ + list_insert_prev(__pname, _iter, __ptr_new); \ + break; \ + } \ + _iter = list_next(_iter); \ + } \ + if (_iter == NULL) \ + list_append(__pname, __ptr_new); \ +} while (0) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_LIST_H__ */ diff --git a/lib/core/include/core_msgq.h b/lib/core/include/core_msgq.h new file mode 100644 index 0000000000..9701ac07ba --- /dev/null +++ b/lib/core/include/core_msgq.h @@ -0,0 +1,86 @@ +#ifndef __CORE_MSGQ_H__ +#define __CORE_MSGQ_H__ + +/** + * @file core_msgq.h + * @brief Message queue header + */ + +#include "core.h" +#include "core_time.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef c_uintptr_t msgq_id; + +#define MAX_MSG_LEN 0xffff + +/** + * @return CORE_OK or CORE_ERROR. + */ +CORE_DECLARE(status_t) msgq_init(void); + +/** + * @return CORE_OK or CORE_ERROR. + */ +CORE_DECLARE(status_t) msgq_final(void); + +#define MSGQ_O_BLOCK 0x0 +#define MSGQ_O_NONBLOCK 0x1 + +/** + * @param id + * @param msgsize + * @param opt + * + * @return If succeed, handler value. If fail, zero + */ +CORE_DECLARE(msgq_id) msgq_create(int qsize, int msgsize, int opt); + +/** + * @param id + * + * @return If succeed, CORE_OK. If fail, CORE_ERROR. + */ +CORE_DECLARE(status_t) msgq_delete(msgq_id id); + +/** + * @param id + * @param msg + * @param msglen + * + * @return the number of bytes to be sent. If there is insufficient room in + * ring buffer, return CORE_EAGAIN. If any error, CORE_ERROR. + */ +CORE_DECLARE(int) msgq_send(msgq_id id, const char *msg, int msglen); + +/** + * @param id + * @param msg + * @param msglen + * + * @return the number of bytes to be read. If any error, CORE_ERROR. + * If ring buffer is empty and MSGQ_O_NONBLOCK set, CORE_EAGAIN. + */ +CORE_DECLARE(int) msgq_recv(msgq_id id, char *msg, int msglen); + +/** + * @param id + * @param msg + * @param msglen + * + * @return the number of bytes to be read. If any error, CORE_ERROR. + * If ring buffer is empty and MSGQ_O_NONBLOCK set, CORE_EAGAIN. + * If time out with empty buffer, CORE_TIMEUP. + */ +CORE_DECLARE(int) msgq_timedrecv(msgq_id id, char *msg, int msglen, + c_time_t timeout); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !__CORE_MSGQ_H__ */ diff --git a/lib/core/include/core_mutex.h b/lib/core/include/core_mutex.h new file mode 100644 index 0000000000..a4cdf53aa3 --- /dev/null +++ b/lib/core/include/core_mutex.h @@ -0,0 +1,89 @@ +#ifndef __MUTEX_H__ +#define __MUTEX_H__ + +/** + * @file mutex.h + * @brief Core Mutex Routines + */ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup mutex Thread Mutex Routines + * @ingroup CORE + * @{ + */ + +/** Opaque thread-local mutex structure */ +typedef c_uintptr_t mutex_id; + +#define MUTEX_DEFAULT 0x0 /**< platform-optimal lock behavior */ +#define MUTEX_NESTED 0x1 /**< enable nested (recursive) locks */ +#define MUTEX_UNNESTED 0x2 /**< disable nested locks */ + +/** + * Initialize Mutex Pool + */ +CORE_DECLARE(status_t) mutex_init(void); + +/** + * Finalize Mutex Pool + */ +CORE_DECLARE(status_t) mutex_final(void); + +/** + * Create and initialize a mutex that can be used to synchronize threads. + * @param id the memory address where the newly created mutex will be + * stored. + * @param flags Or'ed value of: + *
+ *           MUTEX_DEFAULT   platform-optimal lock behavior.
+ *           MUTEX_NESTED    enable nested (recursive) locks.
+ *           MUTEX_UNNESTED  disable nested locks (non-recursive).
+ * 
+ * @param pool the pool from which to allocate the mutex. + * @warning Be cautious in using MUTEX_DEFAULT. While this is the + * most optimial mutex based on a given platform's performance charateristics, + * it will behave as either a nested or an unnested lock. + */ +CORE_DECLARE(status_t) mutex_create(mutex_id *id, unsigned int flags); +/** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param id the mutex on which to acquire the lock. + */ +CORE_DECLARE(status_t) mutex_lock(mutex_id id); + +/** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with CORE_EBUSY. Note: it + * is important that the CORE_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was CORE_EBUSY, for portability reasons. + * @param id the mutex on which to attempt the lock acquiring. + */ +CORE_DECLARE(status_t) mutex_trylock(mutex_id id); + +/** + * Release the lock for the given mutex. + * @param id the mutex from which to release the lock. + */ +CORE_DECLARE(status_t) mutex_unlock(mutex_id id); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param id the mutex to destroy. + */ +CORE_DECLARE(status_t) mutex_delete(mutex_id id); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __MUTEX_H__ */ diff --git a/lib/core/include/core_net.h b/lib/core/include/core_net.h new file mode 100644 index 0000000000..2622acbd62 --- /dev/null +++ b/lib/core/include/core_net.h @@ -0,0 +1,266 @@ +#ifndef __CORE_NET_H__ +#define __CORE_NET_H__ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if HAVE_ARPA_INET_H +#include +#endif + +#if HAVE_NETDB_H +#include +#endif + +#if HAVE_NETINET_IN_H +#include +#endif + +#if HAVE_SYS_SOCKET_H +#include +#endif + +#define MAX_NET_POOL_SIZE 100 + +/* Max length of interface name, ex: eth0, ath0 .. */ +#define MAX_IFNAME_LEN 16 + +#define INET_NTOP(src, dst) inet_ntop(AF_INET,(void *)(src),(dst),INET_ADDRSTRLEN) +#define INET6_NTOP(src, dst) inet_ntop(AF_INET6,(void *)(src),(dst),INET6_ADDRSTRLEN) + +/** Network handler */ +typedef int (*net_handler)(void *net_sl, void *data); + +/** Network socket descriptor */ +typedef struct { + int type; + int proto; + int sock_id; +#if 0 /* deprecated */ + struct sockaddr_in local; +#endif + struct sockaddr_in remote; + int opt; + int sndrcv_errno; +} net_sock_t; + +/** Network socket handler */ +typedef int (*net_sock_handler)(net_sock_t *net_sock, void *data); + +/** Basic socket library */ + +/** Initialize network library */ +CORE_DECLARE(status_t) net_init(void); + +/** Finalize network library */ +CORE_DECLARE(status_t) net_final(void); + +/** + * Create network session. + * @param net_sock Connected network session. + * @param host Host IP address to be connected. + * @param lport Local Port number(only for UDP) + * @param rport Remote Port number + * @param proto Protocol proto + * @param type Protocol type + * @param flag Option flags to be set for this connection + */ +CORE_DECLARE(int) net_open(net_sock_t **net_sock,const char *host, + const int lport, + const int rport, + int type, int proto, const int flag); + +/** + * Create network session. + * @param net_sock Connected network session. + * @param local_addr Local Host IP address to bind(Network order) + * @param remote_host Remote Host IP address to be connected. + * @param lport Local Port number(only for UDP) + * @param rport Remote Port number + * @param proto Protocol proto + * @param type Protocol type + * @param flag Option flags to be set for this connection + */ +CORE_DECLARE(int) net_open_with_addr(net_sock_t **net_sock, + const c_uint32_t local_addr, + const char *remote_host, + const int lport, + const int rport, + int type, int proto, const int flag); +/** + * Read the data from the socket + * @param net_sock Socket which created before + * @param buffer Buffer which data be saved + * @param size Total length of buffer + * @param timeout Wait timeout. If 0 , it will block until data ready + */ +CORE_DECLARE(int) net_read(net_sock_t *net_sock, char *buffer, size_t size,int timeout); + +/** Write the data into the socket + * @param net_sock Socket which created before + * @param buffer Buffer which data be saved + * @param size Total length of buffer + */ +CORE_DECLARE(int) net_write(net_sock_t *net_sock, char *buffer, size_t size, + struct sockaddr_in *dest_addr, int addrlen); + +CORE_DECLARE(int) net_send(net_sock_t *net_sock, char *buffer, size_t size); + +CORE_DECLARE(int) net_sendto(net_sock_t *net_sock, char *buffer, size_t size, + c_uint32_t ip_addr, c_uint16_t port); + + +/** Close the socket + * @param net_sock Socket to be closed + */ +CORE_DECLARE(int) net_close(net_sock_t *net_sock); + +/** Wait the new socket session until given timeout + * @param new_accept_sock Newly created socket for new connection + * @param net_sock Listend socket before created + * @param timeout Wait timeout. If 0, it will be blocked until new connection + * received + */ +CORE_DECLARE(int) net_accept(net_sock_t **new_accept_sock, + net_sock_t *net_sock, int timeout); + +/** Create socket and listen to the specified port + * @param net_sock Returned socket + * @param type Protocol type + * @param proto Protocol proto + * @param port Port number + * @param addr Specific address + */ +CORE_DECLARE(int) net_listen_with_addr( + net_sock_t **net_sock, const int type, const int proto, + const int port, const c_uint32_t addr); +/** Create socket and listen to the specified port + * @param net_sock Returned socket + * @param type Protocol type + * @param proto Protocol proto + * @param port Port number + */ +CORE_DECLARE(int) net_listen( + net_sock_t **net_sock, const int type, const int proto, + const int port); + +/** Network application protocol */ +#define MAX_FTP_SESSION_SIZE 10 +typedef struct { + net_sock_t *ctrl_sock; /* Control channel */ + net_sock_t *data_sock; /* Data channel */ + int flag; + char cmd_buf[256]; + char resp_buf[256]; +} net_ftp_t; + +/** Open ftp session. + * @param host host name or IP address to connect + * @param username User ID or NULL if username is anonymous + * @param passwd Password or NULL if no passwd + * @param flag Option flags + * @param ftp_session Ftp session structure. If connection failed , it will be NULL + */ +CORE_DECLARE(int) net_ftp_open(const char *host, + const char *username, + const char *passwd, + int flag, + net_ftp_t **ftp_session); + +/** Retrieve file using FTP + * @param ftp_session Ftp session which created from net_ftp_open + * @param remote_filename Remote filename to retrieve + * @param local_filename Local filename. If null, the same name as remote will + * be used. + */ +CORE_DECLARE(int) net_ftp_get(net_ftp_t *ftp_session, + const char *remote_filename, + const char *local_filename); + +/** Upload file using FTP + * @param ftp_session Ftp session which created from net_ftp_open + * @param local_filename Local filename to upload. + * @param remote_filename Remote filename.If null, the same name as local will + * be used. + */ +CORE_DECLARE(int) net_ftp_put(net_ftp_t *ftp_session, + const char *local_filename, + const char *remote_filename); +/** Quit from ftp + * @param ftp_session Ftp session which created from net_ftp_open + */ +CORE_DECLARE(int) net_ftp_quit(net_ftp_t *ftp_session); + +/** Close ftp session + * @param ftp_session Ftp session which created from net_ftp_open + */ +CORE_DECLARE(int) net_ftp_close(net_ftp_t *ftp_session); + +/** Network session pool */ +CORE_DECLARE(int) net_pool_avail(); + +/** Network link interface */ +typedef struct { + int fd; + int ioctl_sock; + char ifname[MAX_IFNAME_LEN]; + struct sockaddr hwaddr; +} net_link_t; + +/** Network link handler */ +typedef int (*net_link_handler)(net_link_t *net_sock, void *data); + + +/** Open network interface */ +CORE_DECLARE(int) net_link_open(net_link_t **net_link, char *device, int proto); +/** Close network interface */ +CORE_DECLARE(int) net_link_close(net_link_t *net_link); + +/** Enable or disable promisc mode of network interface */ +CORE_DECLARE(int) net_link_promisc(net_link_t *net_link, int enable); + +/** Write the data into the link */ +CORE_DECLARE(int) net_link_write(net_link_t *net_link, char *buf, int len); + +/** Reate the data from the link */ +CORE_DECLARE(int) net_link_read(net_link_t *net_link, char *buffer, int size, + int timeout); + +/** Open the specified protocol raw socket */ +CORE_DECLARE(int) net_raw_open(net_link_t **net_link, int proto); + +/** Clse the specified protocol raw socket */ +CORE_DECLARE(int) net_raw_close(net_link_t *net_link); + +CORE_DECLARE(int) net_link_sendto(net_link_t *net_link, char *buf, int len, + struct sockaddr *dest_addr, int addrlen); + +/** Register net_sock */ +CORE_DECLARE(int) net_register_sock(net_sock_t *net_sock, + net_sock_handler handler, void *data); + +/** Register net_link */ +CORE_DECLARE(int) net_register_link(net_link_t *net_link, + net_link_handler handler, void *data); + +/** Unregister net_sock */ +CORE_DECLARE(int) net_unregister_sock(net_sock_t *net_sock); + +/** Unregister net_link */ +CORE_DECLARE(int) net_unregister_link(net_link_t *net_link); + +/** Read the multiple fds and run the registered handler + * @param timeout timeout(milliseconds) + */ +CORE_DECLARE(int) net_fds_read_run(long timeout); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_NET_H__ */ diff --git a/lib/core/include/core_param.h b/lib/core/include/core_param.h new file mode 100644 index 0000000000..5c7a9c0499 --- /dev/null +++ b/lib/core/include/core_param.h @@ -0,0 +1,19 @@ +#ifndef __CORE_PARAM_H__ +#define __CORE_PARAM_H__ + +#define MAX_NUM_OF_THREAD 128 +#define MAX_NUM_OF_THREADATTR MAX_NUM_OF_THREAD +#define MAX_NUM_OF_MUTEX 512 +#define MAX_NUM_OF_COND 512 +#define MAX_NUM_OF_RWLOCK 512 +#define MAX_NUM_OF_SEMAPHORE 512 + +#define MAX_NUM_OF_FILE 256 +#define MAX_FILENAME_SIZE 256 +#define MAX_DIRNAME_SIZE 256 + +#define MAX_NUM_OF_TIMER 1024 + +#define MAX_SIG_DESC_SIZE 256 + +#endif /* ! __CORE_PARAM_H__ */ diff --git a/lib/core/include/core_pkbuf.h b/lib/core/include/core_pkbuf.h new file mode 100644 index 0000000000..d397983c5a --- /dev/null +++ b/lib/core/include/core_pkbuf.h @@ -0,0 +1,192 @@ +#ifndef __CORE_PKBUF_H__ +#define __CORE_PKBUF_H__ + +/** + * @file core_pkbuf.h + * @brief Packet Buffer Routines + */ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * Cluster buffer structre */ +typedef struct _clbuf_t { + + /** + * reference count */ + c_uint16_t ref; + + /** + * pointer to cluster */ + void *cluster; + + /** + * the size of cluster */ + c_uint16_t size; + +} clbuf_t; + +/** + * Packet buffer structure */ +typedef struct _pkbuf_t { + + /** next pkbuf in singly linked pkbuf chain */ + struct _pkbuf_t *next; + + /** pointer to cluster */ + clbuf_t *clbuf; + + /** this buffer */ + void *payload; + + /** + * total length of this buffer and all next buffers in chain + * belonging to the same packet. + * + * For non-queue packet chains this is the invariant: + * p->tot_len == p->len + (p->next? p->next->tot_len: 0) + */ + c_uint16_t tot_len; + + /** length of this buffer */ + c_uint16_t len; + + /** misc flags */ + c_uint8_t flags; + +} pkbuf_t; + +/** + * Initializes the packet buffer library */ +CORE_DECLARE(status_t) pkbuf_init(void); + +/** + * Finalizes the packet buffer library */ +CORE_DECLARE(status_t) pkbuf_final(void); + +/** + * Show the pkbuf/clbuf/cluster count */ +CORE_DECLARE(void) pkbuf_show(void); + +/** + * Allocates a pkbuf of the given type (possibly a chain). + * + * The actual memory allocated for the pkbuf is determined by the + * headroom at which the pkbuf is allocated and the requested size + * (from the headroom parameter). + * + * @param headroom define header size + * @param type define header size + * should be allocated as follows: + * + * @return the allocated pkbuf. If multiple pkbufs where allocated, this + * is the first pkbuf of a pkbuf chain. + */ +#define MAX_SIZEOF_HEADROOM 128 +CORE_DECLARE(pkbuf_t *) pkbuf_alloc(c_uint16_t headroom, c_uint16_t length); + +/** + * Dereference a pkbuf chain and deallocate any no-longer-used + * pkbufs at the head of this chain. + * + * Decrements the reference count of the pkbuf's cluster buffer. + * If it reaches zero, the pkbuf is deallocated. + * + * For a pkbuf chain, this is repeated for each pkbuf in the chain, + * up to the first pkbuf which has a non-zero reference count after + * decrementing. So, when all reference counts are one, the whole + * chain is free'd. + * + * @param pkbuf The pkbuf (chain) to be dereferenced. + * + * @return the number of pkbufs that were de-allocated + * from the head of the chain. + */ +CORE_DECLARE(void) pkbuf_free(pkbuf_t *pkbuf); + +/** + * Adjusts the payload pointer to hide or reveal headers in the payload. + * + * Adjusts the ->payload pointer so that space for a header + * (dis)appears in the pkbuf payload. + * + * The ->payload, ->tot_len and ->len fields are adjusted. + * + * @param pkbuf pkbuf to change the header size. + * @param size Number of bytes to increment header size which + * increases the size of the pkbuf. New space is on the front. + * (Using a negative value decreases the header size.) + * If hdr_size_inc is 0, this function does nothing and returns succesful. + * + * @return non-zero on failure, zero on success. + */ +CORE_DECLARE(status_t) pkbuf_header(pkbuf_t *pkbuf, c_int16_t size); + +/** + * Concatenate two pkbufs (each may be a pkbuf chain) and take over + * the caller's reference of the tail pkbuf. + * + * @note The caller MAY NOT reference the tail pkbuf afterwards. + * Use pkbuf_chain() for that purpose. + * + * @see pkbuf_chain() + */ +CORE_DECLARE(void) pkbuf_join(pkbuf_t *h, pkbuf_t *t); + +/** + * Create copies of pkbufs. + * + * @param pkbuf pkbuf source of the copy + */ +CORE_DECLARE(pkbuf_t*) pkbuf_copy(pkbuf_t *pkbuf); + +/** + * Create copies of some part of pkbufs. + * + * @param pkbuf pkbuf source of the copy + * @param offset offset into the packet buffer from where to begin copying + * len bytes + * @param len length of data to copy + */ +CORE_DECLARE(pkbuf_t*) pkbuf_copy_partial(pkbuf_t *pkbuf, + c_uint16_t offset, c_uint16_t len); + +/** + * Copy the whole contents of a packet buffer to an application supplied + * buffer. + * + * @param pkbuf pkbuf from which to copy data + * @param buf buffer to copy to + * @param buflen + */ +CORE_DECLARE(status_t) pkbuf_tobuf(pkbuf_t *pkbuf, + void *buf, c_uint16_t *buflen); + +/** + * Copy part of the contents of a packet buffer to an application supplied + * buffer. + * + * @param pkbuf pkbuf from which to copy data + * @param buf buffer to copy to + * @param buflen + * @param offset offset into the packet buffer from where + * to begin copying len bytes + * @param len length of data to copy + */ +CORE_DECLARE(status_t) pkbuf_tobuf_partial(pkbuf_t *pkbuf, + void *buf, c_uint16_t *buflen, c_uint16_t offset, c_uint16_t len); + +/** + * Get the total length of packet buffer */ +#define pkbuf_length(__pkbuf) (__pkbuf) ? ((__pkbuf)->tot_len : -1) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __PKBUF_H__ */ diff --git a/lib/core/include/core_pool.h b/lib/core/include/core_pool.h new file mode 100644 index 0000000000..a7ab286b1c --- /dev/null +++ b/lib/core/include/core_pool.h @@ -0,0 +1,65 @@ +#ifndef __CORE_POOL_H__ +#define __CORE_POOL_H__ + +#include "core.h" +#include "core_mutex.h" + +#define pool_declare(__name, __type, __size) \ + typedef struct { \ + int head, tail; \ + int size, avail; \ + __type *free[__size], pool[__size]; \ + mutex_id mut; \ + } pool_##__name##_t; \ + pool_##__name##_t __name + +#define pool_init(__pname, __size) do { \ + int __i; \ + mutex_create(&(__pname)->mut, MUTEX_DEFAULT); \ + (__pname)->size = (__pname)->avail = __size; \ + (__pname)->head = (__pname)->tail = 0; \ + for (__i = 0; __i < __size; __i++) \ + (__pname)->free[__i] = &((__pname)->pool[__i]); \ +} while (0) + +#define pool_final(__pname) \ + ((__pname)->mut ? mutex_delete((__pname)->mut) : CORE_OK) + +#define pool_init_wo_lock(__pname, __size) do { \ + int __i; \ + (__pname)->mut = 0; \ + (__pname)->size = (__pname)->avail = __size; \ + (__pname)->head = (__pname)->tail = 0; \ + for (__i = 0; __i < __size; __i++) \ + (__pname)->free[__i] = &((__pname)->pool[__i]); \ +} while (0) + +#define pool_alloc_node(__pname, __pptr_node) do { \ + *(__pptr_node) = NULL; \ + if ((__pname)->mut) mutex_lock((__pname)->mut); \ + if ((__pname)->avail > 0) { \ + (__pname)->avail--; \ + *(__pptr_node) = (void*)(__pname)->free[(__pname)->head]; \ + (__pname)->free[(__pname)->head] = NULL; \ + (__pname)->head = ((__pname)->head + 1) % ((__pname)->size); \ + } \ + if ((__pname)->mut) mutex_unlock((__pname)->mut); \ +} while (0) + +#define pool_free_node(__pname, __ptr_node) do { \ + if ((__pname)->mut) mutex_lock((__pname)->mut); \ + if ((__pname)->avail < (__pname)->size) { \ + (__pname)->avail++; \ + (__pname)->free[(__pname)->tail] = (void*)(__ptr_node); \ + (__pname)->tail = ((__pname)->tail + 1) % ((__pname)->size); \ + } \ + if ((__pname)->mut) mutex_unlock((__pname)->mut); \ +} while (0) + +#define pool_size(__pname) ((__pname)->size) + +#define pool_avail(__pname) ((__pname)->avail) + +#define pool_used(__pname) (pool_size(__pname) - pool_avail(__pname)) + +#endif /* ! __CORE_POOL_H__ */ diff --git a/lib/core/include/core_queue.h b/lib/core/include/core_queue.h new file mode 100644 index 0000000000..901e6b331d --- /dev/null +++ b/lib/core/include/core_queue.h @@ -0,0 +1,40 @@ +#ifndef __CORE_QUEUE_H__ +#define __CORE_QUEUE_H__ + +#include "core.h" + +#define que_declare(__name, __type, __size) \ + struct { \ + int head, tail, size, used; \ + __type pool[(__size)]; \ + } __name + +#define que_init(__pname, __size) \ + ((__pname)->head = (__pname)->tail = 0, \ + (__pname)->used = 0, \ + (__pname)->size = __size) + +#define que_push(__pname, __ptr_node) \ + ((__pname)->used == ((__pname)->size) ? -1 : \ + (((__pname)->pool[(__pname)->head] = *(__ptr_node), \ + (__pname)->head = ((__pname)->head + 1) % ((__pname)->size), \ + ++(__pname)->used))) + + +#define que_pop(__pname, __ptr_node) \ + ((__pname)->used == 0 ? -1 : \ + ((*(__ptr_node) = (__pname)->pool[(__pname)->tail], \ + (__pname)->tail = ((__pname)->tail + 1) % ((__pname)->size), \ + --(__pname)->used))) + +#define que_is_empty(__pname) ((__pname)->used == 0) + +#define que_is_full(__pname) ((__pname)->used == (__pname)->size) + +#define que_size(__pname) ((__pname)->size) + +#define que_used(__pname) ((__pname)->used) + +#define que_avail(__pname) (que_size(__pname) - que_used(__pname)) + +#endif /* ! __CORE_QUEUE_H__ */ diff --git a/lib/core/include/core_ringbuf.h b/lib/core/include/core_ringbuf.h new file mode 100644 index 0000000000..c1a5bee890 --- /dev/null +++ b/lib/core/include/core_ringbuf.h @@ -0,0 +1,57 @@ +#ifndef __CORE_RINGBUF_H__ +#define __CORE_RINGBUF_H__ + +#include "core.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct _rbuf_header_t { + int head, tail, size; + char *pool; +}; + +#define rbuf_declare(__name, __size) \ + struct { \ + struct _rbuf_header_t h; \ + char int_pool[(__size) + 1]; \ + } __name + +#define rbuf_declare_ext(__name) \ + struct { \ + struct _rbuf_header_t h; \ + } __name + +#define rbuf_init(__pname, __size) \ + ((__pname)->h.head = (__pname)->h.tail = 0, \ + (__pname)->h.size = __size, \ + (__pname)->h.pool = (__pname)->int_pool) + +#define rbuf_init_ext(__pname, __size, __ext_pool) \ + ((__pname)->h.head = (__pname)->h.tail = 0, \ + (__pname)->h.size = __size, \ + (__pname)->h.pool = (char *)(__ext_pool)) + +#define rbuf_size(__pname) ((__pname)->h.size) + +#define rbuf_is_empty(__pname) ((__pname)->h.head == (__pname)->h.tail) +#define rbuf_is_full(__pname) (rbuf_free_bytes(__pname) == 0) + +CORE_DECLARE(int) rbuf_bytes(void *__pname); + +CORE_DECLARE(int) rbuf_free_bytes(void *__pname); + +CORE_DECLARE(int) rbuf_skip_write_pos(void *__pname, int __len); + +CORE_DECLARE(int) rbuf_write(void *__pname, const char *__buf, int __buf_len); + +CORE_DECLARE(int) rbuf_skip_read_pos(void *__pname, int __len); + +CORE_DECLARE(int) rbuf_read(void *__pname, char *__buf, int __buf_len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_RINGBUF_H__ */ diff --git a/lib/core/include/core_rwlock.h b/lib/core/include/core_rwlock.h new file mode 100644 index 0000000000..831e081e68 --- /dev/null +++ b/lib/core/include/core_rwlock.h @@ -0,0 +1,110 @@ +#ifndef __CORE_RWLOCK_H__ +#define __CORE_RWLOCK_H__ + +/** + * @file rwlock.h + * @brief CORE Reader/Writer Lock Routines + */ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup rwlock Reader/Writer Lock Routines + * @ingroup CORE + * @{ + */ + +/** Opaque read-write thread-safe lock. */ +typedef c_uintptr_t rwlock_id; + +/** + * Initialize Read-Write Lock Pool + */ +CORE_DECLARE(status_t) rwlock_init(void); + +/** + * Finalize Read-Write Lock Pool + */ +CORE_DECLARE(status_t) rwlock_final(void); + +/** + * Note: The following operations have undefined results: unlocking a + * read-write lock which is not locked in the calling thread; write + * locking a read-write lock which is already locked by the calling + * thread; destroying a read-write lock more than once; clearing or + * destroying the pool from which a locked read-write lock is + * allocated. + */ + +/** + * Create and initialize a read-write lock that can be used to synchronize + * threads. + * @param id the memory address where the newly created readwrite lock + * will be stored. + */ +CORE_DECLARE(status_t) rwlock_create(rwlock_id *id); +/** + * Acquire a shared-read lock on the given read-write lock. This will allow + * multiple threads to enter the same critical section while they have acquired + * the read lock. + * @param id the read-write lock on which to acquire the shared read. + */ +CORE_DECLARE(status_t) rwlock_rdlock(rwlock_id id); + +/** + * Attempt to acquire the shared-read lock on the given read-write lock. This + * is the same as rwlock_rdlock(), only that the function fails + * if there is another thread holding the write lock, or if there are any + * write threads blocking on the lock. If the function fails for this case, + * CORE_EBUSY will be returned. Note: it is important that the + * CORE_STATUS_IS_EBUSY(s) macro be used to determine if the return value was + * CORE_EBUSY, for portability reasons. + * @param id the rwlock on which to attempt the shared read. + */ +CORE_DECLARE(status_t) rwlock_tryrdlock(rwlock_id id); + +/** + * Acquire an exclusive-write lock on the given read-write lock. This will + * allow only one single thread to enter the critical sections. If there + * are any threads currently holding the read-lock, this thread is put to + * sleep until it can have exclusive access to the lock. + * @param id the read-write lock on which to acquire the exclusive write. + */ +CORE_DECLARE(status_t) rwlock_wrlock(rwlock_id id); + +/** + * Attempt to acquire the exclusive-write lock on the given read-write lock. + * This is the same as rwlock_wrlock(), only that the function fails + * if there is any other thread holding the lock (for reading or writing), + * in which case the function will return CORE_EBUSY. Note: it is important + * that the CORE_STATUS_IS_EBUSY(s) macro be used to determine if the return + * value was CORE_EBUSY, for portability reasons. + * @param id the rwlock on which to attempt the exclusive write. + */ +CORE_DECLARE(status_t) rwlock_trywrlock(rwlock_id id); + +/** + * Release either the read or write lock currently held by the calling thread + * associated with the given read-write lock. + * @param id the read-write lock to be released (unlocked). + */ +CORE_DECLARE(status_t) rwlock_unlock(rwlock_id id); + +/** + * Destroy the read-write lock and free the associated memory. + * @param id the rwlock to destroy. + */ +CORE_DECLARE(status_t) rwlock_delete(rwlock_id id); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_RWLOCK_H__ */ diff --git a/lib/core/include/core_semaphore.h b/lib/core/include/core_semaphore.h new file mode 100644 index 0000000000..48df392794 --- /dev/null +++ b/lib/core/include/core_semaphore.h @@ -0,0 +1,81 @@ +#ifndef __SEMAPHORE_H__ +#define __SEMAPHORE_H__ + +/** + * @file semaphore.h + * @brief Core Mutex Routines + */ + +#include "core.h" +#include "core_errno.h" +#include "core_time.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup semaphore Routines + * @ingroup CORE + * @{ + */ + +/** Opaque semaphore structure */ +typedef c_uintptr_t semaphore_id; + +/** + * Initialize Mutex Pool + */ +CORE_DECLARE(status_t) semaphore_init(void); + +/** + * Finalize Mutex Pool + */ +CORE_DECLARE(status_t) semaphore_final(void); + +/** + * Create and initialize a semaphore that can be used to synchronize processes. + * @param id the memory address where the newly created semaphore will be + * stored. + * @value initial value for semaphore + */ +CORE_DECLARE(status_t) semaphore_create(semaphore_id *id, c_uint32_t value); +/** + * Put the active calling thread to sleep until signaled to wake up. + * @param id the semaphore variable on which to block. + */ +CORE_DECLARE(status_t) semaphore_wait(semaphore_id id); + +#if HAVE_SEM_TIMEDWAIT +/** + * Put the active calling thread to sleep until signaled to wake up or + * the timeout is reached. + * @param id the semaphore variable on which to block. + * @param timeout The amount of time in microsesemaphores to wait. This is + * a maximum, not a minimum. If the semaphoreition is signaled, we + * will wake up before this time, otherwise the error CORE_TIMEUP + * is returned. + */ +CORE_DECLARE(status_t) semaphore_timedwait(semaphore_id id, c_time_t timeout); +#endif + +/** + * Posts a single thread, if one exists, that is blocking on the given + * semaphore variable. + * @param id the semaphore variable on which to produce the signal. + */ +CORE_DECLARE(status_t) semaphore_post(semaphore_id id); + +/** + * Destroy the semaphore and free the memory associated with the lock. + * @param semaphore the semaphore to destroy. + */ +CORE_DECLARE(status_t) semaphore_delete(semaphore_id id); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __SEMAPHORE_H__ */ diff --git a/lib/core/include/core_sha1.h b/lib/core/include/core_sha1.h new file mode 100644 index 0000000000..17c5674e0a --- /dev/null +++ b/lib/core/include/core_sha1.h @@ -0,0 +1,61 @@ +/* + * sha1.h + * + * Copyright (C) 1998, 2009 + * Paul E. Jones + * All Rights Reserved + * + ***************************************************************************** + * $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $ + ***************************************************************************** + * + * Description: + * This class implements the Secure Hashing Standard as defined + * in FIPS PUB 180-1 published April 17, 1995. + * + * Many of the variable names in the sha1_ctx, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _CORE_SHA1_H_ +#define _CORE_SHA1_H_ + +#include "core.h" + +#define SHA1_DIGEST_SIZE (160 / 8) +#define SHA1_BLOCK_SIZE (512 / 8) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct sha1_ctx +{ + unsigned Message_Digest[5]; /* Message Digest (output) */ + + unsigned Length_Low; /* Message length in bits */ + unsigned Length_High; /* Message length in bits */ + + unsigned char Message_Block[64]; /* 512-bit message blocks */ + int Message_Block_Index; /* Index into message block array */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corruped? */ +} sha1_ctx; + +CORE_DECLARE(void) sha1_init(sha1_ctx *ctx); +CORE_DECLARE(void) sha1_update(sha1_ctx *ctx, const c_uint8_t *message, + c_uint32_t len); +CORE_DECLARE(void) sha1_final(sha1_ctx *ctx, c_uint8_t *digest); +CORE_DECLARE(void) sha1(const c_uint8_t *message, c_uint32_t len, + c_uint8_t *digest); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _CORE_SHA1_H_ */ diff --git a/lib/core/include/core_sha1_hmac.h b/lib/core/include/core_sha1_hmac.h new file mode 100644 index 0000000000..50d41ae952 --- /dev/null +++ b/lib/core/include/core_sha1_hmac.h @@ -0,0 +1,71 @@ +/*- + * HMAC-SHA-224/256/384/512 implementation + * Last update: 06/15/2005 + * Issue date: 06/15/2005 + * + * Copyright (C) 2005 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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 _CORE_HMAC_SHA1_H +#define _CORE_HMAC_SHA1_H + +#include "core_sha1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + sha1_ctx ctx_inside; + sha1_ctx ctx_outside; + + /* for hmac_reinit */ + sha1_ctx ctx_inside_reinit; + sha1_ctx ctx_outside_reinit; + + c_uint8_t block_ipad[SHA1_BLOCK_SIZE]; + c_uint8_t block_opad[SHA1_BLOCK_SIZE]; +} hmac_sha1_ctx; + +CORE_DECLARE(void) hmac_sha1_init(hmac_sha1_ctx *ctx, c_uint8_t *key, + c_uint32_t key_size); +CORE_DECLARE(void) hmac_sha1_reinit(hmac_sha1_ctx *ctx); +CORE_DECLARE(void) hmac_sha1_update(hmac_sha1_ctx *ctx, c_uint8_t *message, + c_uint32_t message_len); +CORE_DECLARE(void) hmac_sha1_final(hmac_sha1_ctx *ctx, c_uint8_t *mac, + c_uint32_t mac_size); +CORE_DECLARE(void) hmac_sha1(c_uint8_t *key, c_uint32_t key_size, + c_uint8_t *message, c_uint32_t message_len, + c_uint8_t *mac, c_uint32_t mac_size); + +#ifdef __cplusplus +} +#endif + +#endif /* ! _CORE_HMAC_SHA1_H */ + diff --git a/lib/core/include/core_sha2.h b/lib/core/include/core_sha2.h new file mode 100644 index 0000000000..df095c315e --- /dev/null +++ b/lib/core/include/core_sha2.h @@ -0,0 +1,102 @@ +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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 _CORE_SHA2_H_ +#define _CORE_SHA2_H_ + +#include "core.h" + +#define SHA224_DIGEST_SIZE ( 224 / 8) +#define SHA256_DIGEST_SIZE ( 256 / 8) +#define SHA384_DIGEST_SIZE ( 384 / 8) +#define SHA512_DIGEST_SIZE ( 512 / 8) + +#define SHA256_BLOCK_SIZE ( 512 / 8) +#define SHA512_BLOCK_SIZE (1024 / 8) +#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE +#define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct { + c_uint32_t tot_len; + c_uint32_t len; + c_uint8_t block[2 * SHA256_BLOCK_SIZE]; + c_uint32_t h[8]; +} sha256_ctx; + +typedef struct { + c_uint32_t tot_len; + c_uint32_t len; + c_uint8_t block[2 * SHA512_BLOCK_SIZE]; + c_uint64_t h[8]; +} sha512_ctx; + +typedef sha512_ctx sha384_ctx; +typedef sha256_ctx sha224_ctx; + +CORE_DECLARE(void) sha224_init(sha224_ctx *ctx); +CORE_DECLARE(void) sha224_update(sha224_ctx *ctx, const c_uint8_t *message, + c_uint32_t len); +CORE_DECLARE(void) sha224_final(sha224_ctx *ctx, c_uint8_t *digest); +CORE_DECLARE(void) sha224(const c_uint8_t *message, c_uint32_t len, + c_uint8_t *digest); + +CORE_DECLARE(void) sha256_init(sha256_ctx * ctx); +CORE_DECLARE(void) sha256_update(sha256_ctx *ctx, const c_uint8_t *message, + c_uint32_t len); +CORE_DECLARE(void) sha256_final(sha256_ctx *ctx, c_uint8_t *digest); +CORE_DECLARE(void) sha256(const c_uint8_t *message, c_uint32_t len, + c_uint8_t *digest); + +CORE_DECLARE(void) sha384_init(sha384_ctx *ctx); +CORE_DECLARE(void) sha384_update(sha384_ctx *ctx, const c_uint8_t *message, + c_uint32_t len); +CORE_DECLARE(void) sha384_final(sha384_ctx *ctx, c_uint8_t *digest); +CORE_DECLARE(void) sha384(const c_uint8_t *message, c_uint32_t len, + c_uint8_t *digest); + +CORE_DECLARE(void) sha512_init(sha512_ctx *ctx); +CORE_DECLARE(void) sha512_update(sha512_ctx *ctx, const c_uint8_t *message, + c_uint32_t len); +CORE_DECLARE(void) sha512_final(sha512_ctx *ctx, c_uint8_t *digest); +CORE_DECLARE(void) sha512(const c_uint8_t *message, c_uint32_t len, + c_uint8_t *digest); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !_CORE_SHA2_H_ */ diff --git a/lib/core/include/core_sha2_hmac.h b/lib/core/include/core_sha2_hmac.h new file mode 100644 index 0000000000..7907d3be3f --- /dev/null +++ b/lib/core/include/core_sha2_hmac.h @@ -0,0 +1,140 @@ +/*- + * HMAC-SHA-224/256/384/512 implementation + * Last update: 06/15/2005 + * Issue date: 06/15/2005 + * + * Copyright (C) 2005 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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 _CORE_HMAC_SHA2_H +#define _CORE_HMAC_SHA2_H + +#include "core_sha2.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + sha224_ctx ctx_inside; + sha224_ctx ctx_outside; + + /* for hmac_reinit */ + sha224_ctx ctx_inside_reinit; + sha224_ctx ctx_outside_reinit; + + c_uint8_t block_ipad[SHA224_BLOCK_SIZE]; + c_uint8_t block_opad[SHA224_BLOCK_SIZE]; +} hmac_sha224_ctx; + +typedef struct { + sha256_ctx ctx_inside; + sha256_ctx ctx_outside; + + /* for hmac_reinit */ + sha256_ctx ctx_inside_reinit; + sha256_ctx ctx_outside_reinit; + + c_uint8_t block_ipad[SHA256_BLOCK_SIZE]; + c_uint8_t block_opad[SHA256_BLOCK_SIZE]; +} hmac_sha256_ctx; + +typedef struct { + sha384_ctx ctx_inside; + sha384_ctx ctx_outside; + + /* for hmac_reinit */ + sha384_ctx ctx_inside_reinit; + sha384_ctx ctx_outside_reinit; + + c_uint8_t block_ipad[SHA384_BLOCK_SIZE]; + c_uint8_t block_opad[SHA384_BLOCK_SIZE]; +} hmac_sha384_ctx; + +typedef struct { + sha512_ctx ctx_inside; + sha512_ctx ctx_outside; + + /* for hmac_reinit */ + sha512_ctx ctx_inside_reinit; + sha512_ctx ctx_outside_reinit; + + c_uint8_t block_ipad[SHA512_BLOCK_SIZE]; + c_uint8_t block_opad[SHA512_BLOCK_SIZE]; +} hmac_sha512_ctx; + +CORE_DECLARE(void) hmac_sha224_init(hmac_sha224_ctx *ctx, c_uint8_t *key, + c_uint32_t key_size); +CORE_DECLARE(void) hmac_sha224_reinit(hmac_sha224_ctx *ctx); +CORE_DECLARE(void) hmac_sha224_update(hmac_sha224_ctx *ctx, c_uint8_t *message, + c_uint32_t message_len); +CORE_DECLARE(void) hmac_sha224_final(hmac_sha224_ctx *ctx, c_uint8_t *mac, + c_uint32_t mac_size); +CORE_DECLARE(void) hmac_sha224(c_uint8_t *key, c_uint32_t key_size, + c_uint8_t *message, c_uint32_t message_len, + c_uint8_t *mac, c_uint32_t mac_size); + +CORE_DECLARE(void) hmac_sha256_init(hmac_sha256_ctx *ctx, c_uint8_t *key, + c_uint32_t key_size); +CORE_DECLARE(void) hmac_sha256_reinit(hmac_sha256_ctx *ctx); +CORE_DECLARE(void) hmac_sha256_update(hmac_sha256_ctx *ctx, c_uint8_t *message, + c_uint32_t message_len); +CORE_DECLARE(void) hmac_sha256_final(hmac_sha256_ctx *ctx, c_uint8_t *mac, + c_uint32_t mac_size); +CORE_DECLARE(void) hmac_sha256(c_uint8_t *key, c_uint32_t key_size, + c_uint8_t *message, c_uint32_t message_len, + c_uint8_t *mac, c_uint32_t mac_size); + +CORE_DECLARE(void) hmac_sha384_init(hmac_sha384_ctx *ctx, c_uint8_t *key, + c_uint32_t key_size); +CORE_DECLARE(void) hmac_sha384_reinit(hmac_sha384_ctx *ctx); +CORE_DECLARE(void) hmac_sha384_update(hmac_sha384_ctx *ctx, c_uint8_t *message, + c_uint32_t message_len); +CORE_DECLARE(void) hmac_sha384_final(hmac_sha384_ctx *ctx, c_uint8_t *mac, + c_uint32_t mac_size); +CORE_DECLARE(void) hmac_sha384(c_uint8_t *key, c_uint32_t key_size, + c_uint8_t *message, c_uint32_t message_len, + c_uint8_t *mac, c_uint32_t mac_size); + +CORE_DECLARE(void) hmac_sha512_init(hmac_sha512_ctx *ctx, c_uint8_t *key, + c_uint32_t key_size); +CORE_DECLARE(void) hmac_sha512_reinit(hmac_sha512_ctx *ctx); +CORE_DECLARE(void) hmac_sha512_update(hmac_sha512_ctx *ctx, c_uint8_t *message, + c_uint32_t message_len); +CORE_DECLARE(void) hmac_sha512_final(hmac_sha512_ctx *ctx, c_uint8_t *mac, + c_uint32_t mac_size); +CORE_DECLARE(void) hmac_sha512(c_uint8_t *key, c_uint32_t key_size, + c_uint8_t *message, c_uint32_t message_len, + c_uint8_t *mac, c_uint32_t mac_size); + +#ifdef __cplusplus +} +#endif + +#endif /* ! _CORE_HMAC_SHA2_H */ + diff --git a/lib/core/include/core_signal.h b/lib/core/include/core_signal.h new file mode 100644 index 0000000000..2073a17312 --- /dev/null +++ b/lib/core/include/core_signal.h @@ -0,0 +1,90 @@ +#ifndef CORE_SIGNAL_H +#define CORE_SIGNAL_H + +/** + * @file core_signal.h + * @brief CORE Signal Handling + */ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup core_signal Signal Handling + * @ingroup CORE + * @{ + */ + +#if HAVE_SIGACTION + +#if defined(DARWIN) && !defined(__cplusplus) && !defined(_ANSI_SOURCE) +/* work around Darwin header file bugs + * http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2657228.html + */ +#undef SIG_DFL +#undef SIG_IGN +#undef SIG_ERR +#define SIG_DFL (void (*)(int))0 +#define SIG_IGN (void (*)(int))1 +#define SIG_ERR (void (*)(int))-1 +#endif + +/** Function prototype for signal handlers */ +typedef void core_sigfunc_t(int); + +/** + * Set the signal handler function for a given signal + * @param signo The signal (eg... SIGWINCH) + * @param func the function to get called + */ +CORE_DECLARE(core_sigfunc_t *) core_signal(int signo, core_sigfunc_t * func); + +#if defined(SIG_IGN) && !defined(SIG_ERR) +#define SIG_ERR ((core_sigfunc_t *) -1) +#endif + +#else /* !HAVE_SIGACTION */ +#define core_signal(a, b) signal(a, b) +#endif + + +/** + * Setup the process for a single thread to be used for all signal handling. + * @warning This must be called before any threads are created + */ +CORE_DECLARE(status_t) signal_init(void); + +/** + * Make the current thread listen for signals. This thread will loop + * forever, calling a provided function whenever it receives a signal. That + * functions should return 1 if the signal has been handled, 0 otherwise. + * @param signal_handler The function to call when a signal is received + * apr_status_t apr_signal_thread((int)(*signal_handler)(int signum)) + */ +CORE_DECLARE(status_t) signal_thread(int(*signal_handler)(int signum)); + +/** + * Block the delivery of a particular signal + * @param signum The signal number + * @return status + */ +CORE_DECLARE(status_t) signal_block(int signum); + +/** + * Enable the delivery of a particular signal + * @param signum The signal number + * @return status + */ +CORE_DECLARE(status_t) signal_unblock(int signum); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CORE_SIGNAL_H */ diff --git a/lib/core/include/core_thread.h b/lib/core/include/core_thread.h new file mode 100644 index 0000000000..c9df0afb32 --- /dev/null +++ b/lib/core/include/core_thread.h @@ -0,0 +1,79 @@ +#ifndef __CORE_THREAD_H__ +#define __CORE_THREAD_H__ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Opaque Thread structure. */ +typedef c_uintptr_t thread_id; + +/** Opaque Thread attributes structure. */ +typedef struct threadattr_t threadattr_t; + +typedef void *(THREAD_FUNC *thread_start_t)(void*); + +/** + * Check if Thread Should Stop + */ +CORE_DECLARE(int) thread_should_stop(void); + +/** + * Initialize Thread + */ +CORE_DECLARE(status_t) thread_init(void); + +/** + * Finalize Thread + */ +CORE_DECLARE(status_t) thread_final(void); + +/** + * Create and initialize a new threadattr variable + * @param new_attr The newly created threadattr. + */ +CORE_DECLARE(status_t) threadattr_create(threadattr_t **new_attr); + +/** + * Set the stack size of newly created threads. + * @param attr The threadattr to affect + * @param stacksize The stack size in bytes + */ +CORE_DECLARE(status_t) threadattr_stacksize_set( + threadattr_t *attr, size_t stacksize); + +/** + * Delete and initialize a new threadattr variable + * @param new_attr The newly created threadattr. + */ +CORE_DECLARE(status_t) threadattr_delete(threadattr_t *attr); + +/** + * Create a new thread of execution + * @param id The newly created thread handle. + * @param attr The threadattr to use to determine how to create the thread + * @param func The function to start the new thread in + * @param data Any data to be passed to the starting function + */ +CORE_DECLARE(status_t) thread_create(thread_id *id, + threadattr_t *attr, thread_start_t func, void *data); + +/** + * Delete a new thread of execution + * @param id The thread to delete + */ +CORE_DECLARE(status_t) thread_delete(thread_id id); + +/** + * force the current thread to yield the processor + */ +CORE_DECLARE(void) thread_yield(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_THREAD_H__ */ diff --git a/lib/core/include/core_time.h b/lib/core/include/core_time.h new file mode 100644 index 0000000000..fab242688c --- /dev/null +++ b/lib/core/include/core_time.h @@ -0,0 +1,196 @@ +#ifndef __CORE_TIME_H__ +#define __CORE_TIME_H__ + +/** + * @file core_time.h + * @brief CORE Time Library + */ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup core_time Time Routines + * @ingroup CORE + * @{ + */ + +/** month names */ +CORE_DECLARE_DATA extern const char month_snames[12][4]; +/** day names */ +CORE_DECLARE_DATA extern const char day_snames[7][4]; + +/** number of microseconds since 00:00:00 january 1, 1970 UTC */ +typedef c_int64_t c_time_t; + +/** mechanism to properly type c_time_t literals */ +#define TIME_C(val) INT64_C(val) + +/** mechanism to properly print c_time_t values */ +#define TIME_T_FMT INT64_T_FMT + +/** number of microseconds per second */ +#define USEC_PER_SEC TIME_C(1000000) + +/** @return c_time_t as a second */ +#define time_sec(time) ((time) / USEC_PER_SEC) + +/** @return c_time_t as a usec */ +#define time_usec(time) ((time) % USEC_PER_SEC) + +/** @return c_time_t as a msec */ +#define time_msec(time) (((time) / 1000) % 1000) + +/** @return c_time_t as a msec */ +#define time_as_msec(time) ((time) / 1000) + +/** @return milliseconds as an c_time_t */ +#define time_from_msec(msec) ((c_time_t)(msec) * 1000) + +/** @return seconds as an c_time_t */ +#define time_from_sec(sec) ((c_time_t)(sec) * USEC_PER_SEC) + +/** @return a second and usec combination as an c_time_t */ +#define time_make(sec, usec) ((c_time_t)(sec) * USEC_PER_SEC \ + + (c_time_t)(usec)) +/** @see time_exp_t */ +typedef struct time_exp_t time_exp_t; + +/** + * a structure similar to ANSI struct tm with the following differences: + * - tm_usec isn't an ANSI field + * - tm_gmtoff isn't an ANSI field (it's a bsdism) + */ +struct time_exp_t { + /** microseconds past tm_sec */ + int32_t tm_usec; + /** (0-61) seconds past tm_min */ + int32_t tm_sec; + /** (0-59) minutes past tm_hour */ + int32_t tm_min; + /** (0-23) hours past midnight */ + int32_t tm_hour; + /** (1-31) day of the month */ + int32_t tm_mday; + /** (0-11) month of the year */ + int32_t tm_mon; + /** year since 1900 */ + int32_t tm_year; + /** (0-6) days since sunday */ + int32_t tm_wday; + /** (0-365) days since jan 1 */ + int32_t tm_yday; + /** daylight saving time */ + int32_t tm_isdst; + /** seconds east of UTC */ + int32_t tm_gmtoff; +}; + +/** + * @return the current time + */ +CORE_DECLARE(c_time_t) time_now(void); + +/** + * Sleep for the specified number of micro-seconds. + * @param t desired amount of time to sleep. + * @warning May sleep for longer than the specified time. + */ +CORE_DECLARE(void) core_sleep(c_time_t t); + +/** + * convert an ansi time_t to an c_time_t + * @param result the resulting c_time_t + * @param input the time_t to convert + */ +CORE_DECLARE(status_t) time_ansi_put(c_time_t *result, time_t input); + +/** + * convert a time to its human readable components using an offset + * from GMT + * @param result the exploded time + * @param input the time to explode + * @param offs the number of seconds offset to apply + */ +CORE_DECLARE(status_t) time_exp_tz(time_exp_t *result, + c_time_t input, int32_t offs); + +/** + * convert a time to its human readable components in GMT timezone + * @param result the exploded time + * @param input the time to explode + */ +CORE_DECLARE(status_t) time_exp_gmt(time_exp_t *result, c_time_t input); + +/** + * convert a time to its human readable components in local timezone + * @param result the exploded time + * @param input the time to explode + */ +CORE_DECLARE(status_t) time_exp_lt(time_exp_t *result, c_time_t input); + +/** + * Convert time value from human readable format to a numeric c_time_t + * e.g. elapsed usec since epoch + * @param result the resulting imploded time + * @param input the input exploded time + */ +CORE_DECLARE(status_t) time_exp_get(c_time_t *result, time_exp_t *input); + +/** + * Convert time value from human readable format to a numeric c_time_t that + * always represents GMT + * @param result the resulting imploded time + * @param input the input exploded time + */ +CORE_DECLARE(status_t) time_exp_gmt_get(c_time_t *result, time_exp_t *input); + +/** length of a RFC822 Date */ +#define APR_RFC822_DATE_LEN (30) +/** + * rfc822_date formats dates in the RFC822 + * format in an efficient manner. It is a fixed length + * format which requires the indicated amount of storage, + * including the trailing NUL terminator. + * @param date_str String to write to. + * @param t the time to convert + */ +CORE_DECLARE(status_t) rfc822_date(char *date_str, c_time_t t); + +/** length of a CTIME date */ +#define CTIME_LEN (25) +/** + * ctime formats dates in the ctime() format + * in an efficient manner. it is a fixed length format + * and requires the indicated amount of storage including + * the trailing NUL terminator. + * Unlike ANSI/ISO C ctime(), ctime() does not include + * a \n at the end of the string. + * @param date_str String to write to. + * @param t the time to convert + */ +CORE_DECLARE(status_t) core_ctime(char *date_str, c_time_t t); + +/** + * formats the exploded time according to the format specified + * @param s string to write to + * @param retsize The length of the returned string + * @param max The maximum length of the string + * @param format The format for the time string + * @param tm The time to convert + */ +CORE_DECLARE(status_t) core_strftime(char *s, size_t *retsize, + size_t max, const char *format, + time_exp_t *tm); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! __CORE_TIME_H__ */ diff --git a/lib/core/include/core_timer.h b/lib/core/include/core_timer.h new file mode 100644 index 0000000000..ecd04bc26b --- /dev/null +++ b/lib/core/include/core_timer.h @@ -0,0 +1,59 @@ +#ifndef __CORE_TIMER_H__ +#define __CORE_TIMER_H__ + +#include "core.h" +#include "core_errno.h" +#include "core_list.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef enum _tm_type { + TIMER_TYPE_ONE_SHOT, + TIMER_TYPE_PERIODIC +} tm_type_e; + +typedef struct _tm_service_t { + list_t active_list; + list_t idle_list; + /* timer basic element */ +} tm_service_t; + +typedef c_uintptr_t tm_block_id; + +typedef void (*expire_func_t)( + c_uintptr_t arg1, c_uintptr_t arg2, c_uintptr_t arg3); + +typedef struct _tm_desc_t { + tm_type_e type; + c_uint32_t duration; + expire_func_t expire_func; + c_uintptr_t arg1; + c_uintptr_t arg2; + c_uintptr_t arg3; +} tm_desc_t; + +CORE_DECLARE(status_t) tm_init(void); +CORE_DECLARE(status_t) tm_final(void); + +CORE_DECLARE(c_uint32_t) tm_pool_avail(void); + +CORE_DECLARE(void) tm_service_init(tm_service_t *tm_service); +CORE_DECLARE(status_t) tm_execute_tm_service(tm_service_t *p_tm_s); + +CORE_DECLARE(tm_block_id) tm_create(tm_service_t *tm_service); +CORE_DECLARE(void) tm_delete(tm_block_id id); +CORE_DECLARE(status_t) tm_set(tm_block_id id, tm_type_e type, + c_uint32_t duration, expire_func_t expire_func, + c_uintptr_t arg1, c_uintptr_t arg2, c_uintptr_t arg3); +CORE_DECLARE(status_t) tm_set_duration(tm_block_id id, c_uint32_t duration); +CORE_DECLARE(status_t) tm_set_by_desc(tm_block_id id, tm_desc_t *desc); +CORE_DECLARE(status_t) tm_start(tm_block_id id); +CORE_DECLARE(status_t) tm_stop(tm_block_id id); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/lib/core/include/core_tlv.h b/lib/core/include/core_tlv.h new file mode 100644 index 0000000000..6bf2028259 --- /dev/null +++ b/lib/core/include/core_tlv.h @@ -0,0 +1,108 @@ +#ifndef __CORE_TLV_H__ +#define __CORE_TLV_H__ + +#include "core.h" +#include "core_pool.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* UTIS project specific parameters */ +#define UPDU_IE_TYPE_1_CODE 0x01 +#define UPDU_IE_TYPE_2_CODE 0x02 +#define UPDU_IE_TYPE_3_CODE 0x00 + +#define UPDU_IE_TYPE_1_MAX_SIZE 0x40 +#define UPDU_IE_TYPE_2_MAX_SIZE 0x4000 +#define UPDU_IE_TYPE_3_MAX_SIZE 0x40000000 + + +#define TLV_MODE_UTIS 2 +#define TLV_MODE_WIFI 3 +#define TLV_MODE_WMX_R4_R6 4 +#define TLV_MODE_WMX_R1 5 + + +#define NUM_OF_TLV_NODE 100 + +/* tlv_t struncture */ + +typedef struct _tlv_t +{ + /* for tlv management */ + struct _tlv_t* head; + struct _tlv_t* tail; /* this is used only for head tlv_t */ + struct _tlv_t* next; + + struct _tlv_t* parent; + struct _tlv_t* embedded; + + + /* tlv basic element */ + c_uint32_t type; + c_uint32_t length; + void* value; + + /* can be needed in encoding tlv_t*/ + c_uint8_t buff_allocated; + c_uint32_t buff_len; + c_uint8_t* buff_ptr; + c_uint8_t* buff; +} tlv_t; + +#define tlv_type(pTlv) pTlv->type +#define tlv_length(pTlv) pTlv->length +#define tlv_value(pTlv) pTlv->value + +#define tlv_wmx_r4_r6_type(pTlv) (pTlv->type & 0x7FFF) +#define tlv_wmx_r4_r6_tc(pTlv) (pTlv->type & 0x8000) +#define tlv_wmx_r4_r6_set_tc(pTlv) (pTlv->type | 0x8000) +#define tlv_wmx_r4_r6_clr_tc(pTlv) (pTlv->type & 0x7FFF) + + +/* tlv_t pool related functions */ +CORE_DECLARE(tlv_t*) tlv_get(void); +CORE_DECLARE(void) tlv_free(tlv_t *pTlv); +CORE_DECLARE(void) tlv_free_all(tlv_t *rootTlv); + +CORE_DECLARE(status_t) tlv_init(void); +CORE_DECLARE(status_t) tlv_final(void); + +/* tlv_t encoding functions */ +CORE_DECLARE(c_uint8_t*) tlv_write_to_buff( + c_uint8_t *blk, c_uint32_t type, c_uint32_t length, + c_uint8_t *value, c_uint8_t mode); +CORE_DECLARE(tlv_t*) tlv_add( + tlv_t *headTlv, c_uint32_t type, c_uint32_t length, c_uint8_t *value); +CORE_DECLARE(tlv_t*) tlv_create_buff_enabled_tlv( + c_uint8_t *buff, c_uint32_t buff_len, + c_uint32_t type, c_uint32_t length, c_uint8_t *value); +CORE_DECLARE(tlv_t*) tlv_embed( + tlv_t *parent_tlv, c_uint32_t type, c_uint32_t length, c_uint8_t *value); +CORE_DECLARE(c_uint32_t) tlv_render( + tlv_t *rootTlv, c_uint8_t *blk, c_uint32_t length, c_uint8_t mode); + + +/* tlv_t parsing functions */ +CORE_DECLARE(tlv_t*) tlv_parse_tlv_block(c_uint32_t length, + c_uint8_t *blk, c_uint8_t mode); +CORE_DECLARE(tlv_t*) tlv_parse_embedded_tlv_block(tlv_t* pTlv, c_uint8_t mode); + + +/* tlv operation-related function */ +CORE_DECLARE(tlv_t*) tlv_find(tlv_t* pTlv, c_uint32_t type); +CORE_DECLARE(tlv_t*) tlv_find_root(tlv_t* pTlv); +CORE_DECLARE(c_uint32_t) tlv_pool_avail(void); +CORE_DECLARE(c_uint32_t) tlv_calc_length(tlv_t *p_tlv, c_uint8_t mode); +CORE_DECLARE(c_uint32_t) tlv_calc_count(tlv_t *p_tlv); +CORE_DECLARE(c_uint8_t) tlv_value_8(tlv_t *tlv); +CORE_DECLARE(c_uint16_t) tlv_value_16(tlv_t *tlv); +CORE_DECLARE(c_uint32_t) tlv_value_32(tlv_t *tlv); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !__CORE_TLV_H__ */ diff --git a/lib/core/include/core_version.h b/lib/core/include/core_version.h new file mode 100644 index 0000000000..bf5a8505f0 --- /dev/null +++ b/lib/core/include/core_version.h @@ -0,0 +1,141 @@ +#ifndef __CORE_VERSION_H__ +#define __CORE_VERSION_H__ + +/** + * @file version.h + * @brief CORE Versioning Interface + * + * CORE's Version + * + * There are several different mechanisms for accessing the version. There + * is a string form, and a set of numbers; in addition, there are constants + * which can be compiled into your application, and you can query the library + * being used for its actual version. + * + * Note that it is possible for an application to detect that it has been + * compiled against a different version of CORE by use of the compile-time + * constants and the use of the run-time query function. + * + */ + + +/* The numeric compile-time version constants. These constants are the + * authoritative version numbers for CORE. + */ + +/** major version + * Major API changes that could cause compatibility problems for older + * programs such as structure size changes. No binary compatibility is + * possible across a change in the major version. + */ +#define CORE_MAJOR_VERSION 1 + +/** minor version + * Minor API changes that do not cause binary compatibility problems. + * Reset to 0 when upgrading CORE_MAJOR_VERSION + */ +#define CORE_MINOR_VERSION 0 + +/** patch level + * The Patch Level never includes API changes, simply bug fixes. + * Reset to 0 when upgrading CORE_MINOR_VERSION + */ +#define CORE_PATCH_VERSION 0 + +/** + * The symbol CORE_IS_DEV_VERSION is only defined for internal, + * "development" copies of CORE. It is undefined for released versions + * of CORE. + */ +#define CORE_IS_DEV_VERSION + +/** + * Check at compile time if the CORE version is at least a certain + * level. + * @param major The major version component of the version checked + * for (e.g., the "1" of "1.3.0"). + * @param minor The minor version component of the version checked + * for (e.g., the "3" of "1.3.0"). + * @param patch The patch level component of the version checked + * for (e.g., the "0" of "1.3.0"). + * @remark This macro is available with CORE versions starting with + * 1.3.0. + */ +#define CORE_VERSION_AT_LEAST(major,minor,patch) \ +(((major) < CORE_MAJOR_VERSION) \ + || ((major) == CORE_MAJOR_VERSION && (minor) < CORE_MINOR_VERSION) \ + || ((major) == CORE_MAJOR_VERSION && (minor) == CORE_MINOR_VERSION && (patch) <= CORE_PATCH_VERSION)) + +#if defined(CORE_IS_DEV_VERSION) || defined(DOXYGEN) +/** Internal: string form of the "is dev" flag */ +#define CORE_IS_DEV_STRING "-dev" +#else +#define CORE_IS_DEV_STRING "" +#endif + +/* STRINGIFY is defined here, and also in general.h, so wrap it */ +#ifndef STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define STRINGIFY(n) STRINGIFY_HELPER(n) +/** Helper macro for STRINGIFY */ +#define STRINGIFY_HELPER(n) #n +#endif + +/** The formatted string of CORE's version */ +#define CORE_VERSION_STRING \ + STRINGIFY(CORE_MAJOR_VERSION) "." \ + STRINGIFY(CORE_MINOR_VERSION) "." \ + STRINGIFY(CORE_PATCH_VERSION) \ + CORE_IS_DEV_STRING + +/** An alternative formatted string of CORE's version */ +/* macro for Win32 .rc files using numeric csv representation */ +#define CORE_VERSION_STRING_CSV CORE_MAJOR_VERSION ##, \ + ##CORE_MINOR_VERSION ##, \ + ##CORE_PATCH_VERSION + + +#ifndef __CORE_VERSION_ONLY__ + +/* The C language API to access the version at run time, + * as opposed to compile time. CORE_VERSION_ONLY may be defined + * externally when preprocessing version.h to obtain strictly + * the C Preprocessor macro declarations. + */ + +#include "core.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * The numeric version information is broken out into fields within this + * structure. + */ +typedef struct +{ + int major; /**< major number */ + int minor; /**< minor number */ + int patch; /**< patch number */ + int is_dev; /**< is development (1 or 0) */ +} core_version_t; + +/** + * Return CORE's version information information in a numeric form. + * + * @param pvsn Pointer to a version structure for returning the version + * information. + */ +CORE_DECLARE(void) core_version(core_version_t *pvsn); + +/** Return CORE's version information as a string. */ +CORE_DECLARE(const char *) core_version_string(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ndef CORE_VERSION_ONLY */ + +#endif /* ndef CORE_VERSION_H */ diff --git a/lib/core/src/Makefile.am b/lib/core/src/Makefile.am new file mode 100644 index 0000000000..0af823ef56 --- /dev/null +++ b/lib/core/src/Makefile.am @@ -0,0 +1,41 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = @OSDIR@ + +noinst_LTLIBRARIES = libcore.la + +libcore_la_SOURCES = \ + version.c \ + ../include/core_aes_cmac.h ../include/core_aes.h ../include/core_cond.h \ + ../include/core_debug.h ../include/core_errno.h ../include/core_file.h \ + ../include/core_fsm.h ../include/core_general.h ../include/core.h \ + ../include/core.h.in ../include/core_index.h ../include/core_lib.h \ + ../include/core_list.h ../include/core_msgq.h ../include/core_mutex.h \ + ../include/core_net.h ../include/core_param.h ../include/core_pkbuf.h \ + ../include/core_pool.h ../include/core_queue.h ../include/core_ringbuf.h \ + ../include/core_rwlock.h ../include/core_semaphore.h ../include/core_sha1.h \ + ../include/core_sha1_hmac.h ../include/core_sha2.h ../include/core_sha2_hmac.h \ + ../include/core_signal.h ../include/core_thread.h ../include/core_time.h \ + ../include/core_timer.h ../include/core_tlv.h ../include/core_version.h + +nodist_libcore_la_SOURCES = \ + debug.c fsm.c msgq.c ringbuf.c timer.c tlv.c \ + aes.c aes_cmac.c sha1.c sha1_hmac.c sha2.c sha2_hmac.c + +libcore_la_DEPENDENCIES = \ + $(top_srcdir)/lib/core/src/@OSDIR@/libcore@OSDIR@.la + +libcore_la_LIBADD = \ + $(top_srcdir)/lib/core/src/@OSDIR@/libcore@OSDIR@.la + +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib/core/include/arch/@OSDIR@ \ + -I$(top_srcdir)/lib/core/include + +AM_CFLAGS = \ + -Wall -Werror + +MAINTAINERCLEANFILES = Makefile.in +MOSTLYCLEANFILES = core *.stackdump + +EXTRA_DIST = .libs $(noinst_LTLIBRARIES) diff --git a/lib/core/src/aes.c b/lib/core/src/aes.c new file mode 100644 index 0000000000..c732b0e98e --- /dev/null +++ b/lib/core/src/aes.c @@ -0,0 +1,1344 @@ +#define FULL_UNROLL + +#define TRACE_MODULE _aes +#include "core_debug.h" +#include "core_aes.h" + +static const c_uint32_t Te0[256] = +{ + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; + +static const c_uint32_t Te1[256] = +{ + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; + +static const c_uint32_t Te2[256] = +{ + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; + +static const c_uint32_t Te3[256] = +{ + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; + +static const c_uint32_t Te4[256] = +{ + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; + +static const c_uint32_t Td0[256] = +{ + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; + +static const c_uint32_t Td1[256] = +{ + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; + +static const c_uint32_t Td2[256] = +{ + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; + +static const c_uint32_t Td3[256] = +{ + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; + +static const c_uint32_t Td4[256] = +{ + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; + +static const c_uint32_t rcon[] = +{ + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, + /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +#define GETU32(plaintext) (((c_uint32_t)(plaintext)[0] << 24) ^ \ + ((c_uint32_t)(plaintext)[1] << 16) ^ \ + ((c_uint32_t)(plaintext)[2] << 8) ^ \ + ((c_uint32_t)(plaintext)[3])) + +#define PUTU32(ciphertext, st) { (ciphertext)[0] = (c_uint8_t)((st) >> 24); \ + (ciphertext)[1] = (c_uint8_t)((st) >> 16); \ + (ciphertext)[2] = (c_uint8_t)((st) >> 8); \ + (ciphertext)[3] = (c_uint8_t)(st); } + +/** + * Expand the cipher key into the encryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +int aes_setup_enc(c_uint32_t *rk, const c_uint8_t *key, int keybits) +{ + int i = 0; + c_uint32_t temp; + + rk[0] = GETU32(key ); + rk[1] = GETU32(key + 4); + rk[2] = GETU32(key + 8); + rk[3] = GETU32(key + 12); + if (keybits == 128) + { + for (;;) + { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) + return 10; + rk += 4; + } + } + rk[4] = GETU32(key + 16); + rk[5] = GETU32(key + 20); + if (keybits == 192) + { + for (;;) + { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) + return 12; + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(key + 24); + rk[7] = GETU32(key + 28); + if (keybits == 256) + { + for (;;) + { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) + return 14; + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + rk += 8; + } + } + return 0; +} + +/** + * Expand the cipher key into the decryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +int aes_setup_dec(c_uint32_t *rk, const c_uint8_t *key, int keybits) +{ + int nrounds, i, j; + c_uint32_t temp; + + /* expand the cipher key: */ + nrounds = aes_setup_enc(rk, key, keybits); + /* invert the order of the round keys: */ + for (i = 0, j = 4*nrounds; i < j; i += 4, j -= 4) + { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + for (i = 1; i < nrounds; i++) + { + rk += 4; + rk[0] = + Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + rk[1] = + Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + rk[2] = + Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + rk[3] = + Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + } + return nrounds; +} + +void aes_encrypt(const c_uint32_t *rk, int nrounds, const c_uint8_t plaintext[16], + c_uint8_t ciphertext[16]) +{ + c_uint32_t s0, s1, s2, s3, t0, t1, t2, t3; + #ifndef FULL_UNROLL + int r; + #endif /* ?FULL_UNROLL */ + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(plaintext ) ^ rk[0]; + s1 = GETU32(plaintext + 4) ^ rk[1]; + s2 = GETU32(plaintext + 8) ^ rk[2]; + s3 = GETU32(plaintext + 12) ^ rk[3]; + #ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; + if (nrounds > 10) + { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; + if (nrounds > 12) + { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += nrounds << 2; + #else /* !FULL_UNROLL */ + /* + * nrounds - 1 full rounds: + */ + r = nrounds >> 1; + for (;;) + { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + rk += 8; + if (--r == 0) + break; + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } + #endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4[(t0 >> 24) ] & 0xff000000) ^ + (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(ciphertext , s0); + s1 = + (Te4[(t1 >> 24) ] & 0xff000000) ^ + (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(ciphertext + 4, s1); + s2 = + (Te4[(t2 >> 24) ] & 0xff000000) ^ + (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(ciphertext + 8, s2); + s3 = + (Te4[(t3 >> 24) ] & 0xff000000) ^ + (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(ciphertext + 12, s3); +} + +void aes_decrypt(const c_uint32_t *rk, int nrounds, const c_uint8_t ciphertext[16], + c_uint8_t plaintext[16]) +{ + c_uint32_t s0, s1, s2, s3, t0, t1, t2, t3; + #ifndef FULL_UNROLL + int r; + #endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(ciphertext ) ^ rk[0]; + s1 = GETU32(ciphertext + 4) ^ rk[1]; + s2 = GETU32(ciphertext + 8) ^ rk[2]; + s3 = GETU32(ciphertext + 12) ^ rk[3]; + #ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; + if (nrounds > 10) + { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; + if (nrounds > 12) + { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += nrounds << 2; + #else /* !FULL_UNROLL */ + /* + * nrounds - 1 full rounds: + */ + r = nrounds >> 1; + for (;;) + { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + rk += 8; + if (--r == 0) + break; + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } + #endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(plaintext , s0); + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(plaintext + 4, s1); + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(plaintext + 8, s2); + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(plaintext + 12, s3); +} + +status_t aes_cbc_encrypt(const c_uint8_t *key, const c_uint32_t keybits, + c_uint8_t *ivec, const c_uint8_t *in, const c_uint32_t inlen, + c_uint8_t *out, c_uint32_t *outlen) +{ + c_uint32_t n; + c_uint32_t len = inlen; + const c_uint8_t *iv = ivec; + + c_uint32_t rk[RKLENGTH(MAX_KEY_BITS)]; + int nrounds; + + d_assert(key, return CORE_ERROR, "Null param"); + d_assert(keybits >= 128, return CORE_ERROR, + "param 'keybits' must be larger than 128"); + d_assert(ivec, return CORE_ERROR, "Null param"); + d_assert(in, return CORE_ERROR, "Null param"); + d_assert(inlen, return CORE_ERROR, "param 'inlen' is zero"); + d_assert(out, return CORE_ERROR, "Null param"); + d_assert(outlen, return CORE_ERROR, "Null param"); + + if (*outlen < ((inlen - 1) / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE) + { + return CORE_ERROR; + } + + *outlen = ((inlen - 1) / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE; + + nrounds = aes_setup_enc(rk, key, keybits); + + while (len >= AES_BLOCK_SIZE) + { + for(n=0; n < AES_BLOCK_SIZE; ++n) + out[n] = in[n] ^ iv[n]; + aes_encrypt(rk, nrounds, out, out); + iv = out; + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + + if (len) + { + for(n=0; n < len; ++n) + out[n] = in[n] ^ iv[n]; + for(n=len; n < AES_BLOCK_SIZE; ++n) + out[n] = iv[n]; + aes_encrypt(rk, nrounds, out, out); + iv = out; + } + + memcpy(ivec, iv, AES_BLOCK_SIZE); + + return CORE_OK; +} + +status_t aes_cbc_decrypt(const c_uint8_t *key, const c_uint32_t keybits, + c_uint8_t *ivec, const c_uint8_t *in, const c_uint32_t inlen, + c_uint8_t *out, c_uint32_t *outlen) +{ + c_uint32_t n; + c_uint32_t len = inlen; + c_uint8_t tmp[AES_BLOCK_SIZE]; + const c_uint8_t *iv = ivec; + + c_uint32_t rk[RKLENGTH(MAX_KEY_BITS)]; + int nrounds; + + d_assert(key, return CORE_ERROR, "Null param"); + d_assert(keybits >= 128, return CORE_ERROR, + "param 'keybits' must be larger than 128"); + d_assert(ivec, return CORE_ERROR, "Null param"); + d_assert(in, return CORE_ERROR, "Null param"); + d_assert(inlen, return CORE_ERROR, "param 'inlen' is zero"); + d_assert(out, return CORE_ERROR, "Null param"); + d_assert(outlen, return CORE_ERROR, "Null param"); + + if (inlen % AES_BLOCK_SIZE != 0) + { + return CORE_ERROR; + } + + *outlen = inlen; + + nrounds = aes_setup_dec(rk, key, keybits); + + if (in != out) + { + while (len >= AES_BLOCK_SIZE) + { + aes_decrypt(rk, nrounds, in, out); + for(n=0; n < AES_BLOCK_SIZE; ++n) + out[n] ^= iv[n]; + iv = in; + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + + if (len) + { + aes_decrypt(rk, nrounds, in, tmp); + for(n=0; n < len; ++n) + out[n] = tmp[n] ^ iv[n]; + iv = in; + } + + memcpy(ivec, iv, AES_BLOCK_SIZE); + } + else + { + while (len >= AES_BLOCK_SIZE) + { + memcpy(tmp, in, AES_BLOCK_SIZE); + + aes_decrypt(rk, nrounds, in, out); + for(n=0; n < AES_BLOCK_SIZE; ++n) + out[n] ^= ivec[n]; + memcpy(ivec, tmp, AES_BLOCK_SIZE); + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + + if (len) + { + memcpy(tmp, in, AES_BLOCK_SIZE); + aes_decrypt(rk, nrounds, tmp, out); + for(n=0; n < len; ++n) + out[n] ^= ivec[n]; + for(n=len; n < AES_BLOCK_SIZE; ++n) + out[n] = tmp[n]; + + memcpy(ivec, tmp, AES_BLOCK_SIZE); + } + } + + return CORE_OK; +} diff --git a/lib/core/src/aes_cmac.c b/lib/core/src/aes_cmac.c new file mode 100644 index 0000000000..6860ca19ee --- /dev/null +++ b/lib/core/src/aes_cmac.c @@ -0,0 +1,272 @@ +#define TRACE_MODULE _cmac +#include "core.h" +#include "core_debug.h" +#include "core_aes_cmac.h" + +#if (AES_BLOCK_SIZE != 16) +#error "Wrong AES block size" +#endif + +/* From RFC 4493 + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + Algorithm Generate_Subkey + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + + + + Input : K (128-bit key) + + + Output : K1 (128-bit first subkey) + + + K2 (128-bit second subkey) + + +-------------------------------------------------------------------+ + + + + + Constants: const_Zero is 0x00000000000000000000000000000000 + + + const_Rb is 0x00000000000000000000000000000087 + + + Variables: L for output of AES-128 applied to 0^128 + + + + + + Step 1. L := AES-128(K, const_Zero); + + + Step 2. if MSB(L) is equal to 0 + + + then K1 := L << 1; + + + else K1 := (L << 1) XOR const_Rb; + + + Step 3. if MSB(K1) is equal to 0 + + + then K2 := K1 << 1; + + + else K2 := (K1 << 1) XOR const_Rb; + + + Step 4. return K1, K2; + + + + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +static status_t _generate_subkey(c_uint8_t *k1, c_uint8_t *k2, + const c_uint8_t *key) +{ + c_uint8_t zero[16] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + c_uint8_t rb[16] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87 + }; + c_uint8_t L[16]; + + c_uint32_t rk[RKLENGTH(MAX_KEY_BITS)]; + int i, nrounds; + + /* Step 1. L := AES-128(K, const_Zero) */ + nrounds = aes_setup_enc(rk, key, 128); + aes_encrypt(rk, nrounds, zero, L); + + /* Step 2. if MSB(L) is equal to 0 */ + if ((L[0] & 0x80) == 0) + { + /* then k1 := L << 1; */ + for (i = 0; i < 15; i++) + k1[i] = ((L[i] << 1) & 0xfe) | ((L[i + 1] & 0x80) ? 1 : 0); + k1[15] = ((L[15] << 1) & 0xfe); + } + else + { + /* else k1 := (L << 1) XOR const_Rb; */ + for (i = 0; i < 15; i++) + k1[i] = (((L[i] << 1) & 0xfe) | ((L[i + 1] & 0x80) ? 1 : 0)) + ^ rb[i]; + k1[15] = ((L[15] << 1) & 0xfe) ^ rb[15]; + } + + /* Step 3. if MSB(k1) is equal to 0 */ + if ((k1[0] & 0x80) == 0) + { + /* then k2 := k2 << 1; */ + for (i = 0; i < 15; i++) + k2[i] = ((k1[i] << 1) & 0xfe) | ((k1[i + 1] & 0x80) ? 1 : 0); + k2[15] = ((k1[15] << 1) & 0xfe); + } + else + { + /* else k2 := (k2 << 1) XOR const_Rb; */ + for (i = 0; i < 15; i++) + k2[i] = (((k1[i] << 1) & 0xfe) | ((k1[i + 1] & 0x80) ? 1 : 0)) + ^ rb[i]; + k2[15] = ((k1[15] << 1) & 0xfe) ^ rb[15]; + } + + return CORE_OK; +} + +/* From RFC 4493 + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + Algorithm AES-CMAC + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + + + + Input : K ( 128-bit key ) + + + : M ( message to be authenticated ) + + + : len ( length of the message in octets ) + + + Output : T ( message authentication code ) + + + + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + Constants: const_Zero is 0x00000000000000000000000000000000 + + + const_Bsize is 16 + + + + + + Variables: K1, K2 for 128-bit subkeys + + + M_i is the i-th block (i=1..ceil(len/const_Bsize)) + + + M_last is the last block xor-ed with K1 or K2 + + + n for number of blocks to be processed + + + r for number of octets of last block + + + flag for denoting if last block is complete or not + + + + + + Step 1. (K1,K2) := Generate_Subkey(K); + + + Step 2. n := ceil(len/const_Bsize); + + + Step 3. if n = 0 + + + then + + + n := 1; + + + flag := false; + + + else + + + if len mod const_Bsize is 0 + + + then flag := true; + + + else flag := false; + + + + + + Step 4. if flag is true + + + then M_last := M_n XOR K1; + + + else M_last := padding(M_n) XOR K2; + + + Step 5. X := const_Zero; + + + Step 6. for i := 1 to n-1 do + + + begin + + + Y := X XOR M_i; + + + X := AES-128(K,Y); + + + end + + + Y := M_last XOR X; + + + T := AES-128(K,Y); + + + Step 7. return T; + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +status_t aes_cmac_calculate(c_uint8_t *cmac, const c_uint8_t *key, + const c_uint8_t *msg, const c_uint32_t len) +{ + c_uint8_t x[16] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + c_uint8_t y[16], m_last[16]; + c_uint8_t k1[16], k2[16]; + int i, j, n, bs, flag; + c_uint32_t rk[RKLENGTH(MAX_KEY_BITS)]; + int nrounds; + + d_assert(cmac, return CORE_ERROR, "Null param"); + d_assert(key, return CORE_ERROR, "Null param"); + d_assert(msg, return CORE_ERROR, "Null param"); + + /* Step 1. (K1,K2) := Generate_Subkey(K); */ + _generate_subkey(k1, k2, key); + + /* Step 2. n := ceil(len/const_Bsize); */ + n = (len + 15) / AES_BLOCK_SIZE; + + /* Step 3. if n = 0 + then + n := 1; + flag := false; + else + if len mod const_Bsize is 0 + then flag := true; + else flag := false; + */ + if (n == 0) + { + n = 1; + flag = 0; + } + else + { + if (len % AES_BLOCK_SIZE == 0) + flag = 1; + else + flag = 0; + } + + /* Step 4. if flag is true + then M_last := M_n XOR K1; + else M_last := padding(M_n) XOR K2; + */ + bs = (n - 1) * AES_BLOCK_SIZE; + + if (flag) + { + for (i = 0; i < 16; i++) + m_last[i] = msg[bs + i] ^ k1[i]; + } + else + { + for (i = 0; i < len % AES_BLOCK_SIZE; i++) + m_last[i] = msg[bs + i] ^ k2[i]; + + m_last[i] = 0x80 ^ k2[i]; + + for (i = i + 1; i < AES_BLOCK_SIZE; i++) + m_last[i] = 0x00 ^ k2[i]; + } + + + /* Step 5. X := const_Zero; */ + /* Step 6. for i := 1 to n-1 do + begin + Y := X XOR M_i; + X := AES-128(K,Y); + end + Y := M_last XOR X; + T := AES-128(K,Y); + */ + + nrounds = aes_setup_enc(rk, key, 128); + + for (i = 0; i <= n - 2; i++) + { + bs = i * AES_BLOCK_SIZE; + for (j = 0; j < 16; j++) + y[j] = x[j] ^ msg[bs + j]; + aes_encrypt(rk, nrounds, y, x); + } + + bs = (n - 1) * AES_BLOCK_SIZE; + for (j = 0; j < 16; j++) + y[j] = m_last[j] ^ x[j]; + aes_encrypt(rk, nrounds, y, cmac); + + return CORE_OK; +} + +/* From RFC 4493 + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + Algorithm Verify_MAC + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + + + + Input : K ( 128-bit Key ) + + + : M ( message to be verified ) + + + : len ( length of the message in octets ) + + + : T' ( the received MAC to be verified ) + + + Output : INVALID or VALID + + + + + +-------------------------------------------------------------------+ + + + + + Step 1. T* := AES-CMAC(K,M,len); + + + Step 2. if T* is equal to T' + + + then + + + return VALID; + + + else + + + return INVALID; + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +status_t aes_cmac_verify(c_uint8_t *cmac, const c_uint8_t *key, + const c_uint8_t *msg, const c_uint32_t len) +{ + status_t rv; + c_uint8_t cmac_calc[16]; + + rv = aes_cmac_calculate(cmac_calc, key, msg, len); + if (rv != CORE_OK) + return rv; + + if (memcmp(cmac_calc, cmac, 16) != 0) + return ERR_INVALID_CMAC; + + return CORE_OK; +} diff --git a/lib/core/src/debug.c b/lib/core/src/debug.c new file mode 100644 index 0000000000..6d6fb3ac1b --- /dev/null +++ b/lib/core/src/debug.c @@ -0,0 +1,405 @@ +#include "core_debug.h" +#include "core_param.h" +#include "core_file.h" + +#include +#include +#include +#include + +int g_trace_mask = 1; + +int g_msg_to = D_MSG_TO_LOGD | D_MSG_TO_STDOUT; + +int g_console_connected = 0; +int g_syslog_connected = 0; +int g_logd_connected = 0; + +int g_log_level_console = D_LOG_LEVEL_FULL; +int g_log_level_stdout = D_LOG_LEVEL_FULL; +int g_log_level_syslog = D_LOG_LEVEL_FULL; +int g_log_level_logd = D_LOG_LEVEL_FULL; + +int g_console_fd = -1; +int g_logd_fd = -1; +struct sockaddr_un g_logd_addr; + +void d_msg_init() +{ + openlog("wmcore", 0, LOG_DAEMON); + + g_syslog_connected = 1; + + g_logd_fd = socket(AF_UNIX, SOCK_DGRAM, 0); + d_assert(g_logd_fd >= 0, return, + "socket() failed. (%d:%s)\n", errno, strerror(errno)); + + g_logd_addr.sun_family = AF_UNIX; + strcpy(g_logd_addr.sun_path, D_LOGD_IPC_PATH); + + g_logd_connected = 1; +} + +void d_msg_final() +{ + g_syslog_connected = 0; + closelog(); + + g_logd_connected = 0; + close(g_logd_fd); + g_logd_fd = -1; +} + +void d_msg_register_console(int console_fd) +{ + d_assert(console_fd >= 0, return, "param 'console_fd' is invalid"); + + g_console_fd = console_fd; + g_console_connected = 1; +} + +void d_msg_deregister_console() +{ + g_console_connected = 0; + g_console_fd = -1; +} + +void d_msg_to(int to, int on_off) +{ + switch (to) + { + case D_MSG_TO_CONSOLE: + g_msg_to = on_off ? + g_msg_to | D_MSG_TO_CONSOLE : + g_msg_to & ~D_MSG_TO_CONSOLE; + break; + case D_MSG_TO_STDOUT: + g_msg_to = on_off ? + g_msg_to | D_MSG_TO_STDOUT : + g_msg_to & ~D_MSG_TO_STDOUT; + break; + case D_MSG_TO_SYSLOG: + g_msg_to = on_off ? + g_msg_to | D_MSG_TO_SYSLOG : + g_msg_to & ~D_MSG_TO_SYSLOG; + break; + case D_MSG_TO_LOGD: + g_msg_to = on_off ? + g_msg_to | D_MSG_TO_LOGD : + g_msg_to & ~D_MSG_TO_LOGD; + break; + case D_MSG_TO_ALL: + g_msg_to = on_off ? D_MSG_TO_ALL : 0; + break; + default: + break; + } +} + +int d_msg_get_to() +{ + return g_msg_to; +} + +void d_log_set_level(int to, int level) +{ + switch (to) + { + case D_MSG_TO_CONSOLE: + g_log_level_console = level; + break; + case D_MSG_TO_STDOUT: + g_log_level_stdout = level; + break; + case D_MSG_TO_SYSLOG: + g_log_level_syslog = level; + break; + case D_MSG_TO_LOGD: + g_log_level_logd = level; + break; + case D_MSG_TO_ALL: + g_log_level_console = level; + g_log_level_stdout = level; + g_log_level_syslog = level; + g_log_level_logd = level; + break; + default: + break; + } +} + +int d_log_get_level(int to) +{ + switch (to) + { + case D_MSG_TO_CONSOLE: + return g_log_level_console; + case D_MSG_TO_STDOUT: + return g_log_level_stdout; + case D_MSG_TO_SYSLOG: + return g_log_level_syslog; + case D_MSG_TO_LOGD: + return g_log_level_logd; + default: + break; + } + + return -1; +} + +void d_log_full(int to) +{ + switch (to) + { + case D_MSG_TO_CONSOLE: + g_log_level_console = D_LOG_LEVEL_FULL; + break; + case D_MSG_TO_STDOUT: + g_log_level_stdout = D_LOG_LEVEL_FULL; + break; + case D_MSG_TO_SYSLOG: + g_log_level_syslog = D_LOG_LEVEL_FULL; + break; + case D_MSG_TO_LOGD: + g_log_level_logd = D_LOG_LEVEL_FULL; + break; + case D_MSG_TO_ALL: + g_log_level_console = D_LOG_LEVEL_FULL; + g_log_level_stdout = D_LOG_LEVEL_FULL; + g_log_level_syslog = D_LOG_LEVEL_FULL; + g_log_level_logd = D_LOG_LEVEL_FULL; + break; + default: + break; + } +} + +void d_log_off(int to) +{ + switch (to) + { + case D_MSG_TO_CONSOLE: + g_log_level_console = D_LOG_LEVEL_NONE; + break; + case D_MSG_TO_STDOUT: + g_log_level_stdout = D_LOG_LEVEL_NONE; + break; + case D_MSG_TO_SYSLOG: + g_log_level_syslog = D_LOG_LEVEL_NONE; + break; + case D_MSG_TO_LOGD: + g_log_level_logd = D_LOG_LEVEL_NONE; + break; + case D_MSG_TO_ALL: + g_log_level_console = D_LOG_LEVEL_NONE; + g_log_level_stdout = D_LOG_LEVEL_NONE; + g_log_level_syslog = D_LOG_LEVEL_NONE; + g_log_level_logd = D_LOG_LEVEL_NONE; + break; + default: + break; + } +} + +void d_trace_global_on() +{ + g_trace_mask = 1; +} + +void d_trace_global_off() +{ + g_trace_mask = 0; +} + +void d_trace_level(int *mod_name, int level) +{ + *mod_name = level; +} + +void d_trace_off(int *mod_name) +{ + *mod_name = 0; +} + +#define TA_NOR "\033[0m" /* all off */ +#define TA_BOLD "\033[1m" /* bold */ +#define TA_UNDER "\033[4m" /* underscore */ +#define TA_BLINK "\033[5m" /* blink */ +#define TA_REVERSE "\033[7m" /* reverse video */ +#define TA_CONCEALED "\033[8m" /* concealed */ + +#define TA_FGC_BLACK "\033[30m" /* Black */ +#define TA_FGC_RED "\033[31m" /* Red */ +#define TA_FGC_GREEN "\033[32m" /* Green */ +#define TA_FGC_YELLOW "\033[33m" /* Yellow */ +#define TA_FGC_BLUE "\033[34m" /* Blue */ +#define TA_FGC_MAGENTA "\033[35m" /* Magenta */ +#define TA_FGC_CYAN "\033[36m" /* Cyan */ +#define TA_FGC_WHITE "\033[37m" /* White */ +#define TA_FGC_DEFAULT "\033[39m" /* default */ + +#define TA_BGC_BLACK "\033[40m" /* Black */ +#define TA_BGC_RED "\033[41m" /* Red */ +#define TA_BGC_GREEN "\033[42m" /* Green */ +#define TA_BGC_YELLOW "\033[43m" /* Yellow */ +#define TA_BGC_BLUE "\033[44m" /* Blue */ +#define TA_BGC_MAGENTA "\033[45m" /* Magenta */ +#define TA_BGC_CYAN "\033[46m" /* Cyan */ +#define TA_BGC_WHITE "\033[47m" /* White */ +#define TA_BGC_DEFAULT "\033[49m" /* default */ + +#define TIME_FMT_STR "%02d/%02d %02d:%02d:%02d.%03d" +#define TIME_FMT_STR2 "%02d.%06d" +#define TIME_FMT_STR3 "%04d/%02d/%02d %02d:%02d:%02d.%03d" + +int d_msg(int tp, int lv, c_time_t t, char *fn, int ln, char *fmt, ...) +{ + char str[384] = {0}, fstr[512] = {0}, *ac_str; + time_exp_t te; + size_t n; + char *lv_str[5] = {"NONE", "FATL", "ERRR", "WARN", "INFO"}; + + + va_list args; + + va_start(args, fmt); + + if (t) + { + time_exp_lt(&te, t); + } + + switch (tp) + { + case D_MSG_TYPE_RAW: + { + n = vsprintf(fstr, fmt, args); + + if (g_msg_to & D_MSG_TO_STDOUT) + { + printf("%s", fstr); + } + if (g_syslog_connected && (g_msg_to & D_MSG_TO_SYSLOG)) + { + syslog(LOG_DEBUG, "%s", fstr); + } + if (g_logd_connected && (g_msg_to & D_MSG_TO_LOGD)) + { + sendto(g_logd_fd, fstr, n, 0, + (struct sockaddr *)&g_logd_addr, sizeof(g_logd_addr)); + } + if (g_console_connected && (g_msg_to & D_MSG_TO_CONSOLE)) + { + if (fstr[n-1] == '\n') + { + fstr[n-1] = '\r'; fstr[n++] = '\n'; + } + write(g_console_fd, fstr, n); + } + break; + } + case D_MSG_TYPE_TRACE: + { + n = vsprintf(fstr, fmt, args); + + if (g_msg_to & D_MSG_TO_STDOUT) + { + printf("%s", fstr); + } + if (g_syslog_connected && (g_msg_to & D_MSG_TO_SYSLOG)) + { + syslog(LOG_DEBUG, "%s", fstr); + } + if (g_logd_connected && (g_msg_to & D_MSG_TO_LOGD)) + { + sendto(g_logd_fd, fstr, n, 0, + (struct sockaddr *)&g_logd_addr, sizeof(g_logd_addr)); + } + if (g_console_connected && (g_msg_to & D_MSG_TO_CONSOLE)) + { + if (fstr[n-1] == '\n') + { + fstr[n-1] = '\r'; fstr[n++] = '\n'; + } + write(g_console_fd, fstr, n); + } + break; + } + case D_MSG_TYPE_LOG: + { + switch(lv) + { + case D_LOG_LEVEL_INFO: ac_str = TA_FGC_WHITE; break; + case D_LOG_LEVEL_WARN: ac_str = TA_FGC_CYAN; break; + case D_LOG_LEVEL_ERROR: ac_str = TA_FGC_YELLOW; break; + case D_LOG_LEVEL_FATAL: ac_str = TA_FGC_RED; break; + default: ac_str = NULL; break; + } + + vsprintf(str, fmt, args); + + n = sprintf(fstr, "["TIME_FMT_STR"] %s: %s (%s:%d)", + te.tm_mon + 1, te.tm_mday, te.tm_hour, + te.tm_min, te.tm_sec, te.tm_usec/1000, + lv_str[lv], str, fn, ln); + + if ((g_msg_to & D_MSG_TO_STDOUT) && + lv <= g_log_level_stdout) + { + printf("%s%s" TA_NOR "\n", ac_str, fstr); + } + if (g_syslog_connected && (g_msg_to & D_MSG_TO_SYSLOG) && + lv <= g_log_level_syslog) + { + syslog(LOG_INFO, "[%s\n", fstr + 13); + } + if (g_logd_connected && (g_msg_to & D_MSG_TO_LOGD) && + lv <= g_log_level_logd) + { + fstr[n++] = '\n'; + sendto(g_logd_fd, fstr, n, 0, + (struct sockaddr *)&g_logd_addr, sizeof(g_logd_addr)); + } + if (g_console_connected && (g_msg_to & D_MSG_TO_CONSOLE) && + lv <= g_log_level_console) + { + fstr[n++] = '\r'; /* fstr[n++] = '\n'; FIXME: */ + write(g_console_fd, fstr, n); + } + break; + } + case D_MSG_TYPE_ASSERT: + { + vsprintf(str, fmt, args); + + n = sprintf(fstr, "[" TIME_FMT_STR "] ASSERT: %s (%s:%d)", + te.tm_mon + 1, te.tm_mday, te.tm_hour, + te.tm_min, te.tm_sec, te.tm_usec/1000, str, fn, ln); + + if (g_msg_to & D_MSG_TO_STDOUT) + { + printf(TA_BOLD TA_FGC_RED "%s" TA_NOR "\n", fstr); + } + if (g_syslog_connected && (g_msg_to & D_MSG_TO_SYSLOG)) + { + syslog(LOG_CRIT, "[%s\n", fstr + 13); + } + if (g_logd_connected && (g_msg_to & D_MSG_TO_LOGD)) + { + fstr[n++] = '\n'; + sendto(g_logd_fd, fstr, n, 0, + (struct sockaddr *)&g_logd_addr, sizeof(g_logd_addr)); + } + if (g_console_connected && (g_msg_to & D_MSG_TO_CONSOLE)) + { + fstr[n++] = '\r'; /* fstr[n++] = '\n'; FIXME: */ + write(g_console_fd, fstr, n); + } + break; + } + default: + break; + } + + return CORE_OK; +} diff --git a/lib/core/src/fsm.c b/lib/core/src/fsm.c new file mode 100644 index 0000000000..c2b7acd39c --- /dev/null +++ b/lib/core/src/fsm.c @@ -0,0 +1,50 @@ +#include "core_fsm.h" + +static fsm_event_t fsm_event[] = { + FSM_ENTRY_SIG, + FSM_EXIT_SIG +}; + +void fsm_init(fsm_t *s, fsm_event_t *e) +{ + if (s->initial != (fsm_state_t)0) + { + (*s->initial)(s, e); + if (s->initial != s->state) + { + (*s->state)(s, &fsm_event[FSM_ENTRY_SIG]); + } + } +} + +void fsm_dispatch(fsm_t *s, fsm_event_t *e) +{ + fsm_handler_t tmp = s->state; + s->state = (fsm_handler_t)0; + + (*tmp)(s, e); + if (s->state != (fsm_state_t)0) + { + (*tmp)(s, &fsm_event[FSM_EXIT_SIG]); + (*s->state)(s, &fsm_event[FSM_ENTRY_SIG]); + } + else + { + s->state = tmp; + } +} + +void fsm_final(fsm_t *s, fsm_event_t *e) +{ + if (s->final != s->state) + { + (*s->state)(s, &fsm_event[FSM_EXIT_SIG]); + } + + if (s->final != (fsm_state_t)0) + { + (*s->final)(s, 0); + } + + s->state = s->initial; +} diff --git a/lib/core/src/msgq.c b/lib/core/src/msgq.c new file mode 100644 index 0000000000..15cdb790d5 --- /dev/null +++ b/lib/core/src/msgq.c @@ -0,0 +1,310 @@ +#define TRACE_MODULE _msgq +#include "core_debug.h" +#include "core_pool.h" +#include "core_ringbuf.h" +#include "core_cond.h" +#include "core_mutex.h" +#include "core_msgq.h" + +typedef struct _msq_desc_t { + mutex_id mut_c, mut_r, mut_w; + cond_id cond; + int opt; + int qdepth, msgsize, used; + rbuf_declare_ext(rbuf); + unsigned char *pool; +} msg_desc_t; + +pool_declare(msgqpool, msg_desc_t, 3); + +status_t msgq_init(void) +{ + pool_init(&msgqpool, 3); + return CORE_OK; +} + +status_t msgq_final(void) +{ + pool_final(&msgqpool); + return CORE_OK; +} + +msgq_id msgq_create(int qdepth, int msgsize, int opt) +{ + msg_desc_t *md; + int s; + status_t rv; + + if (qdepth == 0 || msgsize == 0) + return 0; + + pool_alloc_node(&msgqpool, &md); + d_assert(md != NULL, return 0, "empty msgq pool"); + + memset((void*)md, 0, sizeof(msg_desc_t)); + + rv = mutex_create(&md->mut_c, MUTEX_DEFAULT); + d_assert(rv == CORE_OK, + goto error_final, "mutex creation failed"); + + rv = mutex_create(&md->mut_r, MUTEX_DEFAULT); + d_assert(rv == CORE_OK, + goto error_final, "mutex creation failed"); + + rv = mutex_create(&md->mut_w, MUTEX_DEFAULT); + d_assert(rv == CORE_OK, + goto error_final, "mutex creation failed"); + + rv = cond_create(&md->cond); + d_assert(rv == CORE_OK, + goto error_final, "mutex creation failed"); + + s = qdepth * (msgsize + 2); + md->pool = malloc(s); + d_assert(md->pool != NULL, + goto error_final, "can't allocate msg q buffer %d bytes", s); + + rbuf_init_ext(&(md->rbuf), s, md->pool); + + md->opt = opt; + md->qdepth = qdepth; + md->msgsize = msgsize; + md->used = 0; + + return (msgq_id)md; + +error_final: + if (md->pool) free(md->pool); + if (md->mut_c) mutex_delete(md->mut_c); + if (md->mut_r) mutex_delete(md->mut_r); + if (md->mut_w) mutex_delete(md->mut_w); + if (md->cond) cond_delete(md->cond); + + pool_free_node(&msgqpool, md); + + return 0; +} + +status_t msgq_delete(msgq_id id) +{ + msg_desc_t *md = (msg_desc_t*)id; + + d_assert(md != NULL, return CORE_ERROR, "param 'id' is null"); + + if (md->pool) free(md->pool); + if (md->mut_c) mutex_delete(md->mut_c); + if (md->cond) cond_delete(md->cond); + + pool_free_node(&msgqpool, md); + + return CORE_OK; +} + +int msgq_send(msgq_id id, const char *msg, int msglen) +{ + msg_desc_t *md = (msg_desc_t*)id; + int n; + unsigned short len = msglen; + + d_assert(md != NULL, return CORE_ERROR, "param 'id' is null"); + d_assert(msg != NULL, return CORE_ERROR, "param 'msg' is null"); + d_assert(msglen <= md->msgsize, return CORE_ERROR, + "'msglen' is bigger than the msg size of queue"); + + d_assert(md->pool != NULL, return CORE_ERROR, "msgq has no ring buffer"); + + mutex_lock(md->mut_w); + + n = rbuf_free_bytes(&md->rbuf); + if (n == 0) + { + mutex_unlock(md->mut_w); + return CORE_EAGAIN; + } + + d_assert(n >= md->msgsize + 2, + mutex_unlock(md->mut_w); return CORE_ERROR, + "msgq integrity broken"); + + n = rbuf_write(&md->rbuf, (const char*)&len, 2); + d_trace(2, "ring write. head:%d tail:%d size:%d len:%d\n", + md->rbuf.h.head, md->rbuf.h.tail, md->rbuf.h.size, 2); + d_assert(n == 2, + mutex_unlock(md->mut_w); return CORE_ERROR, + "msgq integrity broken n:%d", n); + + n += rbuf_write(&md->rbuf, msg, msglen); + d_trace(2, "ring write. head:%d tail:%d size:%d len:%d\n", + md->rbuf.h.head, md->rbuf.h.tail, md->rbuf.h.size, msglen); + d_assert(n == 2 + msglen, + mutex_unlock(md->mut_w); return CORE_ERROR, + "msgq integrity broken n:%d len:%d", n, 2 + msglen); + + if (md->msgsize > msglen) + { + n += rbuf_skip_write_pos(&md->rbuf, md->msgsize - msglen); + d_trace(2, "ring write skip. head:%d tail:%d size:%d len:%d\n", + md->rbuf.h.head, md->rbuf.h.tail, md->rbuf.h.size, + md->msgsize - msglen); + } + + d_assert(n == 2 + md->msgsize, + mutex_unlock(md->mut_w); return CORE_ERROR, + "msgq integrity broken n:%d", n); + + d_trace(1, "msg (%d bytes) pushed.\n", msglen); + + mutex_unlock(md->mut_w); + + mutex_lock(md->mut_c); + cond_signal(md->cond); + mutex_unlock(md->mut_c); + + return msglen; +} + +int msgq_recv(msgq_id id, char *msg, int msglen) +{ + msg_desc_t *md = (msg_desc_t*)id; + unsigned short len; + int n; + + d_assert(md != NULL, return CORE_ERROR, "param 'id' is null"); + d_assert(msg != NULL, return CORE_ERROR, "param 'msg' is null"); + d_assert(msglen >= md->msgsize, return CORE_ERROR, + "'msglen' is smaller than msgsize"); + + d_assert(md->pool != NULL, return CORE_ERROR, "msgq has no ring buffer"); + + mutex_lock(md->mut_r); + + n = rbuf_bytes(&md->rbuf); + + if (!(md->opt & MSGQ_O_NONBLOCK) && (n < md->msgsize + 2)) + { + mutex_lock(md->mut_c); + cond_wait(md->cond, md->mut_c); + mutex_unlock(md->mut_c); + + n = rbuf_bytes(&md->rbuf); + + d_assert(n >= md->msgsize + 2, + mutex_unlock(md->mut_r); return CORE_ERROR, + "msgq integrity broken"); + } + else if (n < md->msgsize + 2) + { + mutex_unlock(md->mut_r); + return CORE_EAGAIN; + } + + n = rbuf_read(&md->rbuf, (char*)&len, 2); + d_trace(2, "ring read. head:%d tail:%d size:%d len:%d\n", + md->rbuf.h.head, md->rbuf.h.tail, md->rbuf.h.size, 2); + d_assert(n == 2, + mutex_unlock(md->mut_r); return CORE_ERROR, + "msgq integrity broken n:%d", len); + + n += rbuf_read(&md->rbuf, msg, len); + d_trace(2, "ring read. head:%d tail:%d size:%d len:%d\n", + md->rbuf.h.head, md->rbuf.h.tail, md->rbuf.h.size, len); + + d_assert(n == 2 + len, + mutex_unlock(md->mut_r); return CORE_ERROR, + "msgq integrity broken n:%d len:%d", n, 2 + len); + + if (md->msgsize > len) + { + n += rbuf_skip_read_pos(&md->rbuf, md->msgsize - len); + d_trace(2, "ring read skip. head:%d tail:%d size:%d len:%d\n", + md->rbuf.h.head, md->rbuf.h.tail, md->rbuf.h.size, + md->msgsize - len); + } + + d_assert(n == 2 + md->msgsize, + mutex_unlock(md->mut_r); return CORE_ERROR, + "msgq integrity broken n:%d s:%d r:%d", + n, md->msgsize, len); + + d_trace(1, "msg (%d bytes) pop.\n", len); + + mutex_unlock(md->mut_r); + + return len; +} + +int msgq_timedrecv(msgq_id id, char *msg, int msglen, c_time_t timeout) +{ + msg_desc_t *md = (msg_desc_t*)id; + unsigned short len; + int n; + status_t rv; + + d_assert(md != NULL, return CORE_ERROR, "param 'id' is null"); + d_assert(msg != NULL, return CORE_ERROR, "param 'msg' is null"); + d_assert(msglen >= md->msgsize, return CORE_ERROR, + "'msglen' is smaller than msgsize"); + + d_assert(md->pool != NULL, return CORE_ERROR, "msgq has no ring buffer"); + + mutex_lock(md->mut_r); + + n = rbuf_bytes(&md->rbuf); + + if (!(md->opt & MSGQ_O_NONBLOCK) && (n < md->msgsize + 2)) + { + mutex_lock(md->mut_c); + rv = cond_timedwait(md->cond, md->mut_c, timeout); + mutex_unlock(md->mut_c); + + if (rv == CORE_TIMEUP) + { + mutex_unlock(md->mut_r); + return CORE_TIMEUP; + } + + n = rbuf_bytes(&md->rbuf); + d_assert(n >= md->msgsize + 2, + mutex_unlock(md->mut_r); return CORE_ERROR, + "msgq integrity broken"); + } + else if (n < md->msgsize + 2) + { + mutex_unlock(md->mut_r); + return CORE_EAGAIN; + } + + n = rbuf_read(&md->rbuf, (char*)&len, 2); + d_trace(2, "ring read. head:%d tail:%d size:%d len:%d\n", + md->rbuf.h.head, md->rbuf.h.tail, md->rbuf.h.size, 2); + d_assert(n == 2, + mutex_unlock(md->mut_r); return CORE_ERROR, + "msgq integrity broken n:%d", len); + + n += rbuf_read(&md->rbuf, msg, len); + d_trace(2, "ring read. head:%d tail:%d size:%d len:%d\n", + md->rbuf.h.head, md->rbuf.h.tail, md->rbuf.h.size, len); + + d_assert(n == 2 + len, + mutex_unlock(md->mut_r); return CORE_ERROR, + "msgq integrity broken n:%d len:%d", n, 2 + len); + + if (md->msgsize > len) + { + n += rbuf_skip_read_pos(&md->rbuf, md->msgsize - len); + d_trace(2, "ring read skip. head:%d tail:%d size:%d len:%d\n", + md->rbuf.h.head, md->rbuf.h.tail, md->rbuf.h.size, + md->msgsize - len); + } + + d_assert(n == 2 + md->msgsize, + mutex_unlock(md->mut_r); return CORE_ERROR, + "msgq integrity broken n:%d s:%d r:%d", + n, md->msgsize, len); + + d_trace(1, "msg (%d bytes) pop.\n", len); + + mutex_unlock(md->mut_r); + + return len; +} diff --git a/lib/core/src/ringbuf.c b/lib/core/src/ringbuf.c new file mode 100644 index 0000000000..f26b529253 --- /dev/null +++ b/lib/core/src/ringbuf.c @@ -0,0 +1,170 @@ +#define TRACE_MODULE _ringbuf +#include "core_debug.h" +#include "core_ringbuf.h" + +#define _rbuf_bytes(__h, __t, __s) \ + (((__h) < (__t)) ? (__h) + (__s) - (__t) + 1 : (__h) - (__t)) + +#define _rbuf_free_bytes(__h, __t, __s) \ + (((__h) < (__t)) ? (__t) - (__h) - 1 : (__t) + (__s) - (__h)) + +int rbuf_bytes(void *__pname) +{ + int h, t; + + struct _rbuf_header_t *ptr_h = (struct _rbuf_header_t*)__pname; + + /* Store for thread safety */ + h = ptr_h->head; t = ptr_h->tail; + + return _rbuf_bytes(h, t, ptr_h->size); +} + +int rbuf_free_bytes(void *__pname) +{ + int h, t; + + struct _rbuf_header_t *ptr_h = (struct _rbuf_header_t*)__pname; + + /* Store for thread safety */ + h = ptr_h->head; t = ptr_h->tail; + + return _rbuf_free_bytes(h, t, ptr_h->size); +} + +#define rbuf_is_empty(__pname) ((__pname)->h.head == (__pname)->h.tail) + +#define rbuf_is_full(__pname) (rbuf_free_bytes(__pname) == 0) + +int rbuf_skip_write_pos(void *__pname, int __len) +{ + /* Write operation must handle only head pointer */ + + int n, h, t; + + struct _rbuf_header_t *ptr_h = (struct _rbuf_header_t*)__pname; + + if (ptr_h == NULL) + return -1; + + t = ptr_h->tail; /* Store for thread safety with read thread */ + h = ptr_h->head; + + /* Check available buffer size */ + n = _rbuf_free_bytes(h, t, ptr_h->size); + /* If no space, return */ + if (n == 0) + return -1; + /* Determin the number of bytes to be skipped */ + n = n < __len ? n : __len; + + /* In this function, only ptr_h->head should be updated */ + ptr_h->head = (h + n) % (ptr_h->size + 1); + + return n; +} + +int rbuf_write(void *__pname, const char *__buf, int __buf_len) +{ + /* Write operation must handle only head pointer */ + + int n, h, t; + + struct _rbuf_header_t *ptr_h = (struct _rbuf_header_t*)__pname; + + if (ptr_h == NULL) + return -1; + + t = ptr_h->tail; /* Store for thread safety with read thread */ + h = ptr_h->head; + + /* Check available buffer size */ + n = _rbuf_free_bytes(h, t, ptr_h->size); + /* If no space, return */ + if (n == 0) + return -1; + /* Determin the number of bytes to be written */ + n = n < __buf_len ? n : __buf_len; + + if ((t > h) || (n < ptr_h->size - h + 1)) + { + memcpy(ptr_h->pool + h, __buf, n); + } + else + { + memcpy(ptr_h->pool + h, __buf, ptr_h->size - h + 1); + memcpy(ptr_h->pool, __buf + (ptr_h->size - h + 1), + n - (ptr_h->size - h + 1)); + } + + /* In this function, only ptr_h->head should be updated */ + ptr_h->head = (h + n) % (ptr_h->size + 1); + + return n; +} + +int rbuf_skip_read_pos(void *__pname, int __len) +{ + /* Read operation must handle only tail pointer */ + int n, h, t; + + struct _rbuf_header_t *ptr_h = (struct _rbuf_header_t*)__pname; + + if (ptr_h == NULL) + return -1; + + h = ptr_h->head; /* Store for thread safety with write thread */ + t = ptr_h->tail; + + /* Check filled buffer size */ + n = _rbuf_bytes(h, t, ptr_h->size); + /* If empty, return */ + if (n == 0) + return -1; + /* Determine the number of bytes to be skipped */ + n = n < __len ? n : __len; + + /* In this function, only ptr_h->tail should be updated */ + ptr_h->tail = (t + n) % (ptr_h->size + 1); + + return n; +} + +int rbuf_read(void *__pname, char *__buf, int __buf_len) +{ + /* Read operation must handle only tail pointer */ + + int n, h, t; + + struct _rbuf_header_t *ptr_h = (struct _rbuf_header_t*)__pname; + + if (ptr_h == NULL) + return -1; + + h = ptr_h->head; /* Store for thread safety with write thread */ + t = ptr_h->tail; + + /* Check filled buffer size */ + n = _rbuf_bytes(h, t, ptr_h->size); + /* If empty, return */ + if (n == 0) + return -1; + /* Determine the number of bytes to be read */ + n = n < __buf_len ? n : __buf_len; + + if (t < h || (n < ptr_h->size - t + 1)) + { + memcpy(__buf, ptr_h->pool + t, n); + } + else + { + memcpy(__buf, ptr_h->pool + t, ptr_h->size - t + 1); + memcpy(__buf + (ptr_h->size - t + 1), ptr_h->pool, + n - (ptr_h->size - t + 1)); + } + + /* In this function, only ptr_h->tail should be updated */ + ptr_h->tail = (t + n) % (ptr_h->size + 1); + + return n; +} diff --git a/lib/core/src/sha1.c b/lib/core/src/sha1.c new file mode 100644 index 0000000000..edd3b4fb42 --- /dev/null +++ b/lib/core/src/sha1.c @@ -0,0 +1,404 @@ +/* + * sha1.c + * + * Copyright (C) 1998, 2009 + * Paul E. Jones + * All Rights Reserved + * + ***************************************************************************** + * $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $ + ***************************************************************************** + * + * Description: + * This file implements the Secure Hashing Standard as defined + * in FIPS PUB 180-1 published April 17, 1995. + * + * The Secure Hashing Standard, which uses the Secure Hashing + * Algorithm (SHA), produces a 160-bit message digest for a + * given data stream. In theory, it is highly improbable that + * two messages will produce the same message digest. Therefore, + * this algorithm can serve as a means of providing a "fingerprint" + * for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code was + * written with the expectation that the processor has at least + * a 32-bit machine word size. If the machine word size is larger, + * the code should still function properly. One caveat to that + * is that the input functions taking characters and character + * arrays assume that only 8 bits of information are stored in each + * character. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated for + * messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is a + * multiple of the size of an 8-bit character. + * + */ + +#include "core_sha1.h" + +/* + * Define the circular shift macro + */ +#define SHA1CircularShift(bits,word) \ + ((((word) << (bits)) & 0xFFFFFFFF) | \ + ((word) >> (32-(bits)))) + +/* Function prototypes */ +static void SHA1ProcessMessageBlock(sha1_ctx *); +static void SHA1PadMessage(sha1_ctx *); + +/* + * sha1_init + * + * Description: + * This function will initialize the sha1_ctx in preparation + * for computing a new message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void sha1_init(sha1_ctx *ctx) +{ + ctx->Length_Low = 0; + ctx->Length_High = 0; + ctx->Message_Block_Index = 0; + + ctx->Message_Digest[0] = 0x67452301; + ctx->Message_Digest[1] = 0xEFCDAB89; + ctx->Message_Digest[2] = 0x98BADCFE; + ctx->Message_Digest[3] = 0x10325476; + ctx->Message_Digest[4] = 0xC3D2E1F0; + + ctx->Computed = 0; + ctx->Corrupted = 0; +} + +/* + * sha1_final + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array within the sha1_ctx provided + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * + * Returns: + * 1 if successful, 0 if it failed. + * + * Comments: + * + */ +#if 0 /* modifed by anoveth */ +void sha1_final(sha1_ctx *ctx) +#else +void sha1_final(sha1_ctx *ctx, c_uint8_t *digest) +#endif +{ +#if 0 /* blocked by anoveth */ + if (ctx->Corrupted) + { + return 0; + } +#endif + + if (!ctx->Computed) + { + SHA1PadMessage(ctx); + ctx->Computed = 1; + } + +#if 0 /* modified by anoveth */ + return 1; +#else + { +#if WORDS_BIGENDIAN + memcpy(digest, ctx->Message_Digest, SHA1_DIGEST_SIZE); +#else +#define ROTR(a) ((((unsigned)(a))>>8)|((a)<<24)) +#define ROTL(a) (((a)<<8)|(((unsigned)(a))>>24)) +#define SWAP32(a) (ROTL((a)&0xff00ff00)|ROTR((a)&0x00ff00ff)) + c_uint32_t n[5]; + n[0] = SWAP32(ctx->Message_Digest[0]); + n[1] = SWAP32(ctx->Message_Digest[1]); + n[2] = SWAP32(ctx->Message_Digest[2]); + n[3] = SWAP32(ctx->Message_Digest[3]); + n[4] = SWAP32(ctx->Message_Digest[4]); + + memcpy(digest, n, SHA1_DIGEST_SIZE); + } +#endif +#endif +} + +/* + * sha1_update + * + * Description: + * This function accepts an array of octets as the next portion of + * the message. + * + * Parameters: + * context: [in/out] + * The SHA-1 context to update + * message_array: [in] + * An array of characters representing the next portion of the + * message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void sha1_update(sha1_ctx *ctx, const c_uint8_t *message_array, + c_uint32_t length) +{ + if (!length) + { + return; + } + + if (ctx->Computed || ctx->Corrupted) + { + ctx->Corrupted = 1; + return; + } + + while(length-- && !ctx->Corrupted) + { + ctx->Message_Block[ctx->Message_Block_Index++] = + (*message_array & 0xFF); + + ctx->Length_Low += 8; + /* Force it to 32 bits */ + ctx->Length_Low &= 0xFFFFFFFF; + if (ctx->Length_Low == 0) + { + ctx->Length_High++; + /* Force it to 32 bits */ + ctx->Length_High &= 0xFFFFFFFF; + if (ctx->Length_High == 0) + { + /* Message is too long */ + ctx->Corrupted = 1; + } + } + + if (ctx->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(ctx); + } + + message_array++; + } +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in the SHAContext, especially the + * single character names, were used because those were the names + * used in the publication. + * + * + */ +static void SHA1ProcessMessageBlock(sha1_ctx *ctx) +{ + const unsigned K[] = /* Constants defined in SHA-1 */ + { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + unsigned temp; /* Temporary word value */ + unsigned W[80]; /* Word sequence */ + unsigned A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = ((unsigned) ctx->Message_Block[t * 4]) << 24; + W[t] |= ((unsigned) ctx->Message_Block[t * 4 + 1]) << 16; + W[t] |= ((unsigned) ctx->Message_Block[t * 4 + 2]) << 8; + W[t] |= ((unsigned) ctx->Message_Block[t * 4 + 3]); + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = ctx->Message_Digest[0]; + B = ctx->Message_Digest[1]; + C = ctx->Message_Digest[2]; + D = ctx->Message_Digest[3]; + E = ctx->Message_Digest[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + ctx->Message_Digest[0] = + (ctx->Message_Digest[0] + A) & 0xFFFFFFFF; + ctx->Message_Digest[1] = + (ctx->Message_Digest[1] + B) & 0xFFFFFFFF; + ctx->Message_Digest[2] = + (ctx->Message_Digest[2] + C) & 0xFFFFFFFF; + ctx->Message_Digest[3] = + (ctx->Message_Digest[3] + D) & 0xFFFFFFFF; + ctx->Message_Digest[4] = + (ctx->Message_Digest[4] + E) & 0xFFFFFFFF; + + ctx->Message_Block_Index = 0; +} + +/* + * SHA1PadMessage + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call SHA1ProcessMessageBlock() + * appropriately. When it returns, it can be assumed that the + * message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * + * Returns: + * Nothing. + * + * Comments: + * + */ +static void SHA1PadMessage(sha1_ctx *ctx) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (ctx->Message_Block_Index > 55) + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0x80; + while(ctx->Message_Block_Index < 64) + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(ctx); + + while(ctx->Message_Block_Index < 56) + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0; + } + } + else + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0x80; + while(ctx->Message_Block_Index < 56) + { + ctx->Message_Block[ctx->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + ctx->Message_Block[56] = (ctx->Length_High >> 24) & 0xFF; + ctx->Message_Block[57] = (ctx->Length_High >> 16) & 0xFF; + ctx->Message_Block[58] = (ctx->Length_High >> 8) & 0xFF; + ctx->Message_Block[59] = (ctx->Length_High) & 0xFF; + ctx->Message_Block[60] = (ctx->Length_Low >> 24) & 0xFF; + ctx->Message_Block[61] = (ctx->Length_Low >> 16) & 0xFF; + ctx->Message_Block[62] = (ctx->Length_Low >> 8) & 0xFF; + ctx->Message_Block[63] = (ctx->Length_Low) & 0xFF; + + SHA1ProcessMessageBlock(ctx); +} + +void sha1(const c_uint8_t *message, c_uint32_t len, c_uint8_t *digest) +{ + sha1_ctx ctx; + + sha1_init(&ctx); + sha1_update(&ctx, message, len); + sha1_final(&ctx, digest); +} diff --git a/lib/core/src/sha1_hmac.c b/lib/core/src/sha1_hmac.c new file mode 100644 index 0000000000..47908473b2 --- /dev/null +++ b/lib/core/src/sha1_hmac.c @@ -0,0 +1,120 @@ +/*- + * HMAC-SHA-224/256/384/512 implementation + * Last update: 06/15/2005 + * Issue date: 06/15/2005 + * + * Copyright (C) 2005 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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 + +#include "core_sha1_hmac.h" + +void hmac_sha1_init(hmac_sha1_ctx *ctx, c_uint8_t *key, + c_uint32_t key_size) +{ + c_uint32_t fill; + c_uint32_t num; + + c_uint8_t *key_used; + c_uint8_t key_temp[SHA1_DIGEST_SIZE]; + int i; + + if (key_size == SHA1_BLOCK_SIZE) { + key_used = key; + num = SHA1_BLOCK_SIZE; + } else { + if (key_size > SHA1_BLOCK_SIZE){ + key_used = key_temp; + num = SHA1_DIGEST_SIZE; + sha1(key, key_size, key_used); + } else { /* key_size > SHA1_BLOCK_SIZE */ + key_used = key; + num = key_size; + } + fill = SHA1_BLOCK_SIZE - num; + + memset(ctx->block_ipad + num, 0x36, fill); + memset(ctx->block_opad + num, 0x5c, fill); + } + + for (i = 0; i < num; i++) { + ctx->block_ipad[i] = key_used[i] ^ 0x36; + ctx->block_opad[i] = key_used[i] ^ 0x5c; + } + + sha1_init(&ctx->ctx_inside); + sha1_update(&ctx->ctx_inside, ctx->block_ipad, SHA1_BLOCK_SIZE); + + sha1_init(&ctx->ctx_outside); + sha1_update(&ctx->ctx_outside, ctx->block_opad, + SHA1_BLOCK_SIZE); + + /* for hmac_reinit */ + memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, + sizeof(sha1_ctx)); + memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, + sizeof(sha1_ctx)); +} + +void hmac_sha1_reinit(hmac_sha1_ctx *ctx) +{ + memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, + sizeof(sha1_ctx)); + memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, + sizeof(sha1_ctx)); +} + +void hmac_sha1_update(hmac_sha1_ctx *ctx, c_uint8_t *message, + c_uint32_t message_len) +{ + sha1_update(&ctx->ctx_inside, message, message_len); +} + +void hmac_sha1_final(hmac_sha1_ctx *ctx, c_uint8_t *mac, + c_uint32_t mac_size) +{ + c_uint8_t digest_inside[SHA1_DIGEST_SIZE]; + c_uint8_t mac_temp[SHA1_DIGEST_SIZE]; + + sha1_final(&ctx->ctx_inside, digest_inside); + sha1_update(&ctx->ctx_outside, digest_inside, SHA1_DIGEST_SIZE); + sha1_final(&ctx->ctx_outside, mac_temp); + memcpy(mac, mac_temp, mac_size); +} + +void hmac_sha1(c_uint8_t *key, c_uint32_t key_size, + c_uint8_t *message, c_uint32_t message_len, + c_uint8_t *mac, c_uint32_t mac_size) +{ + hmac_sha1_ctx ctx; + + hmac_sha1_init(&ctx, key, key_size); + hmac_sha1_update(&ctx, message, message_len); + hmac_sha1_final(&ctx, mac, mac_size); +} diff --git a/lib/core/src/sha2.c b/lib/core/src/sha2.c new file mode 100644 index 0000000000..25ad5abee5 --- /dev/null +++ b/lib/core/src/sha2.c @@ -0,0 +1,822 @@ +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ + +#if 0 +#define UNROLL_LOOPS /* Enable loops unrolling */ +#endif + +#define TRACE_MODULE _sha2 +#include "core_debug.h" +#include "core_sha2.h" + +#define SHFR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define CH(x, y, z) ((x & y) ^ (~x & z)) +#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) + +#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) +#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) + +#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) +#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) +#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7)) +#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6)) + +#define UNPACK32(x, str) \ +{ \ + *((str) + 3) = (c_uint8_t) ((x) ); \ + *((str) + 2) = (c_uint8_t) ((x) >> 8); \ + *((str) + 1) = (c_uint8_t) ((x) >> 16); \ + *((str) + 0) = (c_uint8_t) ((x) >> 24); \ +} + +#define PACK32(str, x) \ +{ \ + *(x) = ((c_uint32_t) *((str) + 3) ) \ + | ((c_uint32_t) *((str) + 2) << 8) \ + | ((c_uint32_t) *((str) + 1) << 16) \ + | ((c_uint32_t) *((str) + 0) << 24); \ +} + +#define UNPACK64(x, str) \ +{ \ + *((str) + 7) = (c_uint8_t) ((x) ); \ + *((str) + 6) = (c_uint8_t) ((x) >> 8); \ + *((str) + 5) = (c_uint8_t) ((x) >> 16); \ + *((str) + 4) = (c_uint8_t) ((x) >> 24); \ + *((str) + 3) = (c_uint8_t) ((x) >> 32); \ + *((str) + 2) = (c_uint8_t) ((x) >> 40); \ + *((str) + 1) = (c_uint8_t) ((x) >> 48); \ + *((str) + 0) = (c_uint8_t) ((x) >> 56); \ +} + +#define PACK64(str, x) \ +{ \ + *(x) = ((c_uint64_t) *((str) + 7) ) \ + | ((c_uint64_t) *((str) + 6) << 8) \ + | ((c_uint64_t) *((str) + 5) << 16) \ + | ((c_uint64_t) *((str) + 4) << 24) \ + | ((c_uint64_t) *((str) + 3) << 32) \ + | ((c_uint64_t) *((str) + 2) << 40) \ + | ((c_uint64_t) *((str) + 1) << 48) \ + | ((c_uint64_t) *((str) + 0) << 56); \ +} + +/* Macros used for loops unrolling */ + +#define SHA256_SCR(i) \ +{ \ + w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + + SHA256_F3(w[i - 15]) + w[i - 16]; \ +} + +#define SHA512_SCR(i) \ +{ \ + w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \ + + SHA512_F3(w[i - 15]) + w[i - 16]; \ +} + +#define SHA256_EXP(a, b, c, d, e, f, g, h, j) \ +{ \ + t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + + sha256_k[j] + w[j]; \ + t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ + wv[d] += t1; \ + wv[h] = t1 + t2; \ +} + +#define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \ +{ \ + t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + + sha512_k[j] + w[j]; \ + t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ + wv[d] += t1; \ + wv[h] = t1 + t2; \ +} + +c_uint32_t sha224_h0[8] = + {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; + +c_uint32_t sha256_h0[8] = + {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + +c_uint64_t sha384_h0[8] = + {0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL}; + +c_uint64_t sha512_h0[8] = + {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL}; + +c_uint32_t sha256_k[64] = + {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +c_uint64_t sha512_k[80] = + {0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL}; + +/* SHA-256 functions */ + +void sha256_transf(sha256_ctx *ctx, const c_uint8_t *message, + c_uint32_t block_nb) +{ + c_uint32_t w[64]; + c_uint32_t wv[8]; + c_uint32_t t1, t2; + const c_uint8_t *sub_block; + int i; + +#ifndef UNROLL_LOOPS + int j; +#endif + + for (i = 0; i < (int) block_nb; i++) { + sub_block = message + (i << 6); + +#ifndef UNROLL_LOOPS + for (j = 0; j < 16; j++) { + PACK32(&sub_block[j << 2], &w[j]); + } + + for (j = 16; j < 64; j++) { + SHA256_SCR(j); + } + + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + + for (j = 0; j < 64; j++) { + t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + + sha256_k[j] + w[j]; + t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) { + ctx->h[j] += wv[j]; + } +#else + PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]); + PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]); + PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]); + PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]); + PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]); + PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]); + PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]); + PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]); + + SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19); + SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23); + SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27); + SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31); + SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35); + SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39); + SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43); + SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47); + SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51); + SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55); + SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59); + SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63); + + wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; + wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; + wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; + wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; + + SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1); + SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3); + SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5); + SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7); + SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9); + SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11); + SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13); + SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15); + SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17); + SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19); + SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21); + SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23); + SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25); + SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27); + SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29); + SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31); + SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33); + SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35); + SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37); + SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39); + SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41); + SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43); + SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45); + SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47); + SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49); + SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51); + SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53); + SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55); + SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57); + SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59); + SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61); + SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63); + + ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; + ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; + ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; + ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; +#endif /* !UNROLL_LOOPS */ + } +} + +void sha256(const c_uint8_t *message, c_uint32_t len, c_uint8_t *digest) +{ + sha256_ctx ctx; + + sha256_init(&ctx); + sha256_update(&ctx, message, len); + sha256_final(&ctx, digest); +} + +void sha256_init(sha256_ctx *ctx) +{ +#ifndef UNROLL_LOOPS + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha256_h0[i]; + } +#else + ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1]; + ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3]; + ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5]; + ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7]; +#endif /* !UNROLL_LOOPS */ + + ctx->len = 0; + ctx->tot_len = 0; +} + +void sha256_update(sha256_ctx *ctx, const c_uint8_t *message, + c_uint32_t len) +{ + c_uint32_t block_nb; + c_uint32_t new_len, rem_len, tmp_len; + const c_uint8_t *shifted_message; + + tmp_len = SHA256_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&ctx->block[ctx->len], message, rem_len); + + if (ctx->len + len < SHA256_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA256_BLOCK_SIZE; + + shifted_message = message + rem_len; + + sha256_transf(ctx, ctx->block, 1); + sha256_transf(ctx, shifted_message, block_nb); + + rem_len = new_len % SHA256_BLOCK_SIZE; + + memcpy(ctx->block, &shifted_message[block_nb << 6], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 6; +} + +void sha256_final(sha256_ctx *ctx, c_uint8_t *digest) +{ + c_uint32_t block_nb; + c_uint32_t pm_len; + c_uint32_t len_b; + +#ifndef UNROLL_LOOPS + int i; +#endif + + block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) + < (ctx->len % SHA256_BLOCK_SIZE))); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 6; + + memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + sha256_transf(ctx, ctx->block, block_nb); + +#ifndef UNROLL_LOOPS + for (i = 0 ; i < 8; i++) { + UNPACK32(ctx->h[i], &digest[i << 2]); + } +#else + UNPACK32(ctx->h[0], &digest[ 0]); + UNPACK32(ctx->h[1], &digest[ 4]); + UNPACK32(ctx->h[2], &digest[ 8]); + UNPACK32(ctx->h[3], &digest[12]); + UNPACK32(ctx->h[4], &digest[16]); + UNPACK32(ctx->h[5], &digest[20]); + UNPACK32(ctx->h[6], &digest[24]); + UNPACK32(ctx->h[7], &digest[28]); +#endif /* !UNROLL_LOOPS */ +} + +/* SHA-512 functions */ + +void sha512_transf(sha512_ctx *ctx, const c_uint8_t *message, + c_uint32_t block_nb) +{ + c_uint64_t w[80]; + c_uint64_t wv[8]; + c_uint64_t t1, t2; + const c_uint8_t *sub_block; + int i, j; + + for (i = 0; i < (int) block_nb; i++) { + sub_block = message + (i << 7); + +#ifndef UNROLL_LOOPS + for (j = 0; j < 16; j++) { + PACK64(&sub_block[j << 3], &w[j]); + } + + for (j = 16; j < 80; j++) { + SHA512_SCR(j); + } + + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + + for (j = 0; j < 80; j++) { + t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + + sha512_k[j] + w[j]; + t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) { + ctx->h[j] += wv[j]; + } +#else + PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]); + PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]); + PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]); + PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]); + PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]); + PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]); + PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]); + PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]); + + SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19); + SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23); + SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27); + SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31); + SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35); + SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39); + SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43); + SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47); + SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51); + SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55); + SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59); + SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63); + SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67); + SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71); + SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75); + SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79); + + wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; + wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; + wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; + wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; + + j = 0; + + do { + SHA512_EXP(0,1,2,3,4,5,6,7,j); j++; + SHA512_EXP(7,0,1,2,3,4,5,6,j); j++; + SHA512_EXP(6,7,0,1,2,3,4,5,j); j++; + SHA512_EXP(5,6,7,0,1,2,3,4,j); j++; + SHA512_EXP(4,5,6,7,0,1,2,3,j); j++; + SHA512_EXP(3,4,5,6,7,0,1,2,j); j++; + SHA512_EXP(2,3,4,5,6,7,0,1,j); j++; + SHA512_EXP(1,2,3,4,5,6,7,0,j); j++; + } while (j < 80); + + ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; + ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; + ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; + ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; +#endif /* !UNROLL_LOOPS */ + } +} + +void sha512(const c_uint8_t *message, c_uint32_t len, + c_uint8_t *digest) +{ + sha512_ctx ctx; + + sha512_init(&ctx); + sha512_update(&ctx, message, len); + sha512_final(&ctx, digest); +} + +void sha512_init(sha512_ctx *ctx) +{ +#ifndef UNROLL_LOOPS + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha512_h0[i]; + } +#else + ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1]; + ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3]; + ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5]; + ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7]; +#endif /* !UNROLL_LOOPS */ + + ctx->len = 0; + ctx->tot_len = 0; +} + +void sha512_update(sha512_ctx *ctx, const c_uint8_t *message, + c_uint32_t len) +{ + c_uint32_t block_nb; + c_uint32_t new_len, rem_len, tmp_len; + const c_uint8_t *shifted_message; + + tmp_len = SHA512_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&ctx->block[ctx->len], message, rem_len); + + if (ctx->len + len < SHA512_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA512_BLOCK_SIZE; + + shifted_message = message + rem_len; + + sha512_transf(ctx, ctx->block, 1); + sha512_transf(ctx, shifted_message, block_nb); + + rem_len = new_len % SHA512_BLOCK_SIZE; + + memcpy(ctx->block, &shifted_message[block_nb << 7], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 7; +} + +void sha512_final(sha512_ctx *ctx, c_uint8_t *digest) +{ + c_uint32_t block_nb; + c_uint32_t pm_len; + c_uint32_t len_b; + +#ifndef UNROLL_LOOPS + int i; +#endif + + block_nb = 1 + ((SHA512_BLOCK_SIZE - 17) + < (ctx->len % SHA512_BLOCK_SIZE)); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 7; + + memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + sha512_transf(ctx, ctx->block, block_nb); + +#ifndef UNROLL_LOOPS + for (i = 0 ; i < 8; i++) { + UNPACK64(ctx->h[i], &digest[i << 3]); + } +#else + UNPACK64(ctx->h[0], &digest[ 0]); + UNPACK64(ctx->h[1], &digest[ 8]); + UNPACK64(ctx->h[2], &digest[16]); + UNPACK64(ctx->h[3], &digest[24]); + UNPACK64(ctx->h[4], &digest[32]); + UNPACK64(ctx->h[5], &digest[40]); + UNPACK64(ctx->h[6], &digest[48]); + UNPACK64(ctx->h[7], &digest[56]); +#endif /* !UNROLL_LOOPS */ +} + +/* SHA-384 functions */ + +void sha384(const c_uint8_t *message, c_uint32_t len, + c_uint8_t *digest) +{ + sha384_ctx ctx; + + sha384_init(&ctx); + sha384_update(&ctx, message, len); + sha384_final(&ctx, digest); +} + +void sha384_init(sha384_ctx *ctx) +{ +#ifndef UNROLL_LOOPS + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha384_h0[i]; + } +#else + ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1]; + ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3]; + ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5]; + ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7]; +#endif /* !UNROLL_LOOPS */ + + ctx->len = 0; + ctx->tot_len = 0; +} + +void sha384_update(sha384_ctx *ctx, const c_uint8_t *message, + c_uint32_t len) +{ + c_uint32_t block_nb; + c_uint32_t new_len, rem_len, tmp_len; + const c_uint8_t *shifted_message; + + tmp_len = SHA384_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&ctx->block[ctx->len], message, rem_len); + + if (ctx->len + len < SHA384_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA384_BLOCK_SIZE; + + shifted_message = message + rem_len; + + sha512_transf(ctx, ctx->block, 1); + sha512_transf(ctx, shifted_message, block_nb); + + rem_len = new_len % SHA384_BLOCK_SIZE; + + memcpy(ctx->block, &shifted_message[block_nb << 7], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 7; +} + +void sha384_final(sha384_ctx *ctx, c_uint8_t *digest) +{ + c_uint32_t block_nb; + c_uint32_t pm_len; + c_uint32_t len_b; + +#ifndef UNROLL_LOOPS + int i; +#endif + + block_nb = (1 + ((SHA384_BLOCK_SIZE - 17) + < (ctx->len % SHA384_BLOCK_SIZE))); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 7; + + memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + sha512_transf(ctx, ctx->block, block_nb); + +#ifndef UNROLL_LOOPS + for (i = 0 ; i < 6; i++) { + UNPACK64(ctx->h[i], &digest[i << 3]); + } +#else + UNPACK64(ctx->h[0], &digest[ 0]); + UNPACK64(ctx->h[1], &digest[ 8]); + UNPACK64(ctx->h[2], &digest[16]); + UNPACK64(ctx->h[3], &digest[24]); + UNPACK64(ctx->h[4], &digest[32]); + UNPACK64(ctx->h[5], &digest[40]); +#endif /* !UNROLL_LOOPS */ +} + +/* SHA-224 functions */ + +void sha224(const c_uint8_t *message, c_uint32_t len, + c_uint8_t *digest) +{ + sha224_ctx ctx; + + sha224_init(&ctx); + sha224_update(&ctx, message, len); + sha224_final(&ctx, digest); +} + +void sha224_init(sha224_ctx *ctx) +{ +#ifndef UNROLL_LOOPS + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha224_h0[i]; + } +#else + ctx->h[0] = sha224_h0[0]; ctx->h[1] = sha224_h0[1]; + ctx->h[2] = sha224_h0[2]; ctx->h[3] = sha224_h0[3]; + ctx->h[4] = sha224_h0[4]; ctx->h[5] = sha224_h0[5]; + ctx->h[6] = sha224_h0[6]; ctx->h[7] = sha224_h0[7]; +#endif /* !UNROLL_LOOPS */ + + ctx->len = 0; + ctx->tot_len = 0; +} + +void sha224_update(sha224_ctx *ctx, const c_uint8_t *message, + c_uint32_t len) +{ + c_uint32_t block_nb; + c_uint32_t new_len, rem_len, tmp_len; + const c_uint8_t *shifted_message; + + tmp_len = SHA224_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&ctx->block[ctx->len], message, rem_len); + + if (ctx->len + len < SHA224_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA224_BLOCK_SIZE; + + shifted_message = message + rem_len; + + sha256_transf(ctx, ctx->block, 1); + sha256_transf(ctx, shifted_message, block_nb); + + rem_len = new_len % SHA224_BLOCK_SIZE; + + memcpy(ctx->block, &shifted_message[block_nb << 6], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 6; +} + +void sha224_final(sha224_ctx *ctx, c_uint8_t *digest) +{ + c_uint32_t block_nb; + c_uint32_t pm_len; + c_uint32_t len_b; + +#ifndef UNROLL_LOOPS + int i; +#endif + + block_nb = (1 + ((SHA224_BLOCK_SIZE - 9) + < (ctx->len % SHA224_BLOCK_SIZE))); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 6; + + memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + sha256_transf(ctx, ctx->block, block_nb); + +#ifndef UNROLL_LOOPS + for (i = 0 ; i < 7; i++) { + UNPACK32(ctx->h[i], &digest[i << 2]); + } +#else + UNPACK32(ctx->h[0], &digest[ 0]); + UNPACK32(ctx->h[1], &digest[ 4]); + UNPACK32(ctx->h[2], &digest[ 8]); + UNPACK32(ctx->h[3], &digest[12]); + UNPACK32(ctx->h[4], &digest[16]); + UNPACK32(ctx->h[5], &digest[20]); + UNPACK32(ctx->h[6], &digest[24]); +#endif /* !UNROLL_LOOPS */ +} diff --git a/lib/core/src/sha2_hmac.c b/lib/core/src/sha2_hmac.c new file mode 100644 index 0000000000..0eacd24479 --- /dev/null +++ b/lib/core/src/sha2_hmac.c @@ -0,0 +1,380 @@ +/*- + * HMAC-SHA-224/256/384/512 implementation + * Last update: 06/15/2005 + * Issue date: 06/15/2005 + * + * Copyright (C) 2005 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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 + +#include "core_sha2_hmac.h" + +/* HMAC-SHA-224 functions */ + +void hmac_sha224_init(hmac_sha224_ctx *ctx, c_uint8_t *key, + c_uint32_t key_size) +{ + c_uint32_t fill; + c_uint32_t num; + + c_uint8_t *key_used; + c_uint8_t key_temp[SHA224_DIGEST_SIZE]; + int i; + + if (key_size == SHA224_BLOCK_SIZE) { + key_used = key; + num = SHA224_BLOCK_SIZE; + } else { + if (key_size > SHA224_BLOCK_SIZE){ + key_used = key_temp; + num = SHA224_DIGEST_SIZE; + sha224(key, key_size, key_used); + } else { /* key_size > SHA224_BLOCK_SIZE */ + key_used = key; + num = key_size; + } + fill = SHA224_BLOCK_SIZE - num; + + memset(ctx->block_ipad + num, 0x36, fill); + memset(ctx->block_opad + num, 0x5c, fill); + } + + for (i = 0; i < num; i++) { + ctx->block_ipad[i] = key_used[i] ^ 0x36; + ctx->block_opad[i] = key_used[i] ^ 0x5c; + } + + sha224_init(&ctx->ctx_inside); + sha224_update(&ctx->ctx_inside, ctx->block_ipad, SHA224_BLOCK_SIZE); + + sha224_init(&ctx->ctx_outside); + sha224_update(&ctx->ctx_outside, ctx->block_opad, + SHA224_BLOCK_SIZE); + + /* for hmac_reinit */ + memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, + sizeof(sha224_ctx)); + memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, + sizeof(sha224_ctx)); +} + +void hmac_sha224_reinit(hmac_sha224_ctx *ctx) +{ + memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, + sizeof(sha224_ctx)); + memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, + sizeof(sha224_ctx)); +} + +void hmac_sha224_update(hmac_sha224_ctx *ctx, c_uint8_t *message, + c_uint32_t message_len) +{ + sha224_update(&ctx->ctx_inside, message, message_len); +} + +void hmac_sha224_final(hmac_sha224_ctx *ctx, c_uint8_t *mac, + c_uint32_t mac_size) +{ + c_uint8_t digest_inside[SHA224_DIGEST_SIZE]; + c_uint8_t mac_temp[SHA224_DIGEST_SIZE]; + + sha224_final(&ctx->ctx_inside, digest_inside); + sha224_update(&ctx->ctx_outside, digest_inside, SHA224_DIGEST_SIZE); + sha224_final(&ctx->ctx_outside, mac_temp); + memcpy(mac, mac_temp, mac_size); +} + +void hmac_sha224(c_uint8_t *key, c_uint32_t key_size, + c_uint8_t *message, c_uint32_t message_len, + c_uint8_t *mac, c_uint32_t mac_size) +{ + hmac_sha224_ctx ctx; + + hmac_sha224_init(&ctx, key, key_size); + hmac_sha224_update(&ctx, message, message_len); + hmac_sha224_final(&ctx, mac, mac_size); +} + +/* HMAC-SHA-256 functions */ + +void hmac_sha256_init(hmac_sha256_ctx *ctx, c_uint8_t *key, + c_uint32_t key_size) +{ + c_uint32_t fill; + c_uint32_t num; + + c_uint8_t *key_used; + c_uint8_t key_temp[SHA256_DIGEST_SIZE]; + int i; + + if (key_size == SHA256_BLOCK_SIZE) { + key_used = key; + num = SHA256_BLOCK_SIZE; + } else { + if (key_size > SHA256_BLOCK_SIZE){ + key_used = key_temp; + num = SHA256_DIGEST_SIZE; + sha256(key, key_size, key_used); + } else { /* key_size > SHA256_BLOCK_SIZE */ + key_used = key; + num = key_size; + } + fill = SHA256_BLOCK_SIZE - num; + + memset(ctx->block_ipad + num, 0x36, fill); + memset(ctx->block_opad + num, 0x5c, fill); + } + + for (i = 0; i < num; i++) { + ctx->block_ipad[i] = key_used[i] ^ 0x36; + ctx->block_opad[i] = key_used[i] ^ 0x5c; + } + + sha256_init(&ctx->ctx_inside); + sha256_update(&ctx->ctx_inside, ctx->block_ipad, SHA256_BLOCK_SIZE); + + sha256_init(&ctx->ctx_outside); + sha256_update(&ctx->ctx_outside, ctx->block_opad, + SHA256_BLOCK_SIZE); + + /* for hmac_reinit */ + memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, + sizeof(sha256_ctx)); + memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, + sizeof(sha256_ctx)); +} + +void hmac_sha256_reinit(hmac_sha256_ctx *ctx) +{ + memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, + sizeof(sha256_ctx)); + memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, + sizeof(sha256_ctx)); +} + +void hmac_sha256_update(hmac_sha256_ctx *ctx, c_uint8_t *message, + c_uint32_t message_len) +{ + sha256_update(&ctx->ctx_inside, message, message_len); +} + +void hmac_sha256_final(hmac_sha256_ctx *ctx, c_uint8_t *mac, + c_uint32_t mac_size) +{ + c_uint8_t digest_inside[SHA256_DIGEST_SIZE]; + c_uint8_t mac_temp[SHA256_DIGEST_SIZE]; + + sha256_final(&ctx->ctx_inside, digest_inside); + sha256_update(&ctx->ctx_outside, digest_inside, SHA256_DIGEST_SIZE); + sha256_final(&ctx->ctx_outside, mac_temp); + memcpy(mac, mac_temp, mac_size); +} + +void hmac_sha256(c_uint8_t *key, c_uint32_t key_size, + c_uint8_t *message, c_uint32_t message_len, + c_uint8_t *mac, c_uint32_t mac_size) +{ + hmac_sha256_ctx ctx; + + hmac_sha256_init(&ctx, key, key_size); + hmac_sha256_update(&ctx, message, message_len); + hmac_sha256_final(&ctx, mac, mac_size); +} + +/* HMAC-SHA-384 functions */ + +void hmac_sha384_init(hmac_sha384_ctx *ctx, c_uint8_t *key, + c_uint32_t key_size) +{ + c_uint32_t fill; + c_uint32_t num; + + c_uint8_t *key_used; + c_uint8_t key_temp[SHA384_DIGEST_SIZE]; + int i; + + if (key_size == SHA384_BLOCK_SIZE) { + key_used = key; + num = SHA384_BLOCK_SIZE; + } else { + if (key_size > SHA384_BLOCK_SIZE){ + key_used = key_temp; + num = SHA384_DIGEST_SIZE; + sha384(key, key_size, key_used); + } else { /* key_size > SHA384_BLOCK_SIZE */ + key_used = key; + num = key_size; + } + fill = SHA384_BLOCK_SIZE - num; + + memset(ctx->block_ipad + num, 0x36, fill); + memset(ctx->block_opad + num, 0x5c, fill); + } + + for (i = 0; i < num; i++) { + ctx->block_ipad[i] = key_used[i] ^ 0x36; + ctx->block_opad[i] = key_used[i] ^ 0x5c; + } + + sha384_init(&ctx->ctx_inside); + sha384_update(&ctx->ctx_inside, ctx->block_ipad, SHA384_BLOCK_SIZE); + + sha384_init(&ctx->ctx_outside); + sha384_update(&ctx->ctx_outside, ctx->block_opad, + SHA384_BLOCK_SIZE); + + /* for hmac_reinit */ + memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, + sizeof(sha384_ctx)); + memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, + sizeof(sha384_ctx)); +} + +void hmac_sha384_reinit(hmac_sha384_ctx *ctx) +{ + memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, + sizeof(sha384_ctx)); + memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, + sizeof(sha384_ctx)); +} + +void hmac_sha384_update(hmac_sha384_ctx *ctx, c_uint8_t *message, + c_uint32_t message_len) +{ + sha384_update(&ctx->ctx_inside, message, message_len); +} + +void hmac_sha384_final(hmac_sha384_ctx *ctx, c_uint8_t *mac, + c_uint32_t mac_size) +{ + c_uint8_t digest_inside[SHA384_DIGEST_SIZE]; + c_uint8_t mac_temp[SHA384_DIGEST_SIZE]; + + sha384_final(&ctx->ctx_inside, digest_inside); + sha384_update(&ctx->ctx_outside, digest_inside, SHA384_DIGEST_SIZE); + sha384_final(&ctx->ctx_outside, mac_temp); + memcpy(mac, mac_temp, mac_size); +} + +void hmac_sha384(c_uint8_t *key, c_uint32_t key_size, + c_uint8_t *message, c_uint32_t message_len, + c_uint8_t *mac, c_uint32_t mac_size) +{ + hmac_sha384_ctx ctx; + + hmac_sha384_init(&ctx, key, key_size); + hmac_sha384_update(&ctx, message, message_len); + hmac_sha384_final(&ctx, mac, mac_size); +} + +/* HMAC-SHA-512 functions */ + +void hmac_sha512_init(hmac_sha512_ctx *ctx, c_uint8_t *key, + c_uint32_t key_size) +{ + c_uint32_t fill; + c_uint32_t num; + + c_uint8_t *key_used; + c_uint8_t key_temp[SHA512_DIGEST_SIZE]; + int i; + + if (key_size == SHA512_BLOCK_SIZE) { + key_used = key; + num = SHA512_BLOCK_SIZE; + } else { + if (key_size > SHA512_BLOCK_SIZE){ + key_used = key_temp; + num = SHA512_DIGEST_SIZE; + sha512(key, key_size, key_used); + } else { /* key_size > SHA512_BLOCK_SIZE */ + key_used = key; + num = key_size; + } + fill = SHA512_BLOCK_SIZE - num; + + memset(ctx->block_ipad + num, 0x36, fill); + memset(ctx->block_opad + num, 0x5c, fill); + } + + for (i = 0; i < num; i++) { + ctx->block_ipad[i] = key_used[i] ^ 0x36; + ctx->block_opad[i] = key_used[i] ^ 0x5c; + } + + sha512_init(&ctx->ctx_inside); + sha512_update(&ctx->ctx_inside, ctx->block_ipad, SHA512_BLOCK_SIZE); + + sha512_init(&ctx->ctx_outside); + sha512_update(&ctx->ctx_outside, ctx->block_opad, + SHA512_BLOCK_SIZE); + + /* for hmac_reinit */ + memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, + sizeof(sha512_ctx)); + memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, + sizeof(sha512_ctx)); +} + +void hmac_sha512_reinit(hmac_sha512_ctx *ctx) +{ + memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, + sizeof(sha512_ctx)); + memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, + sizeof(sha512_ctx)); +} + +void hmac_sha512_update(hmac_sha512_ctx *ctx, c_uint8_t *message, + c_uint32_t message_len) +{ + sha512_update(&ctx->ctx_inside, message, message_len); +} + +void hmac_sha512_final(hmac_sha512_ctx *ctx, c_uint8_t *mac, + c_uint32_t mac_size) +{ + c_uint8_t digest_inside[SHA512_DIGEST_SIZE]; + c_uint8_t mac_temp[SHA512_DIGEST_SIZE]; + + sha512_final(&ctx->ctx_inside, digest_inside); + sha512_update(&ctx->ctx_outside, digest_inside, SHA512_DIGEST_SIZE); + sha512_final(&ctx->ctx_outside, mac_temp); + memcpy(mac, mac_temp, mac_size); +} + +void hmac_sha512(c_uint8_t *key, c_uint32_t key_size, + c_uint8_t *message, c_uint32_t message_len, + c_uint8_t *mac, c_uint32_t mac_size) +{ + hmac_sha512_ctx ctx; + + hmac_sha512_init(&ctx, key, key_size); + hmac_sha512_update(&ctx, message, message_len); + hmac_sha512_final(&ctx, mac, mac_size); +} diff --git a/lib/core/src/timer.c b/lib/core/src/timer.c new file mode 100644 index 0000000000..3b8b6db034 --- /dev/null +++ b/lib/core/src/timer.c @@ -0,0 +1,244 @@ +#define TRACE_MODULE _timer +#include "core_debug.h" +#include "core_timer.h" +#include "core_time.h" +#include "core_param.h" +#include "core_pool.h" + +typedef struct _tm_block_t { + lnode_t node; + + tm_service_t *tm_s; + c_uint32_t expire_time; + + expire_func_t expire_func; + c_uintptr_t arg1; + c_uintptr_t arg2; + c_uintptr_t arg3; + + tm_type_e type; + c_uint8_t running; + c_uint32_t duration; +} tm_block_t; + +pool_declare(timer_pool, tm_block_t, MAX_NUM_OF_TIMER); + +static int _tm_cmp_func(lnode_t *pnode1, lnode_t *pnode2); +static tm_block_t *_tm_get(void); +static void _tm_free(tm_block_t *tm); + +#define _tm_add(__l, __tm) \ + list_insert_sorted(__l, __tm, _tm_cmp_func) + +#define _tm_remove(__l, __tm) \ + list_remove(__l, __tm) + +status_t tm_init(void) +{ + pool_init(&timer_pool, MAX_NUM_OF_TIMER); + return CORE_OK; +} + +status_t tm_final(void) +{ + pool_final(&timer_pool); + return CORE_OK; +} + +c_uint32_t tm_pool_avail(void) +{ + return pool_avail(&timer_pool); +} + +void tm_service_init(tm_service_t *tm_service) +{ + memset(tm_service, 0x00, sizeof(tm_service_t)); + list_init(&tm_service->active_list); + list_init(&tm_service->idle_list); + return; +} + +status_t tm_execute_tm_service(tm_service_t *p_tm_s) +{ + c_uint32_t cur_time; + tm_block_t *tm; + + cur_time = time_as_msec(time_now()); + tm = list_first(&(p_tm_s->active_list)); + + while(tm) + { + if(tm->expire_time < cur_time) + { + /* execute expiry function */ + tm->expire_func(tm->arg1, tm->arg2, tm->arg3); + + /* remove this tm_block from the active list */ + _tm_remove(&(p_tm_s->active_list), tm); + + if(tm->type == TIMER_TYPE_PERIODIC) + { + tm->expire_time = cur_time + tm->duration; + + /* add this tm_block to the active list */ + _tm_add(&(p_tm_s->active_list), tm); + } + else + { + /* add this tm_block to the idle list */ + _tm_add(&(p_tm_s->idle_list), tm); + tm->running = 0; + } + + tm = list_first(&(p_tm_s->active_list)); + } + else + { + break; + } + } + return CORE_OK; +} + +static int _tm_cmp_func(lnode_t *pnode1, lnode_t *pnode2) +{ + tm_block_t *tm1 = (tm_block_t*)pnode1; + tm_block_t *tm2 = (tm_block_t*)pnode2; + + if(tm1->expire_time < tm2->expire_time) + return -1; + else + return 1; +} + +static tm_block_t *_tm_get(void) +{ + tm_block_t *tm_b = NULL; + + /* get timer node from node pool */ + pool_alloc_node(&timer_pool, &tm_b); + + /* check for error */ + d_assert(tm_b != NULL, return NULL, "fail to get timer pool\n"); + + /* intialize timer node */ + memset((char*)tm_b, 0x00, sizeof(tm_block_t)); + return tm_b; + +} + +static void _tm_free(tm_block_t *tm) +{ + /* free tlv node to the node pool */ + pool_free_node(&timer_pool, tm); + return; + +} + +tm_block_id tm_create(tm_service_t *tm_service) +{ + tm_block_t *tm = NULL; + tm = _tm_get(); + + d_assert(tm, return 0, "tm_create failed\n"); + tm->tm_s = tm_service; + + _tm_add(&(tm->tm_s->idle_list), tm); + + return (tm_block_id)tm; +} + +void tm_delete(tm_block_id id) +{ + tm_block_t *tm = (tm_block_t *)id; + + /* If running timer, pop it from active list */ + if (tm->running == 1) + _tm_remove(&(tm->tm_s->active_list), tm); + /* If not running timer, pop it from idle list */ + else + _tm_remove(&(tm->tm_s->idle_list), tm); + + _tm_free(tm); + + return; +} + +status_t tm_set( + tm_block_id id, tm_type_e type, c_uint32_t duration, + expire_func_t expire_func, + c_uintptr_t arg1, c_uintptr_t arg2, c_uintptr_t arg3) +{ + tm_block_t *tm = (tm_block_t *)id; + + tm->type = type; + tm->duration = duration; + tm->expire_func = expire_func; + tm->arg1 = arg1; + tm->arg2 = arg2; + tm->arg3 = arg3; + + return CORE_OK; +} + +status_t tm_set_duration(tm_block_id id, c_uint32_t duration) +{ + tm_block_t *tm = (tm_block_t *)id; + + tm->duration = duration; + + return CORE_OK; +} + +status_t tm_set_by_desc(tm_block_id id, tm_desc_t *desc) +{ + tm_block_t *tm = (tm_block_t *)id; + + tm->type = desc->type; + tm->duration = desc->duration; + tm->expire_func = desc->expire_func; + tm->arg1 = desc->arg1; + tm->arg2 = desc->arg2; + tm->arg3 = desc->arg3; + + return CORE_OK; +} + +status_t tm_start(tm_block_id id) +{ + c_uint32_t cur_time = time_as_msec(time_now()); + tm_block_t *tm = (tm_block_t *)id; + + /* If already running timer, pop it from active list for put again */ + if (tm->running == 1) + _tm_remove(&(tm->tm_s->active_list), tm); + /* If not running, tm is in idle list. pop it */ + else + _tm_remove(&(tm->tm_s->idle_list), tm); + + /* Calculate expiration */ + tm->expire_time = cur_time + tm->duration; + + /* Push tm to active list */ + _tm_add(&(tm->tm_s->active_list), tm); + + tm->running = 1; + + return CORE_OK; +} + +status_t tm_stop(tm_block_id id) +{ + tm_block_t *tm = (tm_block_t *)id; + + /* If already stopped timer, no operations needed */ + if (tm->running == 0) + return CORE_OK; + + _tm_remove(&(tm->tm_s->active_list), tm); + _tm_add(&(tm->tm_s->idle_list), tm); + + tm->running = 0; + + return CORE_OK; +} diff --git a/lib/core/src/tlv.c b/lib/core/src/tlv.c new file mode 100644 index 0000000000..df0c8d59a0 --- /dev/null +++ b/lib/core/src/tlv.c @@ -0,0 +1,729 @@ +#define TRACE_MODULE _tlv +#include "core_debug.h" +#include "core_tlv.h" +#include "core_lib.h" + +pool_declare(tlv_pool, tlv_t, NUM_OF_TLV_NODE); + +/* tlv_t common functions */ +tlv_t* tlv_get(void) +{ + tlv_t *tlv = NULL; + + /* get tlv node from node pool */ + pool_alloc_node(&tlv_pool, &tlv); + + /* check for error */ + d_assert(tlv != NULL, return NULL, "fail to get tlv pool\n"); + + /* intialize tlv node */ + memset((char*)tlv, 0x00, sizeof(tlv_t)); + return tlv; +} + +void tlv_free(tlv_t *p_tlv) +{ + /* free tlv node to the node pool */ + pool_free_node(&tlv_pool, p_tlv); + return; +} + +status_t tlv_init(void) +{ + pool_init(&tlv_pool, NUM_OF_TLV_NODE); + return CORE_OK; +} + +status_t tlv_final(void) +{ + pool_final(&tlv_pool); + return CORE_OK; +} + +c_uint32_t tlv_pool_avail(void) +{ + return pool_avail(&tlv_pool); +} + +void tlv_free_all(tlv_t *root_tlv) +{ + /* free all tlv node to the node pool */ + tlv_t *p_tlv = root_tlv; + tlv_t *next = NULL; + while(p_tlv) + { + if(p_tlv->embedded != NULL) + { + tlv_free_all(p_tlv->embedded); + } + next = p_tlv->next; + tlv_free(p_tlv); + p_tlv = next; + } + return; +} + +c_uint8_t tlv_value_8(tlv_t *tlv) +{ + return (*((c_uint8_t*)(tlv->value))); +} + +c_uint16_t tlv_value_16(tlv_t *tlv) +{ + c_uint16_t c_16; + c_uint8_t *v = tlv->value; + + c_16 = ((v[0] << 8) & 0xff00) | + ((v[1] ) & 0x00ff); + + return c_16; +} + +c_uint32_t tlv_value_32(tlv_t *tlv) +{ + c_uint32_t c_32; + c_uint8_t *v = tlv->value; + + c_32 = ((v[0] << 24) & 0xff000000) | + ((v[1] << 16) & 0x00ff0000) | + ((v[2] << 8) & 0x0000ff00) | + ((v[3] ) & 0x000000ff); + + return c_32; +} + +c_uint32_t tlv_calc_length(tlv_t *p_tlv, c_uint8_t mode) +{ + tlv_t *tmp_tlv = p_tlv; + c_uint32_t length = 0; + + while(tmp_tlv) + { + /* this is length for type field */ + if(mode == TLV_MODE_WMX_R4_R6) + { + length += 2; + } + else + { + length += 1; + } + + + /* this is length for type field */ + if(tmp_tlv->embedded != NULL) + { + tmp_tlv->length = tlv_calc_length(tmp_tlv->embedded, mode); + } + + if(mode == TLV_MODE_WMX_R4_R6) + { + length += 2; + } + else if(mode == TLV_MODE_UTIS) + { + if(tmp_tlv->length < UPDU_IE_TYPE_1_MAX_SIZE) + length += 1; + else if(tmp_tlv->length < UPDU_IE_TYPE_2_MAX_SIZE) + length += 2; + else if(tmp_tlv->length < UPDU_IE_TYPE_3_MAX_SIZE) + length += 4; + else + { + /* Error : Invalid IE length field */ + } + } + else + { + length += 1; + } + + + /* this is length for value field */ + length += tmp_tlv->length; + + tmp_tlv = tmp_tlv->next; + } + return length; +} + +c_uint32_t tlv_calc_count(tlv_t *p_tlv) +{ + tlv_t *tmp_tlv = p_tlv; + c_uint32_t count = 0; + + while(tmp_tlv) + { + if(tmp_tlv->embedded != NULL) + { + count += tlv_calc_count(tmp_tlv->embedded); + } + else + { + count++; + } + tmp_tlv = tmp_tlv->next; + } + return count; +} + + +c_uint32_t _tlv_get_length_utis(c_uint8_t **pos) +{ + c_uint8_t *blk = *pos; + c_uint32_t length = 0; + + switch(*blk >> 6) + { + case UPDU_IE_TYPE_1_CODE: + length = *blk & 0x3F; + *pos += 1; + break; + + case UPDU_IE_TYPE_2_CODE: + length = ((*blk & 0x3F) << 8) + *(blk + 1); + *pos += 2; + break; + + case UPDU_IE_TYPE_3_CODE: + length = ((*blk & 0x3F) << 24) + + (*(blk + 1) << 16) + (*(blk + 2) << 8) + *(blk + 3); + *pos += 4; + break; + default: + /* Error : Invalid IE length field */ + return CORE_ERROR; + break; + } + + return length; +} + +c_uint8_t* _tlv_put_length_utis(c_uint32_t length, c_uint8_t *pos) +{ + if(length < UPDU_IE_TYPE_1_MAX_SIZE) + { + *(pos++) = (UPDU_IE_TYPE_1_CODE << 6) | length; + } + else if(length < UPDU_IE_TYPE_2_MAX_SIZE) + { + *(pos++) = (UPDU_IE_TYPE_2_CODE << 6) | (length >> 8); + *(pos++) = length & 0xFF; + } + else if(length < UPDU_IE_TYPE_3_MAX_SIZE) + { + *(pos++) = (length >> 24) & 0xFF; + *(pos++) = (length >> 16) & 0xFF; + *(pos++) = (length >> 8) & 0xFF; + *(pos++) = length & 0xFF; + } + else + { + d_assert(FALSE, return NULL, "invalid tlv length\n"); + } + + return pos; +} + + +c_uint32_t _tlv_get_length_wifi(c_uint8_t **pos) +{ + c_uint8_t *blk = *pos; + c_uint32_t length = 0; + + if(*blk & 0x80) + { + d_error("TLV for wifi is not implemented in case of (length > 127)"); + } + else + { + length = *blk; + *pos += 1; + } + + return length; +} + +c_uint8_t* _tlv_put_length_wifi(c_uint32_t length, c_uint8_t *pos) +{ + if(length < 128) + { + *(pos++) = length; + } + else + { + d_error("TLV for wifi is not implemented in case of (length > 127)"); + } + return pos; +} + + +c_uint32_t _tlv_get_length_wmx_r4_r6(c_uint8_t **pos) +{ + c_uint8_t *blk = *pos; + c_uint32_t length = 0; + + length = ((*blk) << 8) + *(blk+1); + *pos += 2; + + return length; +} + +c_uint8_t* _tlv_put_length_wmx_r4_r6(c_uint32_t length, c_uint8_t *pos) +{ + *(pos++) = (length >> 8) & 0xFF; + *(pos++) = length & 0xFF; + + return pos; +} + +/* Not Implemented for WMX_R1*/ +c_uint32_t _tlv_get_length_wmx_r1(c_uint8_t **pos) +{ + c_uint8_t *blk = *pos; + c_uint32_t length = 0; + + if(*blk & 0x80) + { + d_error("TLV is not implemented in case of (length > 127)"); + } + else + { + length = *blk; + *pos += 1; + } + + return length; +} + +c_uint8_t* _tlv_put_length_wmx_r1(c_uint32_t length, c_uint8_t *pos) +{ + if(length < 128) + { + *(pos++) = length; + } + else + { + d_error("TLV is not implemented in case of (length > 127)"); + } + return pos; +} + +c_uint32_t _tlv_get_length_common(c_uint8_t **pos) +{ + c_uint8_t *blk = *pos; + c_uint32_t length = 0; + + if(*blk & 0x80) + { + d_error("TLV is not implemented in case of (length > 127)"); + } + else + { + length = *blk; + *pos += 1; + } + + return length; +} + +c_uint8_t* _tlv_put_length_common(c_uint32_t length, c_uint8_t *pos) +{ + if(length < 128) + { + *(pos++) = length; + } + else + { + d_error("TLV is not implemented in case of (length > 127)"); + } + return pos; +} + + +c_uint8_t* _tlv_put_length(c_uint32_t length, c_uint8_t *pos, c_uint8_t mode) +{ + if(mode == TLV_MODE_UTIS) + { + pos = _tlv_put_length_utis(length, pos); + + } + else if(mode == TLV_MODE_WIFI) + { + pos = _tlv_put_length_wifi(length, pos); + } + else if(mode == TLV_MODE_WMX_R4_R6) + { + pos = _tlv_put_length_wmx_r4_r6(length, pos); + } + else if(mode == TLV_MODE_WMX_R1) + { + pos = _tlv_put_length_wmx_r1(length, pos); + } + else + { + pos = _tlv_put_length_common(length, pos); + } + + return pos; +} + + +c_uint8_t* _tlv_get_element(tlv_t *p_tlv, c_uint8_t *tlvBlock, c_uint8_t mode) +{ + c_uint8_t *pos = tlvBlock; + + if(mode == TLV_MODE_WMX_R4_R6) + { + p_tlv->type = *(pos++) << 8; + p_tlv->type += *(pos++); + } + else + { + p_tlv->type = *(pos++); + } + + + if(mode == TLV_MODE_UTIS) + { + p_tlv->length = _tlv_get_length_utis(&pos); + } + else if(mode == TLV_MODE_WIFI) + { + p_tlv->length = _tlv_get_length_wifi(&pos); + } + else if(mode == TLV_MODE_WMX_R4_R6) + { + p_tlv->length = _tlv_get_length_wmx_r4_r6(&pos); + } + else if(mode == TLV_MODE_WMX_R1) + { + p_tlv->length = _tlv_get_length_wmx_r1(&pos); + } + else + { + p_tlv->length = _tlv_get_length_common(&pos); + } + p_tlv->value = pos; + + return (pos + tlv_length(p_tlv)); +} + + +c_uint8_t* _tlv_put_type(c_uint32_t type, c_uint8_t *pos, c_uint8_t mode) +{ + if(mode == TLV_MODE_WMX_R4_R6) + { + *(pos++) = (type >> 8) & 0xFF; + *(pos++) = type & 0xFF; + } + else + { + *(pos++) = type & 0xFF; + } + return pos; +} + + +c_uint8_t* _tlv_get_type(tlv_t *p_tlv, c_uint8_t *tlvBlock, c_uint8_t mode) +{ + c_uint8_t *pos = tlvBlock; + + p_tlv->type = *(pos++); + if(mode == TLV_MODE_UTIS) + { + p_tlv->length = _tlv_get_length_utis(&pos); + } + else if(mode == TLV_MODE_WIFI) + { + p_tlv->length = _tlv_get_length_wifi(&pos); + } + else if(mode == TLV_MODE_WMX_R4_R6) + { + p_tlv->length = _tlv_get_length_wmx_r4_r6(&pos); + } + else if(mode == TLV_MODE_WMX_R1) + { + p_tlv->length = _tlv_get_length_wmx_r1(&pos); + } + else + { + p_tlv->length = _tlv_get_length_common(&pos); + } + p_tlv->value = pos; + + return (pos + tlv_length(p_tlv)); +} + + + +/* tlv_t encoding functions */ + +c_uint8_t *tlv_write_to_buff( + c_uint8_t *blk, c_uint32_t type, c_uint32_t length, + c_uint8_t *value, c_uint8_t mode) +{ + c_uint8_t *pos = blk; + *(pos++) = type; + pos = _tlv_put_length(length, pos, mode); + + memcpy((c_uint8_t*)pos, (c_uint8_t*)value, length); + + pos += length; + return pos; +} + +void _tlv_alloc_buff_to_tlv( + tlv_t* head_tlv, c_uint8_t* buff, c_uint32_t buff_len) +{ + head_tlv->buff_allocated = TRUE; + head_tlv->buff_len = buff_len; + head_tlv->buff_ptr = buff; + head_tlv->buff = buff; +} + +tlv_t * tlv_find_root(tlv_t* p_tlv) +{ + tlv_t *head_tlv = p_tlv->head; + tlv_t *parentTlv; + + parentTlv = head_tlv->parent; + while(parentTlv) + { + head_tlv = parentTlv->head; + parentTlv = head_tlv->parent; + } + + return head_tlv; +} + + +tlv_t * tlv_add( + tlv_t *head_tlv, c_uint32_t type, c_uint32_t length, c_uint8_t *value) +{ + tlv_t* curr_tlv = head_tlv; + tlv_t* new_tlv = NULL; + + new_tlv = tlv_get(); + d_assert(new_tlv, return NULL, "can't get tlv node\n"); + if(length != 0) + { + d_assert(value, return NULL, "tlv value is NULL\n"); + } + + new_tlv->type = type; + new_tlv->length = length; + new_tlv->value = value; + + if(head_tlv != NULL && head_tlv->buff_allocated == TRUE) + { + d_assert((head_tlv->buff_ptr - head_tlv->buff + length)< + head_tlv->buff_len, tlv_free(new_tlv); return NULL, + "overflow in tlv buffer\n"); + + memcpy(head_tlv->buff_ptr, value, length); + new_tlv->value = head_tlv->buff_ptr; + head_tlv->buff_ptr += length; + } + + if(curr_tlv == NULL) + { + new_tlv->head = new_tlv; + new_tlv->tail = new_tlv; + } + else + { + head_tlv = head_tlv->head; /* in case head_tlv is not head */ + new_tlv->head = head_tlv; + head_tlv->tail->next = new_tlv; + head_tlv->tail = new_tlv; + } + return new_tlv; +} + +tlv_t * tlv_create_buff_enabled_tlv( + c_uint8_t *buff, c_uint32_t buff_len, + c_uint32_t type, c_uint32_t length, c_uint8_t *value) +{ + tlv_t* new_tlv = NULL; + + new_tlv = tlv_get(); + d_assert(new_tlv, return NULL, "can't get tlv node\n"); + + new_tlv->type = type; + new_tlv->length = length; + new_tlv->value = value; + new_tlv->head = new_tlv->tail = new_tlv; + + _tlv_alloc_buff_to_tlv(new_tlv,buff, buff_len); + + memcpy(new_tlv->buff_ptr, value, length); + new_tlv->value = new_tlv->buff_ptr; + new_tlv->buff_ptr += length; + + return new_tlv; +} + + + +tlv_t * tlv_embed( + tlv_t *parent_tlv, c_uint32_t type, c_uint32_t length, c_uint8_t *value) +{ + tlv_t* new_tlv = NULL, *root_tlv = NULL; + + d_assert(parent_tlv, return NULL, "parent tlv is NULL\n"); + + new_tlv = tlv_get(); + d_assert(new_tlv, return NULL, "can't get tlv node\n"); + + new_tlv->type = type; + new_tlv->length = length; + new_tlv->value = value; + + root_tlv = tlv_find_root(parent_tlv); + + if(root_tlv->buff_allocated == TRUE) + { + d_assert((root_tlv->buff_ptr - root_tlv->buff + length)buff_len, + tlv_free(new_tlv); return NULL, "overflow in tlv buffer\n"); + + memcpy(root_tlv->buff_ptr, value, length); + new_tlv->value = root_tlv->buff_ptr; + root_tlv->buff_ptr += length; + } + + if(parent_tlv->embedded == NULL) + { + parent_tlv->embedded = new_tlv->head = new_tlv->tail = new_tlv; + new_tlv->parent = parent_tlv; + } + else + { + new_tlv->head = parent_tlv->embedded; + parent_tlv->embedded->tail->next = new_tlv; + parent_tlv->embedded->tail = new_tlv; + } + + return new_tlv; +} + + +c_uint32_t tlv_render( + tlv_t *root_tlv, c_uint8_t *blk, c_uint32_t length, c_uint8_t mode) +{ + tlv_t* curr_tlv = root_tlv; + c_uint8_t* pos = blk; + c_uint32_t embedded_len = 0; + + while(curr_tlv) + { + pos = _tlv_put_type(curr_tlv->type, pos, mode); + + if(curr_tlv->embedded == NULL) + { + pos = _tlv_put_length(curr_tlv->length, pos, mode); + + if((pos - blk) + tlv_length(curr_tlv) > length) + { + d_assert(FALSE, ;, + "tlv_t encoding error:overflow for given buff length\n"); + memcpy((char*)pos, (char*)curr_tlv->value, length - (pos-blk)); + pos += length - (pos-blk); + + return (pos - blk); + } + + memcpy((char*)pos, (char*)curr_tlv->value, curr_tlv->length); + pos += curr_tlv->length; + } + else + { + embedded_len = tlv_calc_length(curr_tlv->embedded, mode); + pos = _tlv_put_length(embedded_len, pos, mode); + tlv_render(curr_tlv->embedded, + pos, length - (c_uint32_t)(pos-blk), mode); + pos += embedded_len; + } + curr_tlv = curr_tlv->next; + } + + return (pos - blk); +} + + +/* tlv_t parsing functions */ + +tlv_t * tlv_parse_tlv_block(c_uint32_t length, c_uint8_t *blk, c_uint8_t mode) +{ + c_uint8_t* pos = blk; + + tlv_t* root_tlv = NULL; + tlv_t* prev_tlv = NULL; + tlv_t* curr_tlv = NULL; + + root_tlv = curr_tlv = tlv_get(); + + d_assert(curr_tlv, return NULL, "can't get tlv node\n"); + + pos = _tlv_get_element(curr_tlv, pos, mode); + + d_assert(pos != NULL, tlv_free_all(root_tlv); return NULL, + "tlvGetElement Failed\n"); + + while(pos - blk < length) + { + prev_tlv = curr_tlv; + + curr_tlv = tlv_get(); + d_assert(curr_tlv, tlv_free_all(root_tlv); return NULL, + "can't get tlv node\n"); + prev_tlv->next = curr_tlv; + + pos = _tlv_get_element(curr_tlv, pos, mode); + d_assert(pos != NULL, tlv_free_all(root_tlv); return NULL, + "tlvGetElement Failed\n"); + } + + d_assert(length == (pos - blk), + tlv_free_all(root_tlv); return NULL, + "total size is not equal to sum of each tlv. %d %d", + length, pos - blk); + + return root_tlv; +} + +tlv_t * tlv_parse_embedded_tlv_block(tlv_t* p_tlv, c_uint8_t mode) +{ + p_tlv->embedded = tlv_parse_tlv_block(p_tlv->length, p_tlv->value, mode); + + return p_tlv->embedded; +} + + + +/* tlv operation-related function */ + +tlv_t * tlv_find(tlv_t* p_tlv, c_uint32_t type) +{ + tlv_t *tmp_tlv = p_tlv, *embed_tlv = NULL; + while(tmp_tlv) + { + if(tmp_tlv->type == type) + { + return tmp_tlv; + } + + if(tmp_tlv->embedded != NULL) + { + embed_tlv = tlv_find(tmp_tlv->embedded, type); + if(embed_tlv != NULL) + { + return embed_tlv; + } + } + tmp_tlv = tmp_tlv->next; + } + + /* tlv for the designated type doesn't exist */ + return NULL; +} diff --git a/lib/core/src/unix/Makefile.am b/lib/core/src/unix/Makefile.am new file mode 100644 index 0000000000..058b53ffe3 --- /dev/null +++ b/lib/core/src/unix/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in + +noinst_LTLIBRARIES = libcoreunix.la + +libcoreunix_la_SOURCES = \ + ../../include/arch/core_private_common.h \ + ../../include/arch/unix/core_arch_file.h \ + ../../include/arch/unix/core_arch_mutex.h \ + ../../include/arch/unix/core_arch_semaphore.h + +nodist_libcoreunix_la_SOURCES = \ + cond.c file.c net_lib.c thread.c errorcodes.c mutex.c rwlock.c \ + start.c time.c semaphore.c signal.c pkbuf.c + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/lib/core/include/arch/@OSDIR@ \ + -I$(top_srcdir)/lib/core/include + +AM_CFLAGS = \ + -Wall -Werror @OSCFLAGS@ + +MAINTAINERCLEANFILES = Makefile.in +MOSTLYCLEANFILES = core *.stackdump + +EXTRA_DIST = .libs $(noinst_LTLIBRARIES) diff --git a/lib/core/src/unix/cond.c b/lib/core/src/unix/cond.c new file mode 100644 index 0000000000..be0f110cf3 --- /dev/null +++ b/lib/core/src/unix/cond.c @@ -0,0 +1,103 @@ +#include "core.h" +#include "core_cond.h" +#include "core_arch_mutex.h" +#include "core_pool.h" +#include "core_param.h" +#include "core_general.h" +#include "core_debug.h" + +typedef struct _cond_t { + pthread_cond_t cond; +} cond_t; + +pool_declare(cond_pool, cond_t, MAX_NUM_OF_COND); + +status_t cond_init(void) +{ + pool_init(&cond_pool, MAX_NUM_OF_COND); + return CORE_OK; +} + +status_t cond_final(void) +{ + pool_final(&cond_pool); + return CORE_OK; +} + +status_t cond_create(cond_id *id) +{ + cond_t *new_cond = NULL; + status_t rv; + + pool_alloc_node(&cond_pool, &new_cond); + d_assert(new_cond, return CORE_ENOMEM, "cond_pool(%d) is not enough\n", + MAX_NUM_OF_COND); + + if ((rv = pthread_cond_init(&new_cond->cond, NULL))) + { + return rv; + } + + *id = (cond_id)new_cond; + return CORE_OK; +} + +status_t cond_wait(cond_id id, mutex_id mid) +{ + status_t rv; + cond_t *cond = (cond_t *)id; + mutex_t *mutex = (mutex_t *)mid; + + rv = pthread_cond_wait(&cond->cond, &mutex->mutex); + return rv; +} + +status_t cond_timedwait(cond_id id, + mutex_id mid, c_time_t timeout) +{ + status_t rv; + c_time_t then; + struct timespec abstime; + cond_t *cond = (cond_t *)id; + mutex_t *mutex = (mutex_t *)mid; + + then = time_now() + timeout; + abstime.tv_sec = time_sec(then); + abstime.tv_nsec = time_usec(then) * 1000; /* nanoseconds */ + + rv = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &abstime); + if (ETIMEDOUT == rv) + { + return CORE_TIMEUP; + } + return rv; +} + + +status_t cond_signal(cond_id id) +{ + status_t rv; + cond_t *cond = (cond_t *)id; + + rv = pthread_cond_signal(&cond->cond); + return rv; +} + +status_t cond_broadcast(cond_id id) +{ + status_t rv; + cond_t *cond = (cond_t *)id; + + rv = pthread_cond_broadcast(&cond->cond); + return rv; +} + +status_t cond_delete(cond_id id) +{ + status_t rv; + cond_t *cond = (cond_t *)id; + + rv = pthread_cond_destroy(&cond->cond); + pool_free_node(&cond_pool, cond); + return rv; +} diff --git a/lib/core/src/unix/errorcodes.c b/lib/core/src/unix/errorcodes.c new file mode 100644 index 0000000000..0e7b7e44c1 --- /dev/null +++ b/lib/core/src/unix/errorcodes.c @@ -0,0 +1,420 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core.h" +#include "core_lib.h" +#include "core_net.h" + +static char *stuffbuffer(char *buf, size_t bufsize, const char *s) +{ + strncpy(buf,s,bufsize); + return buf; +} + +static char *core_error_string(status_t statcode) +{ + switch (statcode) { + case CORE_ENOPOOL: + return "A new pool could not be created."; + case CORE_EBADDATE: + return "An invalid date has been provided"; + case CORE_EINVALSOCK: + return "An invalid socket was returned"; + case CORE_ENOPROC: + return "No process was provided and one was required."; + case CORE_ENOTIME: + return "No time was provided and one was required."; + case CORE_ENODIR: + return "No directory was provided and one was required."; + case CORE_ENOLOCK: + return "No lock was provided and one was required."; + case CORE_ENOPOLL: + return "No poll structure was provided and one was required."; + case CORE_ENOSOCKET: + return "No socket was provided and one was required."; + case CORE_ENOTHREAD: + return "No thread was provided and one was required."; + case CORE_ENOTHDKEY: + return "No thread key structure was provided and one was required."; + case CORE_ENOSHMAVAIL: + return "No shared memory is currently available"; + case CORE_EDSOOPEN: + return "DSO load failed"; + case CORE_EBADIP: + return "The specified IP address is invalid."; + case CORE_EBADMASK: + return "The specified network mask is invalid."; + + case CORE_INCHILD: + return + "Your code just forked, and you are currently executing in the " + "child process"; + case CORE_INPARENT: + return + "Your code just forked, and you are currently executing in the " + "parent process"; + case CORE_DETACH: + return "The specified thread is detached"; + case CORE_NOTDETACH: + return "The specified thread is not detached"; + case CORE_CHILD_DONE: + return "The specified child process is done executing"; + case CORE_CHILD_NOTDONE: + return "The specified child process is not done executing"; + case CORE_TIMEUP: + return "The timeout specified has expired"; + case CORE_INCOMPLETE: + return "Partial results are valid but processing is incomplete"; + case CORE_BADCH: + return "Bad character specified on command line"; + case CORE_BADARG: + return "Missing parameter for the specified command line option"; + case CORE_EOF: + return "End of file found"; + case CORE_NOTFOUND: + return "Could not find specified socket in poll list."; + case CORE_ANONYMOUS: + return "Shared memory is implemented anonymously"; + case CORE_FILEBASED: + return "Shared memory is implemented using files"; + case CORE_KEYBASED: + return "Shared memory is implemented using a key system"; + case CORE_EINIT: + return + "There is no error, this value signifies an initialized " + "error code"; + case CORE_ENOTIMPL: + return "This function has not been implemented on this platform"; + case CORE_EMISMATCH: + return "passwords do not match"; + case CORE_EABSOLUTE: + return "The given path is absolute"; + case CORE_ERELATIVE: + return "The given path is relative"; + case CORE_EINCOMPLETE: + return "The given path is incomplete"; + case CORE_EABOVEROOT: + return "The given path was above the root path"; + case CORE_EBADPATH: + return "The given path is misformatted or contained invalid characters"; + case CORE_EPATHWILD: + return "The given path contained wildcard characters"; + case CORE_EPROC_UNKNOWN: + return "The process is not recognized."; + case CORE_EGENERAL: + return "Internal error"; + default: + return "Error string not specified yet"; + } +} + + +#ifdef OS2 +#include + +int core_canonical_error(status_t err); + +static char *core_os_strerror(char* buf, size_t bufsize, int err) +{ + char result[200]; + unsigned char message[HUGE_STRING_LEN]; + ULONG len; + char *pos; + int c; + + if (err >= 10000 && err < 12000) { /* socket error codes */ + return stuffbuffer(buf, bufsize, + strerror(core_canonical_error(err+OS_START_SYSERR))); + } + else if (DosGetMessage(NULL, 0, message, HUGE_STRING_LEN, err, + "OSO001.MSG", &len) == 0) { + len--; + message[len] = 0; + pos = result; + + if (len >= sizeof(result)) + len = sizeof(result) - 1; + + for (c=0; c= 0) { + buf[i] = (char) msg[i]; + } else { + buf[i] = '?'; + } + } +#endif +#endif + + if (!len) { + for (i = 0; gaErrorList[i].msg; ++i) { + if (gaErrorList[i].code == errcode) { + core_cpystrn(buf, gaErrorList[i].msg, bufsize); + len = strlen(buf); + break; + } + } + } + + if (len) { + /* FormatMessage put the message in the buffer, but it may + * have embedded a newline (\r\n), and possible more than one. + * Remove the newlines replacing them with a space. This is not + * as visually perfect as moving all the remaining message over, + * but more efficient. + */ + i = len; + while (i) { + i--; + if ((buf[i] == '\r') || (buf[i] == '\n')) + buf[i] = ' '; + } + } + else { + /* Windows didn't provide us with a message. Even stuff like * WSAECONNREFUSED won't get a message. + */ + core_snprintf(buf, bufsize, "Unrecognized Win32 error code %d", errcode); + } + + return buf; +} + +#else +/* On Unix, core_os_strerror() handles error codes from the resolver + * (h_errno). + */ +static char *core_os_strerror(char* buf, size_t bufsize, int err) +{ +#ifdef HAVE_HSTRERROR + return stuffbuffer(buf, bufsize, hstrerror(err)); +#else /* HAVE_HSTRERROR */ + const char *msg; + + switch(err) { + case HOST_NOT_FOUND: + msg = "Unknown host"; + break; +#if defined(NO_DATA) + case NO_DATA: +#if defined(NO_ADDRESS) && (NO_DATA != NO_ADDRESS) + case NO_ADDRESS: +#endif + msg = "No address for host"; + break; +#elif defined(NO_ADDRESS) + case NO_ADDRESS: + msg = "No address for host"; + break; +#endif /* NO_DATA */ + default: + msg = "Unrecognized resolver error"; + } + return stuffbuffer(buf, bufsize, msg); +#endif /* HAVE_STRERROR */ +} +#endif + +#if defined(HAVE_STRERROR_R) && defined(STRERROR_R_RC_INT) && !defined(BEOS) +/* AIX and Tru64 style */ +static char *native_strerror(status_t statcode, char *buf, + size_t bufsize) +{ + if (strerror_r(statcode, buf, bufsize) < 0) { + return stuffbuffer(buf, bufsize, + "CORE does not understand this error code"); + } + else { + return buf; + } +} +#elif defined(HAVE_STRERROR_R) +/* glibc style */ + +/* BeOS has the function available, but it doesn't provide + * the prototype publically (doh!), so to avoid a build warning + * we add a suitable prototype here. + */ +#if defined(BEOS) +const char *strerror_r(status_t, char *, size_t); +#endif + +static char *native_strerror(status_t statcode, char *buf, + size_t bufsize) +{ + const char *msg; + + buf[0] = '\0'; + msg = strerror_r(statcode, buf, bufsize); + if (buf[0] == '\0') { /* libc didn't use our buffer */ + return stuffbuffer(buf, bufsize, msg); + } + else { + return buf; + } +} +#else +/* plain old strerror(); + * thread-safe on some platforms (e.g., Solaris, OS/390) + */ +static char *native_strerror(status_t statcode, char *buf, + size_t bufsize) +{ +#ifdef _WIN32_WCE + static char err[32]; + sprintf(err, "Native Error #%d", statcode); + return stuffbuffer(buf, bufsize, err); +#else + const char *err = strerror(statcode); + if (err) { + return stuffbuffer(buf, bufsize, err); + } else { + return stuffbuffer(buf, bufsize, + "CORE does not understand this error code"); + } +#endif +} +#endif + +char * core_strerror(status_t statcode, char *buf, + size_t bufsize) +{ + if (statcode < OS_START_ERROR) { + return native_strerror(statcode, buf, bufsize); + } + else if (statcode < OS_START_USERERR) { + return stuffbuffer(buf, bufsize, core_error_string(statcode)); + } + else if (statcode < OS_START_EAIERR) { + return stuffbuffer(buf, bufsize, "CORE does not understand this error code"); + } + else if (statcode < OS_START_SYSERR) { +#if defined(HAVE_GAI_STRERROR) + statcode -= OS_START_EAIERR; +#if defined(NEGATIVE_EAI) + statcode = -statcode; +#endif + return stuffbuffer(buf, bufsize, gai_strerror(statcode)); +#else + return stuffbuffer(buf, bufsize, "CORE does not understand this error code"); +#endif + } + else { + return core_os_strerror(buf, bufsize, statcode - OS_START_SYSERR); + } +} + diff --git a/lib/core/src/unix/file.c b/lib/core/src/unix/file.c new file mode 100644 index 0000000000..497fbc5d9a --- /dev/null +++ b/lib/core/src/unix/file.c @@ -0,0 +1,1012 @@ +#include "core_arch_file.h" +#include "core.h" +#include "core_errno.h" +#include "core_general.h" +#include "core_debug.h" +#include "core_pool.h" +#include "core_net.h" + +pool_declare(file_pool, file_t, MAX_NUM_OF_FILE); + +status_t file_init(void) +{ + pool_init(&file_pool, MAX_NUM_OF_FILE); + return CORE_OK; +} + +status_t file_final(void) +{ + pool_final(&file_pool); + return CORE_OK; +} + +#if !defined(OS2) && !defined(WIN32) +mode_t unix_perms2mode(file_perms_t perms) +{ + mode_t mode = 0; + + if (perms & FILE_USETID) + mode |= S_ISUID; + if (perms & FILE_UREAD) + mode |= S_IRUSR; + if (perms & FILE_UWRITE) + mode |= S_IWUSR; + if (perms & FILE_UEXECUTE) + mode |= S_IXUSR; + + if (perms & FILE_GSETID) + mode |= S_ISGID; + if (perms & FILE_GREAD) + mode |= S_IRGRP; + if (perms & FILE_GWRITE) + mode |= S_IWGRP; + if (perms & FILE_GEXECUTE) + mode |= S_IXGRP; + +#ifdef S_ISVTX + if (perms & FILE_WSTICKY) + mode |= S_ISVTX; +#endif + if (perms & FILE_WREAD) + mode |= S_IROTH; + if (perms & FILE_WWRITE) + mode |= S_IWOTH; + if (perms & FILE_WEXECUTE) + mode |= S_IXOTH; + + return mode; +} + +file_perms_t unix_mode2perms(mode_t mode) +{ + file_perms_t perms = 0; + + if (mode & S_ISUID) + perms |= FILE_USETID; + if (mode & S_IRUSR) + perms |= FILE_UREAD; + if (mode & S_IWUSR) + perms |= FILE_UWRITE; + if (mode & S_IXUSR) + perms |= FILE_UEXECUTE; + + if (mode & S_ISGID) + perms |= FILE_GSETID; + if (mode & S_IRGRP) + perms |= FILE_GREAD; + if (mode & S_IWGRP) + perms |= FILE_GWRITE; + if (mode & S_IXGRP) + perms |= FILE_GEXECUTE; + +#ifdef S_ISVTX + if (mode & S_ISVTX) + perms |= FILE_WSTICKY; +#endif + if (mode & S_IROTH) + perms |= FILE_WREAD; + if (mode & S_IWOTH) + perms |= FILE_WWRITE; + if (mode & S_IXOTH) + perms |= FILE_WEXECUTE; + + return perms; +} +#endif + +status_t file_open(file_t **new, + const char *fname, c_int32_t flag, file_perms_t perm) +{ + os_file_t fd; + int oflags = 0; + + if ((flag & FILE_READ) && (flag & FILE_WRITE)) + { + oflags = O_RDWR; + } + else if (flag & FILE_READ) + { + oflags = O_RDONLY; + } + else if (flag & FILE_WRITE) + { + oflags = O_WRONLY; + } + else + { + return CORE_EACCES; + } + + if (flag & FILE_CREATE) + { + oflags |= O_CREAT; + if (flag & FILE_EXCL) + { + oflags |= O_EXCL; + } + } + if ((flag & FILE_EXCL) && !(flag & FILE_CREATE)) + { + return CORE_EACCES; + } + + if (flag & FILE_APPEND) + { + oflags |= O_APPEND; + } + if (flag & FILE_TRUNCATE) + { + oflags |= O_TRUNC; + } +#ifdef O_BINARY + if (flag & FILE_BINARY) + { + oflags |= O_BINARY; + } +#endif + + if (perm == FILE_OS_DEFAULT) + { + fd = open(fname, oflags, 0666); + } + else + { + fd = open(fname, oflags, unix_perms2mode(perm)); + } + if (fd < 0) + { + return errno; + } + + pool_alloc_node(&file_pool, &(*new)); + d_assert((*new), return CORE_ENOMEM, "file_pool(%d) is not enough\n", + MAX_NUM_OF_FILE); + + (*new)->flags = flag; + (*new)->filedes = fd; + + strcpy((*new)->fname, fname); + + (*new)->timeout = -1; + (*new)->eof_hit = 0; + (*new)->filePtr = 0; + + return CORE_OK; +} + +status_t file_close(file_t *file) +{ + status_t rv = CORE_OK; + + if (close(file->filedes) == 0) + { + file->filedes = -1; + + /* Only the parent process should delete the file! */ + if (file->flags & FILE_DELONCLOSE) + { + unlink(file->fname); + } + } + else + { + /* Are there any error conditions other than EINTR or EBADF? */ + rv = errno; + } + + pool_free_node(&file_pool, file); + + return rv; +} + +status_t file_remove(const char *path) +{ + if (unlink(path) == 0) + { + return CORE_OK; + } + else + { + return errno; + } +} + +static status_t file_transfer_contents( + const char *from_path, const char *to_path, + c_int32_t flags, file_perms_t to_perms) +{ + file_t *s, *d; + status_t status; + file_info_t finfo; + file_perms_t perms; + + /* Open source file. */ + status = file_open(&s, from_path, FILE_READ, FILE_OS_DEFAULT); + if (status) + return status; + + /* Maybe get its permissions. */ + if (to_perms == FILE_SOURCE_PERMS) + { + status = file_info_get(&finfo, FILE_INFO_PROT, s); + if (status != CORE_OK && status != CORE_INCOMPLETE) + { + file_close(s); /* toss any error */ + return status; + } + perms = finfo.protection; + } + else + perms = to_perms; + + /* Open dest file. */ + status = file_open(&d, to_path, flags, perms); + if (status) + { + file_close(s); /* toss any error */ + return status; + } + +#if BUFSIZ > FILE_DEFAULT_BUFSIZE +#define COPY_BUFSIZ BUFSIZ +#else +#define COPY_BUFSIZ FILE_DEFAULT_BUFSIZE +#endif + + /* Copy bytes till the cows come home. */ + while (1) + { + char buf[COPY_BUFSIZ]; + size_t bytes_this_time = sizeof(buf); + status_t read_err; + status_t write_err; + + /* Read 'em. */ + read_err = file_read(s, buf, &bytes_this_time); + if (read_err && !STATUS_IS_EOF(read_err)) + { + file_close(s); /* toss any error */ + file_close(d); /* toss any error */ + return read_err; + } + + /* Write 'em. */ + write_err = file_write_full(d, buf, bytes_this_time, NULL); + if (write_err) + { + file_close(s); /* toss any error */ + file_close(d); /* toss any error */ + return write_err; + } + + if (read_err && STATUS_IS_EOF(read_err)) + { + status = file_close(s); + if (status) + { + file_close(d); /* toss any error */ + return status; + } + + /* return the results of this close: an error, or success */ + return file_close(d); + } + } + /* NOTREACHED */ +} + +status_t file_rename(const char *from_path, const char *to_path) +{ + if (rename(from_path, to_path) != 0) + { + return errno; + } + return CORE_OK; +} + +status_t file_link(const char *from_path, const char *to_path) +{ + if (link(from_path, to_path) == -1) + { + return errno; + } + + return CORE_OK; +} + +status_t file_copy( + const char *from_path, const char *to_path, file_perms_t perms) +{ + return file_transfer_contents(from_path, to_path, + (FILE_WRITE | FILE_CREATE | FILE_TRUNCATE), perms); +} + +status_t file_append( + const char *from_path, const char *to_path, file_perms_t perms) +{ + return file_transfer_contents(from_path, to_path, + (FILE_WRITE | FILE_CREATE | FILE_APPEND), perms); +} + +status_t file_eof(file_t *fptr) +{ + if (fptr->eof_hit == 1) + { + return CORE_EOF; + } + return CORE_OK; +} + +status_t file_read(file_t *thefile, void *buf, size_t *nbytes) +{ + ssize_t rv; + size_t bytes_read; + + if (*nbytes <= 0) + { + *nbytes = 0; + return CORE_OK; + } + + bytes_read = 0; + + do + { + rv = read(thefile->filedes, buf, *nbytes); + } while (rv == -1 && errno == EINTR); + *nbytes = bytes_read; + if (rv == 0) + { + thefile->eof_hit = TRUE; + return CORE_EOF; + } + if (rv > 0) + { + *nbytes += rv; + return CORE_OK; + } + return errno; +} + +status_t file_write( + file_t *thefile, const void *buf, size_t *nbytes) +{ + size_t rv; + + do + { + rv = write(thefile->filedes, buf, *nbytes); + } while (rv == (size_t)-1 && errno == EINTR); + + if (rv == (size_t)-1) + { + (*nbytes) = 0; + return errno; + } + *nbytes = rv; + return CORE_OK; +} +status_t file_writev(file_t *thefile, + const struct iovec *vec, size_t nvec, size_t *nbytes) +{ +#ifdef HAVE_WRITEV + status_t rv; + ssize_t bytes; + + if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) + { + *nbytes = 0; + rv = errno; + } + else + { + *nbytes = bytes; + rv = CORE_OK; + } + return rv; +#else + /** + * The problem with trying to output the entire iovec is that we cannot + * maintain the behaviour that a real writev would have. If we iterate + * over the iovec one at a time, we lose the atomic properties of + * writev(). The other option is to combine the entire iovec into one + * buffer that we could then send in one call to write(). This is not + * reasonable since we do not know how much data an iovec could contain. + * + * The only reasonable option, that maintains the semantics of a real + * writev(), is to only write the first iovec. Callers of file_writev() + * must deal with partial writes as they normally would. If you want to + * ensure an entire iovec is written, use file_writev_full(). + */ + + *nbytes = vec[0].iov_len; + return file_write(thefile, vec[0].iov_base, nbytes); +#endif +} + +status_t file_read_full(file_t *thefile, void *buf, + size_t nbytes, size_t *bytes_read) +{ + status_t status; + size_t total_read = 0; + + do { + size_t amt = nbytes; + + status = file_read(thefile, buf, &amt); + buf = (char *)buf + amt; + nbytes -= amt; + total_read += amt; + } while (status == CORE_OK && nbytes > 0); + + if (bytes_read != NULL) + *bytes_read = total_read; + + return status; +} +status_t file_write_full(file_t *thefile, + const void *buf, size_t nbytes, size_t *bytes_written) +{ + status_t status; + size_t total_written = 0; + + do { + size_t amt = nbytes; + + status = file_write(thefile, buf, &amt); + buf = (char *)buf + amt; + nbytes -= amt; + total_written += amt; + } while (status == CORE_OK && nbytes > 0); + + if (bytes_written != NULL) + *bytes_written = total_written; + + return status; +} + +status_t file_writev_full(file_t *thefile, + const struct iovec *vec, size_t nvec, size_t *bytes_written) +{ + status_t rv = CORE_OK; + size_t i; + size_t amt = 0; + size_t total = 0; + + for (i = 0; i < nvec; i++) + { + total += vec[i].iov_len; + } + + rv = file_writev(thefile, vec, nvec, &amt); + + if (bytes_written != NULL) + *bytes_written = amt; + + if (rv != CORE_OK || (amt == total)) + { + return rv; + } + + for (i = 0; i < nvec && amt; i++) + { + if (amt >= vec[i].iov_len) + { + amt -= vec[i].iov_len; + } + else + { + break; + } + } + + if (amt) + { + rv = file_write_full(thefile, (const char *)vec[i].iov_base + amt, + vec[i].iov_len - amt, NULL); + } + + for (; i < nvec && rv == CORE_OK; i++) + { + rv = file_write_full(thefile, vec[i].iov_base, + vec[i].iov_len, &amt); + } + + if (bytes_written != NULL) + *bytes_written = total; + + return rv; +} + +status_t file_putc(char ch, file_t *thefile) +{ + size_t nbytes = 1; + + return file_write(thefile, &ch, &nbytes); +} +status_t file_getc(char *ch, file_t *thefile) +{ + size_t nbytes = 1; + + return file_read(thefile, ch, &nbytes); +} + +status_t file_gets(char *str, int len, file_t *thefile) +{ + status_t rv = CORE_OK; /* get rid of gcc warning */ + size_t nbytes; + const char *str_start = str; + char *final = str + len - 1; + + if (len <= 1) + { + /* sort of like fgets(), which returns NULL and stores no bytes + */ + return CORE_OK; + } + + while (str < final) + { /* leave room for trailing '\0' */ + nbytes = 1; + rv = file_read(thefile, str, &nbytes); + if (rv != CORE_OK) + { + break; + } + if (*str == '\n') + { + ++str; + break; + } + ++str; + } + + /* We must store a terminating '\0' if we've stored any chars. We can + * get away with storing it if we hit an error first. + */ + *str = '\0'; + if (str > str_start) + { + /* we stored chars; don't report EOF or any other errors; + * the app will find out about that on the next call + */ + return CORE_OK; + } + return rv; +} + +status_t file_puts(const char *str, file_t *thefile) +{ + return file_write_full(thefile, str, strlen(str), NULL); +} + +status_t file_sync(file_t *thefile) +{ + status_t rv = CORE_OK; + + if (fsync(thefile->filedes)) + { + rv = get_os_error(); + } + + return rv; +} + +status_t file_seek(file_t *thefile, + seek_where_t where, off_t *offset) +{ + off_t rv; + + thefile->eof_hit = 0; + + rv = lseek(thefile->filedes, *offset, where); + if (rv == -1) + { + *offset = -1; + return errno; + } + else + { + *offset = rv; + return CORE_OK; + } +} + +status_t file_name_get(const char **fname, file_t *thefile) +{ + *fname = thefile->fname; + return CORE_OK; +} + +status_t file_perms_set(const char *fname, file_perms_t perms) +{ + mode_t mode = unix_perms2mode(perms); + + if (chmod(fname, mode) == -1) + return errno; + return CORE_OK; +} + +status_t file_attrs_set(const char *fname, + file_attrs_t attributes, file_attrs_t attr_mask) +{ + status_t status; + file_info_t finfo; + + /* Don't do anything if we can't handle the requested attributes */ + if (!(attr_mask & (ATTR_READONLY | ATTR_EXECUTABLE))) + return CORE_OK; + + status = file_stat(&finfo, fname, FILE_INFO_PROT); + if (status) + return status; + + /* ### TODO: should added bits be umask'd? */ + if (attr_mask & ATTR_READONLY) + { + if (attributes & ATTR_READONLY) + { + finfo.protection &= ~FILE_UWRITE; + finfo.protection &= ~FILE_GWRITE; + finfo.protection &= ~FILE_WWRITE; + } + else + { + /* ### umask this! */ + finfo.protection |= FILE_UWRITE; + finfo.protection |= FILE_GWRITE; + finfo.protection |= FILE_WWRITE; + } + } + + if (attr_mask & ATTR_EXECUTABLE) + { + if (attributes & ATTR_EXECUTABLE) + { + /* ### umask this! */ + finfo.protection |= FILE_UEXECUTE; + finfo.protection |= FILE_GEXECUTE; + finfo.protection |= FILE_WEXECUTE; + } + else + { + finfo.protection &= ~FILE_UEXECUTE; + finfo.protection &= ~FILE_GEXECUTE; + finfo.protection &= ~FILE_WEXECUTE; + } + } + + return file_perms_set(fname, finfo.protection); +} + +status_t file_mtime_set(const char *fname, c_time_t mtime) +{ + status_t status; + file_info_t finfo; + + status = file_stat(&finfo, fname, FILE_INFO_ATIME); + if (status) + { + return status; + } + +#ifdef HAVE_UTIMES + { + struct timeval tvp[2]; + + tvp[0].tv_sec = time_sec(finfo.atime); + tvp[0].tv_usec = time_usec(finfo.atime); + tvp[1].tv_sec = time_sec(mtime); + tvp[1].tv_usec = time_usec(mtime); + + if (utimes(fname, tvp) == -1) + { + return errno; + } + } +#elif defined(HAVE_UTIME) + { + struct utimbuf buf; + + buf.actime = (time_t) (finfo.atime / USEC_PER_SEC); + buf.modtime = (time_t) (mtime / USEC_PER_SEC); + + if (utime(fname, &buf) == -1) + { + return errno; + } + } +#else + return CORE_ENOTIMPL; +#endif + + return CORE_OK; +} + +status_t dir_make(const char *path, file_perms_t perm) +{ + mode_t mode = unix_perms2mode(perm); + + if (mkdir(path, mode) == 0) + { + return CORE_OK; + } + else + { + return errno; + } +} + +#define PATH_SEPARATOR '/' + +/* Remove trailing separators that don't affect the meaning of PATH. */ +static void path_canonicalize (char *dir) +{ + /* At some point this could eliminate redundant components. For + * now, it just makes sure there is no trailing slash. */ + size_t len = strlen (dir); + size_t orig_len = len; + + while ((len > 0) && (dir[len - 1] == PATH_SEPARATOR)) + len--; + + if (len != orig_len) + dir[len] = 0; +} + +/* Remove one component off the end of PATH. */ +static void path_remove_last_component (char *dir, const char *path) +{ + int i; + int len = 0; + + strcpy(dir, path); + path_canonicalize (dir); + for (i = (strlen(dir) - 1); i >= 0; i--) { + if (path[i] == PATH_SEPARATOR) + break; + } + + len = (i < 0) ? 0 : i; + dir[len] = 0; +} + +status_t dir_make_recursive(const char *path, file_perms_t perm) +{ + status_t err = 0; + + err = dir_make(path, perm); /* Try to make PATH right out */ + + if (err == EEXIST) /* It's OK if PATH exists */ + return CORE_OK; + + if (err == ENOENT) /* Missing an intermediate dir */ + { + char dir[MAX_DIRNAME_SIZE]; + + path_remove_last_component(dir, path); + /* If there is no path left, give up. */ + if (dir[0] == '\0') + { + return err; + } + + err = dir_make_recursive(dir, perm); + + if (!err) + err = dir_make (path, perm); + } + + return err; +} +status_t dir_remove(const char *path) +{ + if (rmdir(path) == 0) + { + return CORE_OK; + } + else { + return errno; + } +} + +static filetype_e filetype_from_mode(mode_t mode) +{ + filetype_e type; + + switch (mode & S_IFMT) + { + case S_IFREG: + type = FILE_REG; break; + case S_IFDIR: + type = FILE_DIR; break; + case S_IFLNK: + type = FILE_LNK; break; + case S_IFCHR: + type = FILE_CHR; break; + case S_IFBLK: + type = FILE_BLK; break; +#if defined(S_IFFIFO) + case S_IFFIFO: + type = FILE_PIPE; break; +#endif +#if !defined(BEOS) && defined(S_IFSOCK) + case S_IFSOCK: + type = FILE_SOCK; break; +#endif + + default: + /* Work around missing S_IFxxx values above + * for Linux et al. + */ +#if !defined(S_IFFIFO) && defined(S_ISFIFO) + if (S_ISFIFO(mode)) + { + type = FILE_PIPE; + } + else +#endif +#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK) + if (S_ISSOCK(mode)) + { + type = FILE_SOCK; + } else +#endif + type = FILE_UNKFILE; + } + return type; +} + +static void fill_out_finfo(file_info_t *finfo, struct_stat *info, + c_int32_t wanted) +{ + finfo->valid = FILE_INFO_MIN | FILE_INFO_IDENT | FILE_INFO_NLINK + | FILE_INFO_OWNER | FILE_INFO_PROT; + finfo->protection = unix_mode2perms(info->st_mode); + finfo->filetype = filetype_from_mode(info->st_mode); + finfo->user = info->st_uid; + finfo->group = info->st_gid; + finfo->size = info->st_size; + finfo->device = info->st_dev; + finfo->nlink = info->st_nlink; + + /* Check for overflow if storing a 64-bit st_ino in a 32-bit + * ino_t for LFS builds: */ + if (sizeof(ino_t) >= sizeof(info->st_ino) + || (ino_t)info->st_ino == info->st_ino) + { + finfo->inode = info->st_ino; + } else + { + finfo->valid &= ~FILE_INFO_INODE; + } + + time_ansi_put(&finfo->atime, info->st_atime); +#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC + finfo->atime += info->st_atim.tv_nsec / TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC) + finfo->atime += info->st_atimensec / TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_ATIME_N) + finfo->ctime += info->st_atime_n / TIME_C(1000); +#endif + + time_ansi_put(&finfo->mtime, info->st_mtime); +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + finfo->mtime += info->st_mtim.tv_nsec / TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) + finfo->mtime += info->st_mtimensec / TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_MTIME_N) + finfo->ctime += info->st_mtime_n / TIME_C(1000); +#endif + + time_ansi_put(&finfo->ctime, info->st_ctime); +#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC + finfo->ctime += info->st_ctim.tv_nsec / TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC) + finfo->ctime += info->st_ctimensec / TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_CTIME_N) + finfo->ctime += info->st_ctime_n / TIME_C(1000); +#endif + +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS +#ifdef DEV_BSIZE + finfo->csize = (off_t)info->st_blocks * (off_t)DEV_BSIZE; +#else + finfo->csize = (off_t)info->st_blocks * (off_t)512; +#endif + finfo->valid |= FILE_INFO_CSIZE; +#endif +} + + +status_t file_info_get(file_info_t *finfo, + c_int32_t wanted, file_t *thefile) +{ + struct_stat info; + + if (fstat(thefile->filedes, &info) == 0) + { + strcpy(finfo->fname, thefile->fname); + fill_out_finfo(finfo, &info, wanted); + return (wanted & ~finfo->valid) ? CORE_INCOMPLETE : CORE_OK; + } + else { + return errno; + } +} + +status_t file_trunc(file_t *fp, off_t offset) +{ + if (ftruncate(fp->filedes, offset) == -1) + { + return errno; + } + return file_seek(fp, FILE_SET, &offset); +} + +c_int32_t file_flags_get(file_t *f) +{ + return f->flags; +} + +status_t file_stat(file_info_t *finfo, + const char *fname, c_int32_t wanted) +{ + struct_stat info; + int srv; + + if (wanted & FILE_INFO_LINK) + srv = lstat(fname, &info); + else + srv = stat(fname, &info); + + if (srv == 0) + { + strcpy(finfo->fname, fname); + fill_out_finfo(finfo, &info, wanted); + if (wanted & FILE_INFO_LINK) + wanted &= ~FILE_INFO_LINK; + return (wanted & ~finfo->valid) ? CORE_INCOMPLETE : CORE_OK; + } + else + { +#if !defined(ENOENT) || !defined(ENOTDIR) +#error ENOENT || ENOTDIR not defined; please see the +#error comments at this line in the source for a workaround. + /* + * If ENOENT || ENOTDIR is not defined in one of the your OS's + * include files, CORE cannot report a good reason why the stat() + * of the file failed; there are cases where it can fail even though + * the file exists. This opens holes in Apache, for example, because + * it becomes possible for someone to get a directory listing of a + * directory even though there is an index (eg. index.html) file in + * it. If you do not have a problem with this, delete the above + * #error lines and start the compile again. If you need to do this, + * please submit a bug report to http://www.apache.org/bug_report.html + * letting us know that you needed to do this. Please be sure to + * include the operating system you are using. + */ + /* WARNING: All errors will be handled as not found + */ +#if !defined(ENOENT) + return CORE_ENOENT; +#else + /* WARNING: All errors but not found will be handled as not directory + */ + if (errno != ENOENT) + return CORE_ENOENT; + else + return errno; +#endif +#else /* All was defined well, report the usual: */ + return errno; +#endif + } +} + +status_t temp_dir_get(char *temp_dir) +{ + strcpy(temp_dir, "/tmp"); + return CORE_OK; +} + diff --git a/lib/core/src/unix/mutex.c b/lib/core/src/unix/mutex.c new file mode 100644 index 0000000000..9b49073a4f --- /dev/null +++ b/lib/core/src/unix/mutex.c @@ -0,0 +1,108 @@ +#include "core.h" +#include "core_arch_mutex.h" +#include "core_errno.h" +#include "core_param.h" +#include "core_general.h" +#include "core_debug.h" +#include "core_pool.h" + +pool_declare(mutex_pool, mutex_t, MAX_NUM_OF_MUTEX); + +status_t mutex_init(void) +{ + pool_init_wo_lock(&mutex_pool, MAX_NUM_OF_MUTEX); + return CORE_OK; +} + +status_t mutex_final(void) +{ + pool_final(&mutex_pool); + return CORE_OK; +} + +status_t mutex_create(mutex_id *id, unsigned int flags) +{ + mutex_t *new_mutex; + status_t rv; + + pool_alloc_node(&mutex_pool, &new_mutex); + d_assert(new_mutex, return CORE_ENOMEM, "mutex_pool(%d) is not enough\n", + MAX_NUM_OF_MUTEX); + + if (flags & MUTEX_NESTED) + { + return CORE_ENOTIMPL; + } + + if (flags & MUTEX_NESTED) + { + pthread_mutexattr_t mattr; + + rv = pthread_mutexattr_init(&mattr); + if (rv) return rv; + + rv = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); + if (rv) + { + pthread_mutexattr_destroy(&mattr); + return rv; + } + + rv = pthread_mutex_init(&new_mutex->mutex, &mattr); + + pthread_mutexattr_destroy(&mattr); + } else + rv = pthread_mutex_init(&new_mutex->mutex, NULL); + + if (rv) + { + return rv; + } + + *id = (mutex_id)new_mutex; + return CORE_OK; +} + +status_t mutex_lock(mutex_id id) +{ + status_t rv; + mutex_t *mutex = (mutex_t *)id; + + rv = pthread_mutex_lock(&mutex->mutex); + return rv; +} + +status_t mutex_trylock(mutex_id id) +{ + status_t rv; + mutex_t *mutex = (mutex_t *)id; + + rv = pthread_mutex_trylock(&mutex->mutex); + if (rv) + { + return (rv == EBUSY) ? CORE_EBUSY : rv; + } + + return CORE_OK; +} + +status_t mutex_unlock(mutex_id id) +{ + status_t rv; + mutex_t *mutex = (mutex_t *)id; + + rv = pthread_mutex_unlock(&mutex->mutex); + + return rv; +} + +status_t mutex_delete(mutex_id id) +{ + status_t rv; + mutex_t *mutex = (mutex_t *)id; + + rv = pthread_mutex_destroy(&mutex->mutex); + pool_free_node(&mutex_pool, mutex); + + return rv; +} diff --git a/lib/core/src/unix/net_lib.c b/lib/core/src/unix/net_lib.c new file mode 100644 index 0000000000..937056fead --- /dev/null +++ b/lib/core/src/unix/net_lib.c @@ -0,0 +1,1571 @@ +#define TRACE_MODULE net_lib +#include "core.h" +#include "core_debug.h" +#include "core_list.h" +#include "core_pool.h" +#include "core_net.h" +#include "core_errno.h" +#include "core_time.h" + +#include +#include +#include + +#if LINUX == 1 +#include +#endif + +#define NET_FD_TYPE_SOCK 0 +#define NET_FD_TYPE_LINK 1 + +typedef struct { + lnode_t node; + void *net_sl; + int fd; + int type; + net_handler handler; + void *data; +} net_fd_t; + +typedef struct { + int max_fd; + mutex_id mut; + list_t fd_list; + fd_set rfds; +} net_fd_tbl_t; + +pool_declare(net_pool, net_sock_t, MAX_NET_POOL_SIZE); +pool_declare(ftp_pool, net_ftp_t, MAX_FTP_SESSION_SIZE); +pool_declare(link_pool, net_link_t, MAX_NET_POOL_SIZE); +pool_declare(net_fd_pool, net_fd_t, MAX_NET_POOL_SIZE); + +static net_fd_tbl_t g_net_fd_tbl; + +status_t net_init(void) +{ + /* Initialize network connection pool */ + pool_init(&net_pool, MAX_NET_POOL_SIZE); + /* Initialize ftp connection pool */ + pool_init(&ftp_pool, MAX_FTP_SESSION_SIZE); + /* Initialize network connection pool */ + pool_init(&link_pool, MAX_NET_POOL_SIZE); + /* Initialize network fd pool */ + pool_init(&net_fd_pool, MAX_NET_POOL_SIZE); + + memset(&g_net_fd_tbl, 0, sizeof(net_fd_tbl_t)); + mutex_create(&g_net_fd_tbl.mut, MUTEX_DEFAULT); + + return CORE_OK; +} + +status_t net_final(void) +{ + /* Finalize network connection pool */ + pool_final(&net_pool); + /* Finalize ftp connection pool */ + pool_final(&ftp_pool); + /* Finalize network connection pool */ + pool_final(&link_pool); + + mutex_delete(g_net_fd_tbl.mut); + + return CORE_OK; +} + +int net_pool_avail() +{ + return pool_avail(&net_pool); +} + +/** Allocate socket from network pool and create it */ +static net_sock_t *net_sock_create(int type, int protocol) +{ + int rc,sock, sockopt; + net_sock_t *net_sock = NULL; + + pool_alloc_node(&net_pool, &net_sock); + d_assert(net_sock != NULL, return NULL,"No net pool is availabe\n"); + + /* Create stream socket */ + sock = socket(PF_INET, type, protocol); + if (sock < 0) + { + d_error("Can not create socket(type: %d protocol: %d)",type,protocol); + return NULL; + } + + /* Set the useful socket option */ + + /* Don't leave the socket in a TIME_WAIT state if we close the + * connection + */ +#if 0 + fix_ling.l_onoff = 1; + fix_ling.l_linger = 0; + rc = setsockopt(sock, SOL_SOCKET, SO_LINGER, &fix_ling, + sizeof(fix_ling)); + if (rc < 0) + { + goto cleanup; + } +#endif + + /* Reuse the binded address */ + sockopt = 1; + rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, + sizeof(sockopt)); + if (rc < 0) + { + d_error("setsockopt error(SO_REUSEADDR)"); + goto cleanup; + } + + if (protocol == IPPROTO_SCTP) + { + struct sctp_event_subscribe event; + struct sctp_paddrparams heartbeat; + struct sctp_rtoinfo rtoinfo; + struct sctp_initmsg initmsg; + socklen_t socklen; + + memset(&event, 0, sizeof(event)); + memset(&heartbeat, 0, sizeof(heartbeat)); + memset(&rtoinfo, 0, sizeof(rtoinfo)); + memset(&initmsg, 0, sizeof(initmsg)); + + event.sctp_association_event = 1; + event.sctp_send_failure_event = 1; + event.sctp_shutdown_event = 1; + + if (setsockopt(sock, IPPROTO_SCTP, SCTP_EVENTS, + &event, sizeof( event)) != 0 ) + { + d_error("Unable to subscribe to SCTP events: (%d:%s)", + errno, strerror( errno )); + goto cleanup; + } + + socklen = sizeof(heartbeat); + if (getsockopt(sock, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, + &heartbeat, &socklen) != 0 ) + { + d_error("Failure : getsockopt for SCTP_PEER_ADDR: (%d:%s)", + errno, strerror( errno )); + goto cleanup; + } + + d_trace(3,"Old spp _flags = 0x%x hbinter = %d pathmax = %d\n", + heartbeat.spp_flags, + heartbeat.spp_hbinterval, + heartbeat.spp_pathmaxrxt); + + /* FIXME : Need to configure this param */ + heartbeat.spp_hbinterval = 5000; /* 5 secs */ + + if (setsockopt(sock, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, + &heartbeat, sizeof( heartbeat)) != 0 ) + { + d_error("Failure : setsockopt for SCTP_PEER_ADDR_PARAMS: (%d:%s)", + errno, strerror( errno )); + goto cleanup; + } + d_trace(3,"New spp _flags = 0x%x hbinter = %d pathmax = %d\n", + heartbeat.spp_flags, + heartbeat.spp_hbinterval, + heartbeat.spp_pathmaxrxt); + + socklen = sizeof(rtoinfo); + if (getsockopt(sock, IPPROTO_SCTP, SCTP_RTOINFO, + &rtoinfo, &socklen) != 0 ) + { + d_error("Failure : getsockopt for SCTP_RTOINFO: (%d:%s)", + errno, strerror( errno )); + goto cleanup; + } + + d_trace(3,"Old RTO (initial:%d max:%d min:%d)\n", + rtoinfo.srto_initial, + rtoinfo.srto_max, + rtoinfo.srto_min); + + /* FIXME : Need to configure this param */ + rtoinfo.srto_initial = 1000; + rtoinfo.srto_min = 100; + rtoinfo.srto_max = 1000; + + if (setsockopt(sock, IPPROTO_SCTP, SCTP_RTOINFO, + &rtoinfo, sizeof(rtoinfo)) != 0 ) + { + d_error("Failure : setsockopt for SCTP_RTOINFO: (%d:%s)", + errno, strerror( errno )); + goto cleanup; + } + d_trace(3,"New RTO (initial:%d max:%d min:%d)\n", + rtoinfo.srto_initial, + rtoinfo.srto_max, + rtoinfo.srto_min); + + socklen = sizeof(initmsg); + if (getsockopt(sock, IPPROTO_SCTP, SCTP_INITMSG, + &initmsg, &socklen) != 0 ) + { + d_error("Failure : getsockopt for SCTP_INITMSG: (%d:%s)", + errno, strerror( errno )); + goto cleanup; + } + + d_trace(3,"Old INITMSG (numout:%d maxin:%d maxattempt:%d maxinit_to:%d)\n", + initmsg.sinit_num_ostreams, + initmsg.sinit_max_instreams, + initmsg.sinit_max_attempts, + initmsg.sinit_max_init_timeo); + + /* FIXME : Need to configure this param */ + initmsg.sinit_max_attempts = 4; + initmsg.sinit_max_init_timeo = 8000; /* 8secs */ + + if (setsockopt(sock, IPPROTO_SCTP, SCTP_INITMSG, + &initmsg, sizeof(initmsg)) != 0 ) + { + d_error("Failure : setsockopt for SCTP_INITMSG: (%d:%s)", + errno, strerror( errno )); + goto cleanup; + } + + d_trace(3,"New INITMSG (numout:%d maxin:%d maxattempt:%d maxinit_to:%d)\n", + initmsg.sinit_num_ostreams, + initmsg.sinit_max_instreams, + initmsg.sinit_max_attempts, + initmsg.sinit_max_init_timeo); + } + + /* Set socket descriptor */ + net_sock->sock_id = sock; + +cleanup: + if (rc < 0) + { + close(sock); + pool_free_node(&net_pool, net_sock); + } + + return net_sock; +} + +static void net_sock_delete(net_sock_t *net_sock) +{ + pool_free_node(&net_pool, net_sock); + return; +} + +/** Resolve host name */ +int net_resolve_host(const char *host, struct in_addr *addr) +{ + int rc; + /* FIXME : Resolve host by using DNS */ + rc = inet_aton(host, addr); + return rc; +} + +static int _net_open_addr(net_sock_t **net_sock, + const c_uint32_t local_addr, + const char *remote_host, + const int lport, + const int rport, + int type, int proto, const int flag) +{ + struct sockaddr_in sock_addr; + int rc; + net_sock_t *result_sock = NULL; + socklen_t addr_len; + + d_assert(net_sock, return -1, "net_sock is NULL\n"); + + result_sock = net_sock_create(type, proto); + if (result_sock == NULL) + { + return -1; + } + + /* FIXME : Set socket option */ + + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = htons(rport); + + /* Resolve host(it must be hostname or valid IP) */ + if (!net_resolve_host(remote_host, &sock_addr.sin_addr)) + { + goto cleanup; + } + + result_sock->type = type; + result_sock->proto = proto; + + /* Connect to host */ + if (proto == IPPROTO_UDP || + (proto == IPPROTO_SCTP && (lport != 0 || local_addr))) + { + struct sockaddr_in cli_addr; + + memset(&cli_addr, 0, sizeof(cli_addr)); + cli_addr.sin_family = AF_INET; + cli_addr.sin_addr.s_addr = local_addr; + cli_addr.sin_port = htons(lport); + + if (bind(result_sock->sock_id, (struct sockaddr *)&cli_addr, + sizeof(cli_addr)) < 0) + { + d_error("bind error(proto:%d lport:%d)",proto,lport); + goto cleanup; + } + } + + if (proto == IPPROTO_TCP || + (proto == IPPROTO_SCTP && type == SOCK_STREAM)) + { + rc = connect(result_sock->sock_id, + (struct sockaddr *)&sock_addr, sizeof(sock_addr)); + if (rc < 0) + { + d_error("connect error(proto:%d remote:%s dport:%d lport:%d)", + proto, + remote_host, + rport, + lport); + goto cleanup; + } + addr_len = sizeof(result_sock->remote); + if (getpeername(result_sock->sock_id, + (struct sockaddr *)&result_sock->remote, &addr_len) != 0) + { + d_warn("getpeername error = %d\n",errno); + } + } + else + { + memcpy(&result_sock->remote, &sock_addr, sizeof(sock_addr)); + } + +#if 0 /* deprecated */ + addr_len = sizeof(result_sock->local); + if (getsockname(result_sock->sock_id, + (struct sockaddr *)&result_sock->local, &addr_len) + != 0) + { + d_warn("getsockname error = %d\n",errno); + } +#endif + + *net_sock = result_sock; + + return 0; + +cleanup: + net_close(result_sock); + return -1; +} + +/** Create TCP/UDP socket and open it */ +int net_open(net_sock_t **net_sock, const char *host, + const int lport, + const int rport, + int type, int proto, const int flag) +{ + return _net_open_addr(net_sock, + 0, + host, + lport, + rport, + type, proto, flag); +} + +int net_open_with_addr(net_sock_t **net_sock, const c_uint32_t local_addr, + const char *remote_host, + const int lport, + const int rport, + int type, int proto, const int flag) +{ + return _net_open_addr(net_sock, + local_addr, + remote_host, + lport, + rport, + type, proto, flag); +} + +/** Read data from socket */ +int net_read(net_sock_t *net_sock, char *buffer, size_t size, int timeout) +{ + fd_set rfds; + struct timeval tv; + int rc; + + d_assert(net_sock, return -1, "net_sock is NULL\n"); + + FD_ZERO(&rfds); + FD_SET(net_sock->sock_id, &rfds); + + /* Set timeout */ + if (timeout > 0) + { + tv.tv_sec = timeout; + tv.tv_usec = 0; + } + + rc = select(net_sock->sock_id + 1, &rfds, NULL, NULL, + (timeout ? &tv : NULL)); + if (rc < 0) net_sock->sndrcv_errno = errno; + + if (rc == -1) /* Error */ + { + return -1; + } + + else if (rc) /* Data received */ + { + if (net_sock->proto == IPPROTO_TCP) + { + rc = recv(net_sock->sock_id, buffer, size, 0); + if (rc < 0) net_sock->sndrcv_errno = errno; + } + else if (net_sock->proto == IPPROTO_UDP) + { + struct sockaddr remote_addr; + socklen_t addr_len = sizeof(struct sockaddr); + + rc = recvfrom(net_sock->sock_id, buffer, size, 0, + &remote_addr, &addr_len); + if (rc < 0) net_sock->sndrcv_errno = errno; + + /* Save the remote address */ + memcpy(&net_sock->remote, &remote_addr, sizeof(remote_addr)); + } + else if (net_sock->proto == IPPROTO_SCTP) + { + struct sctp_sndrcvinfo sndrcvinfo; + int flags = 0; + struct sockaddr remote_addr; + socklen_t addr_len = sizeof(struct sockaddr); + + rc = sctp_recvmsg(net_sock->sock_id, buffer, size, + (struct sockaddr *)&remote_addr, &addr_len, + &sndrcvinfo, &flags); + if (rc < 0) net_sock->sndrcv_errno = errno; + + /* Save the remote address */ + if (net_sock->type == SOCK_SEQPACKET) + { + memcpy(&net_sock->remote, &remote_addr, sizeof(remote_addr)); + } + + if (flags & MSG_NOTIFICATION) + { + if (flags & MSG_EOR) + { + union sctp_notification *not = + (union sctp_notification *)buffer; + + switch( not->sn_header.sn_type ) + { + case SCTP_ASSOC_CHANGE : + d_trace(3, "SCTP_ASSOC_CHANGE" + "(type:%x, flags:%x, state:%x)\n", + not->sn_assoc_change.sac_type, + not->sn_assoc_change.sac_flags, + not->sn_assoc_change.sac_state); + + net_sock->sndrcv_errno = EAGAIN; + if (not->sn_assoc_change.sac_state == SCTP_COMM_UP) + return -2; + if (not->sn_assoc_change.sac_state == + SCTP_SHUTDOWN_COMP || + not->sn_assoc_change.sac_state == + SCTP_COMM_LOST) + net_sock->sndrcv_errno = ECONNREFUSED; + break; + case SCTP_SEND_FAILED : + d_error("SCTP_SEND_FAILED"); + break; + case SCTP_SHUTDOWN_EVENT : + d_trace(3, "SCTP_SHUTDOWN_EVENT\n"); + net_sock->sndrcv_errno = ECONNREFUSED; + break; + default : + net_sock->sndrcv_errno = EAGAIN; + d_error("Discarding event with unknown " + "flags = 0x%x, type 0x%x", + flags, not->sn_header.sn_type); + break; + } + } + else + { + d_error("Not engough buffer. Need more recv : 0x%x", flags); + } + return -1; + } + } + else + { + return -1; + } + } + else /* Timeout */ + { + return 0; + } + + return rc; +} + +/** Write data into socket */ +int net_write(net_sock_t *net_sock, char *buffer, size_t size, + struct sockaddr_in *dest_addr, int addrsize) +{ + char ip_addr[INET_ADDRSTRLEN]; + int rc; + + d_assert(net_sock, return -1, "net_sock is NULL\n"); + + d_trace(3,"%s)Send %d bytes to %s:%d(%s)\n", + net_sock->proto == IPPROTO_TCP ? "TCP" : + net_sock->proto == IPPROTO_UDP ? "UDP" : "SCTP", + size, INET_NTOP(&dest_addr->sin_addr, ip_addr), + ntohs(dest_addr->sin_port), + dest_addr->sin_family == AF_INET ? "AF_INET" : "Invalid"); + + if (net_sock->proto == IPPROTO_TCP) + { + rc = send(net_sock->sock_id, buffer, size, 0); + if (rc < 0) net_sock->sndrcv_errno = errno; + + return rc; + } + else if (net_sock->proto == IPPROTO_UDP || + net_sock->proto == IPPROTO_SCTP) + { + rc = sendto(net_sock->sock_id, buffer, size, 0, + (struct sockaddr *)dest_addr, addrsize); + if (rc < 0) net_sock->sndrcv_errno = errno; + + return rc; + } + else + { + return -1; + } + +} + +int net_send(net_sock_t *net_sock, char *buffer, size_t size) +{ + d_assert(net_sock && buffer, return -1, "Invalid params\n"); + + return net_write(net_sock, buffer, size, + &net_sock->remote, sizeof(net_sock->remote)); +} + +int net_sendto(net_sock_t *net_sock, char *buffer, size_t size, + c_uint32_t ip_addr, c_uint16_t port) +{ + struct sockaddr_in sock_addr; + d_assert(net_sock && buffer, return -1, "Invalid params\n"); + + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = htons(port); + sock_addr.sin_addr.s_addr = ip_addr; + + return net_write(net_sock, buffer, size, + &sock_addr, sizeof(sock_addr)); +} + +/** Close the socket */ +int net_close(net_sock_t *net_sock) +{ + int rc; + + d_assert(net_sock, return -1, "net_sock is NULL\n"); + + rc = close(net_sock->sock_id); + net_sock_delete(net_sock); + return rc; +} + +/** Accept the new connection.This function will allocation new session + * from network pool + */ +int net_accept(net_sock_t **new_accept_sock, net_sock_t *net_sock, int timeout) +{ + fd_set rfds; + struct timeval tv; + int new_sock; + int rc; + int sock; + socklen_t addr_len; + + sock = net_sock->sock_id; + + FD_ZERO(&rfds); + FD_SET(sock, &rfds); + + if (timeout > 0) + { + tv.tv_sec = timeout; + tv.tv_usec = 0; + } + + rc = select(sock+1, &rfds, NULL, NULL, (timeout ? &tv : NULL)); + if (rc == -1) + { + /* Error */ + goto cleanup; + } + + if (rc == 0) /* Timeout */ + { + goto cleanup; + } + else + { + if (FD_ISSET(sock, &rfds)) + { + net_sock_t *node = NULL; + pool_alloc_node(&net_pool, &node); + new_sock = accept(sock, NULL, NULL); + + node->sock_id = new_sock; + node->proto = net_sock->proto; + *new_accept_sock = node; + + /* Save local and remote address */ + addr_len = sizeof(node->remote); + if (getpeername(node->sock_id, + (struct sockaddr *)&node->remote, &addr_len) != 0) + { + d_warn("getpeername error = %d\n",errno); + } + +#if 0 /* deprecated */ + addr_len = sizeof(node->local); + if (getsockname(node->sock_id, + (struct sockaddr *)&node->local, &addr_len) != 0) + { + d_warn("getsockname error = %d\n",errno); + } +#endif + } + else + { + rc = -1; + } + } + +cleanup: + return rc; +} + +/** Listen connection */ +int net_listen_with_addr( + net_sock_t **net_sock, const int type, const int proto, + const int port, const c_uint32_t addr) +{ + struct sockaddr_in sock_addr; + net_sock_t *result_sock = NULL; + + /* Create socket */ + result_sock = net_sock_create(type, proto); + if (result_sock == NULL) + { + return -1; + } + + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = htons(port); + sock_addr.sin_addr.s_addr = addr; + + if (bind(result_sock->sock_id, (const void *)&sock_addr, + sizeof(sock_addr)) < 0) + { + goto cleanup; + } + + if (proto == IPPROTO_TCP || proto == IPPROTO_SCTP) + { + if (listen(result_sock->sock_id, 5) < 0) + { + goto cleanup; + } + } + + result_sock->type = type; + result_sock->proto = proto; + + *net_sock = result_sock; + + return 0; + +cleanup: + net_close(result_sock); + return -1; +} + +int net_listen( + net_sock_t **net_sock, const int type, const int proto, + const int port) +{ + return net_listen_with_addr(net_sock, type, proto, port, INADDR_ANY); +} + + +/****************************************************************************** + * FTP Library +******************************************************************************/ +static int net_ftp_readline(net_sock_t *net_sock, char *buf, int buf_size) +{ + int cnt = 0; + int rc; + char c; + + while (1) + { + rc = net_read(net_sock, &c, 1, 0); + if (rc != 1) + { + /* Error */ + } + + if ( c == '\n') + { + break; + } + + if (cnt < buf_size) + { + buf[cnt++] = c; + } + } + + if (cnt < buf_size) + { + buf[cnt] = '\0'; + } + else + { + buf[buf_size-1] = '\0'; + } + + d_trace(1, "RX:%s\n",buf); + + return cnt; +} + +static int net_ftp_get_reply(net_ftp_t *session) +{ + int more = 0; + int rc ; + int first_line = 1; + int code = 0; + + d_assert(session, return -1, "Invalid session\n"); + + do + { + if ((rc = net_ftp_readline(session->ctrl_sock, session->resp_buf, + sizeof(session->resp_buf))) < 0) + { + return rc; + } + if (first_line) + { + code = strtoul(session->resp_buf, NULL, 0); + first_line = 0; + more = (session->resp_buf[3] == '-'); + } + else + { + if (isdigit(session->resp_buf[0]) && isdigit(session->resp_buf[1]) + && isdigit(session->resp_buf[2]) && + (code == strtoul(session->resp_buf, NULL, 0)) && + session->resp_buf[3] == ' ') + { + more = 0; + } + else + { + more = 1; + } + } + + } while (more); + + return (session->resp_buf[0] - '0'); +} + +static int net_ftp_send_cmd(net_ftp_t *session) +{ + int rc; + + d_assert(session, return -1, "Invalid session\n"); + d_trace(1,"TX:%s\n",session->cmd_buf); + rc = net_send(session->ctrl_sock, session->cmd_buf, + strlen(session->cmd_buf)); + if (rc != strlen(session->cmd_buf)) + { + d_error("FTP : net_ftp_send_cmd error\n"); + return -1; + } + rc = net_ftp_get_reply(session); + return rc; +} + +int net_ftp_open(const char *host, + const char *username, + const char *passwd, + int flag, + net_ftp_t **ftp_session) +{ + int port = 21; /* default ftp port */ + int rc = -1; + net_ftp_t *session = NULL; + char *ptr = NULL; + + d_assert(ftp_session, return -1, "Invalid ftp sesssion\n"); + *ftp_session = NULL; + + pool_alloc_node(&ftp_pool, &session); + d_assert(session != NULL, return -1,"No ftp pool is availabe\n"); + + memset(session, 0, sizeof(net_ftp_t)); + + /* Check if port number is given. + * ex: 192.168.1.1:1111 + */ + if ((ptr = strchr(host,':')) != NULL) + { + *ptr++ = '\0'; + port = atoi(ptr); + } + + /* Open control channel */ + rc = net_open(&session->ctrl_sock, host, 0, port, + SOCK_DGRAM, IPPROTO_TCP, 0); + if (rc != 0) + { + d_error("net_open error(errno = %d) : host = %s, port = %d\n", + errno, + host,port); + pool_free_node(&ftp_pool, session); + return -1; + } + + /* Read welcome messages */ + net_ftp_get_reply(session); + + /* Login */ + sprintf(session->cmd_buf,"USER %s\r\n", username ? username : "anonymous"); + rc = net_ftp_send_cmd(session); + if (rc != 3) + { + d_error("FTP : User %s not accepted\n", username); + goto cleanup; + } + sprintf(session->cmd_buf,"PASS %s\r\n", passwd ? passwd : "taiji@"); + rc = net_ftp_send_cmd(session); + if (rc !=2) + { + d_error("FTP : Login failed for user %s\n", + username ? username : "anonymous"); + goto cleanup; + } + + /* Ftp login success */ + sprintf(session->cmd_buf,"TYPE I\r\n"); + rc = net_ftp_send_cmd(session); + if (rc !=2 ) + { + d_error("FTP : TYPE failed\n"); + goto cleanup; + } + session->flag = flag; + *ftp_session = session; + + return 0; + +cleanup: + pool_free_node(&ftp_pool, session); + net_close(session->ctrl_sock); + + return -1; +} + + +static int net_ftp_opendata(net_ftp_t *ftp_session) +{ + char *cp = NULL; + int port = 0; + int rc; + char ip_addr[INET_ADDRSTRLEN]; + + d_assert(ftp_session, return -1, "Invalid session\n"); + + /* FIXME: Passive or Active */ + sprintf(ftp_session->cmd_buf,"PASV\r\n"); + rc = net_ftp_send_cmd(ftp_session); + if (rc != 2) + { + d_error("FTP : PASV failed\n"); + return -1; + } + /* Response is like + * 227 Entering Passive Mode (0,0,0,0,p1,p2) + * Server's port for data connection is p1*256 + p2 + */ + cp = strchr(ftp_session->resp_buf, '('); + if (cp) + { + unsigned int v[6]; + + sscanf(cp,"(%u,%u,%u,%u,%u,%u)",&v[0],&v[1],&v[2],&v[3],&v[4],&v[5]); + port = v[4]*256 + v[5]; + } + + /* Open control channel */ + rc = net_open(&ftp_session->data_sock, + INET_NTOP(&ftp_session->ctrl_sock->remote.sin_addr, ip_addr), + 0, + port, + SOCK_STREAM, IPPROTO_TCP, 0); + if (rc != 0) + { + d_error("net_open error in net_ftp_opendata(host = %s,port = %d)\n", + INET_NTOP(&ftp_session->ctrl_sock->remote.sin_addr, ip_addr), + port); + return -1; + } + + return 0; +} + +int net_ftp_get(net_ftp_t *ftp_session, + const char *remote_filename, + const char *local_filename) +{ + int rc; + int len; + int local_fd; + int total_size = 0; + char buf[512]; + char *l_filename = NULL; + + d_assert(ftp_session, return -1, "Invalid session\n"); + + d_assert(remote_filename, return -1, + "Invalid filename.It should not be NULL\n"); + + /* Open data channel */ + rc = net_ftp_opendata(ftp_session); + if (rc != 0) + { + return -1; + } + + sprintf(ftp_session->cmd_buf,"RETR %s\r\n",remote_filename); + rc = net_ftp_send_cmd(ftp_session); + if (rc != 1) + { + d_error("FTP : RETR %s failed\n",remote_filename); + return -1; + } + + /* Open local file descriptor */ + if (local_filename == NULL) + { + /* Strip leading '/' if exist */ + l_filename = strrchr(remote_filename,'/'); + if (l_filename) + l_filename++; + else + l_filename = (char *)remote_filename; + } + else + { + l_filename = (char *)local_filename; + } + + local_fd = open(l_filename, O_RDWR|O_CREAT, 0644); + if (local_fd == -1) + { + d_error("FTP : local open error(filename = %s)\n",local_filename); + return -1; + } + + do { + len = net_read(ftp_session->data_sock, buf, 512, 0); + if (len > 0) + { + /* Write to file */ + write(local_fd, buf, len); + } + else + { + break; + } + total_size += len; + } while (1); + + d_trace(1,"Receive completed (bytes = %d)\n",total_size); + + rc = net_ftp_get_reply(ftp_session); + close(local_fd); + + net_close(ftp_session->data_sock); + ftp_session->data_sock = NULL; + + return 0; +} + +int net_ftp_put(net_ftp_t *ftp_session, + const char *local_filename, + const char *remote_filename) +{ + int rc; + int len; + int local_fd; + int total_size = 0; + char buf[512]; + char *r_filename = NULL; + + d_assert(ftp_session, return -1, "Invalid session\n"); + + d_assert(local_filename, return -1, + "Invalid filename.It should not be NULL\n"); + + /* Open data channel */ + rc = net_ftp_opendata(ftp_session); + if (rc != 0) + { + return -1; + } + + if (remote_filename == NULL) + { + r_filename = strrchr(local_filename, '/'); + if (r_filename) + r_filename++; + else + r_filename = (char *)local_filename; + } + else + { + r_filename = (char *)remote_filename; + } + + sprintf(ftp_session->cmd_buf,"STOR %s\r\n",r_filename); + rc = net_ftp_send_cmd(ftp_session); + if (rc != 1) + { + d_error("FTP : STOR %s failed\n",remote_filename); + return -1; + } + + /* Open local file descriptor */ + local_fd = open(local_filename, O_RDONLY, 0); + if (local_fd == -1) + { + d_error("FTP : local open error(filename = %s)\n",local_filename); + return -1; + } + + do { + len = read(local_fd, buf, 512); + if (len > 0) + { + len = net_send(ftp_session->data_sock, buf, len); + } + else + { + break; + } + total_size += len; + } while (1); + net_close(ftp_session->data_sock); + ftp_session->data_sock = NULL; + d_trace(1,"Trasnsmit completed (bytes = %d)\n",total_size); + rc = net_ftp_get_reply(ftp_session); + close(local_fd); + + return 0; +} + +int net_ftp_close(net_ftp_t *ftp_session) +{ + d_assert(ftp_session, return -1, "Invalid session\n"); + + if (ftp_session->ctrl_sock) + { + net_close(ftp_session->ctrl_sock); + } + if (ftp_session->data_sock) + { + net_close(ftp_session->data_sock); + } + pool_free_node(&ftp_pool, ftp_session); + return 0; +} + +int net_ftp_quit(net_ftp_t *ftp_session) +{ + int rc; + d_assert(ftp_session, return -1, "Invalid session\n"); + + sprintf(ftp_session->cmd_buf,"QUIT\r\n"); + rc = net_ftp_send_cmd(ftp_session); + if (rc != 2) + { + d_error("FTP : QUIT failed\n"); + return -1; + } + return 0; +} + + +#if LINUX == 1 +/****************************************************************************** + * Network link (raw socket) +******************************************************************************/ + +int net_raw_open(net_link_t **net_link, int proto) +{ + int sock; + net_link_t *new_link = NULL; + + d_assert(net_link, return -1, "Invalid arguments\n"); + + d_assert(getuid() == 0 || geteuid() == 0 , return -1, + "ROOT privileges required to open the interface\n"); + + pool_alloc_node(&link_pool, &new_link); + d_assert(new_link != NULL, return -1,"No link pool is availabe\n"); + + memset(new_link, 0, sizeof(net_link_t)); + /* Create raw socket */ + sock = socket(PF_INET, SOCK_RAW, proto); + + if (sock < 0) + { + return -1; + } + + new_link->fd = sock; + + *net_link = new_link; + return 0; +} + +int net_link_open(net_link_t **net_link, char *device, int proto) +{ + int sock,ioctl_sock; + net_link_t *new_link = NULL; + struct ifreq ifr; + struct sockaddr_ll sll; + + d_assert(net_link && device, return -1, "Invalid arguments\n"); + + d_assert(getuid() == 0 || geteuid() == 0 , return -1, + "ROOT privileges required to open the interface\n"); + + pool_alloc_node(&link_pool, &new_link); + d_assert(new_link != NULL, return -1,"No link pool is availabe\n"); + + memset(new_link, 0, sizeof(net_link_t)); + /* Create raw socket */ +#if 0 + sock = socket(PF_INET, SOCK_RAW, htons(ETH_P_ALL)); +#else + sock = socket(PF_PACKET, SOCK_RAW, htons(proto)); +#endif + if (sock < 0) + { + return -1; + } + + ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (ioctl_sock < 0) + { + close(sock); + return -1; + } + + /* Save socket descriptor */ + new_link->fd = sock; + new_link->ioctl_sock = ioctl_sock; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + /* Save the interface name */ + strncpy(new_link->ifname, ifr.ifr_name, sizeof(new_link->ifname)); + + /* Get the interface address */ + if (ioctl(ioctl_sock, SIOCGIFHWADDR, &ifr) < 0) + { + d_error("ioctl[SIOCGIFHWADDR] error(errno = %d)\n",errno); + goto cleanup; + } + memcpy(&new_link->hwaddr, &ifr.ifr_hwaddr, sizeof(ifr.ifr_hwaddr)); + + /* Get the interface index */ + if (ioctl(ioctl_sock, SIOCGIFINDEX, &ifr) < 0) + { + d_error("ioctl[SIOCGIFINDEX] error(errno = %d)\n",errno); + goto cleanup; + } + + sll.sll_family = AF_PACKET; + sll.sll_ifindex = ifr.ifr_ifindex; + sll.sll_protocol = htons(proto); + + + if (bind(sock, (struct sockaddr *)&sll, sizeof(sll)) == 1) + { + d_error("bind error(errno = %d)\n",errno); + goto cleanup; + } + + *net_link = new_link; + return 0; + +cleanup: + pool_free_node(&link_pool, new_link); + close(sock); + close(ioctl_sock); + return -1; +} + +int net_link_promisc(net_link_t *net_link, int enable) +{ + struct ifreq ifr; + + d_assert(net_link,return -1, "net_link is NULL\n"); + + strncpy(ifr.ifr_name, net_link->ifname, sizeof(ifr.ifr_name)); + + if (ioctl(net_link->ioctl_sock, SIOCGIFFLAGS, &ifr) < 0) + { + d_error("ioctl[SIOCGIFINDEX] error(errno = %d)\n",errno); + return -1; + } + + if (enable) + { + + if ((ifr.ifr_flags & IFF_PROMISC) == 0) + { + ifr.ifr_flags |= IFF_PROMISC; + if (ioctl(net_link->ioctl_sock, SIOCSIFFLAGS, &ifr) == -1) + { + d_error("ioctl[SIOCSIFFLAGS] error(errno = %d)\n",errno); + return -1; + } + + } + } + else + { + if ((ifr.ifr_flags & IFF_PROMISC)) + { + ifr.ifr_flags &= ~IFF_PROMISC; + if (ioctl(net_link->ioctl_sock, SIOCSIFFLAGS, &ifr) == -1) + { + d_error("ioctl[SIOCSIFFLAGS] error(errno = %d)\n",errno); + return -1; + } + } + } + return 0; +} + +/** Close network interface */ +int net_link_close(net_link_t *net_link) +{ + d_assert(net_link,return -1, "net_link is NULL\n"); + /* Disable promisc mode if enabled */ + net_link_promisc(net_link, 0); + close(net_link->fd); + close(net_link->ioctl_sock); + pool_free_node(&link_pool, net_link); + return 0; +} + +/** Close network interface */ +int net_raw_close(net_link_t *net_link) +{ + d_assert(net_link,return -1, "net_link is NULL\n"); + close(net_link->fd); + pool_free_node(&link_pool, net_link); + return 0; +} + +int net_link_write(net_link_t *net_link, char *buf, int len) +{ + d_assert(net_link && buf, return -1, "Invalid params\n"); + + return write(net_link->fd, buf, len); +} + +int net_link_sendto(net_link_t *net_link, char *buf, int len, + struct sockaddr *dest_addr, int addrlen) +{ + d_assert(net_link && buf, return -1, "Invalid params\n"); + + return sendto(net_link->fd, buf, len, 0, dest_addr, addrlen); +} + +int net_link_read(net_link_t *net_link, char *buffer, int size, int timeout) +{ + fd_set rfds; + struct timeval tv; + int rc; + + d_assert(net_link, return -1, "net_link is NULL\n"); + + FD_ZERO(&rfds); + FD_SET(net_link->fd, &rfds); + + /* Set timeout */ + if (timeout > 0) + { + tv.tv_sec = timeout; + tv.tv_usec = 0; + } + + rc = select(net_link->fd + 1, &rfds, NULL, NULL, (timeout ? &tv : NULL)); + if (rc == -1) /* Error */ + { + return -1; + } + + else if (rc) /* Data received */ + { +#if 0 + struct sockaddr remote_addr; + size_t addr_len; + + rc = recvfrom(net_link->fd, buffer, size, 0, &remote_addr, &addr_len); +#else + rc = recvfrom(net_link->fd, buffer, size, 0, NULL, NULL); +#endif + } + else /* Timeout */ + { + return 0; + } + + return rc; +} + +#endif /* #if LINUX == 1 */ + +static int net_register_fd(void *net_sl, int type, void *handler, void *data) +{ + net_fd_t *net_fd = NULL; + + pool_alloc_node(&net_fd_pool, &net_fd); + d_assert(net_fd != NULL, return -1,"No fd pool is availabe\n"); + + net_fd->net_sl = net_sl; + net_fd->type = type; + net_fd->data = data; + net_fd->handler = handler; + + if (type == NET_FD_TYPE_SOCK) + { + net_sock_t *net_sock = (net_sock_t *)net_sl; + + net_fd->fd = net_sock->sock_id; + } + else if (type == NET_FD_TYPE_LINK) + { + net_link_t *net_link = (net_link_t *)net_sl; + + net_fd->fd = net_link->fd; + } + else + { + pool_free_node(&net_fd_pool, net_fd); + d_error("Invalid fd type = %d",type); + return -1; + } + + mutex_lock(g_net_fd_tbl.mut); + if (net_fd->fd > g_net_fd_tbl.max_fd) + { + g_net_fd_tbl.max_fd = net_fd->fd; + } + + list_append(&g_net_fd_tbl.fd_list, net_fd); + mutex_unlock(g_net_fd_tbl.mut); + + return 0; +} + +static int net_unregister_fd(void *net_sl, int type) +{ + net_fd_t *iter; + int rc = -1; + + mutex_lock(g_net_fd_tbl.mut); + for (iter = (net_fd_t *)list_first(&g_net_fd_tbl.fd_list); + iter != NULL; + iter = (net_fd_t *)list_next(iter)) + { + if (iter->net_sl == net_sl) + { + d_assert(iter->type == type, break, "Invalid type matched"); + pool_free_node(&net_fd_pool, iter); + list_remove(&g_net_fd_tbl.fd_list, iter); + rc = 0; + break; + } + } + mutex_unlock(g_net_fd_tbl.mut); + + if (rc != 0) + { + d_error("Can not find net_fd"); + } + + return rc; +} + +/** Register net_sock */ +int net_register_sock(net_sock_t *net_sock, net_sock_handler handler, + void *data) +{ + int type = NET_FD_TYPE_SOCK; + + return net_register_fd((void *)net_sock, type, (void *)handler, data); +} + +/** Register net_link */ +int net_register_link(net_link_t *net_link, net_link_handler handler, + void *data) +{ + int type = NET_FD_TYPE_LINK; + + return net_register_fd((void *)net_link, type, (void *)handler, data); +} + +/** Unregister net_sock */ +int net_unregister_sock(net_sock_t *net_sock) +{ + int type = NET_FD_TYPE_SOCK; + + return net_unregister_fd((void *)net_sock, type); +} + +/** Unregister net_link */ +int net_unregister_link(net_link_t *net_link) +{ + int type = NET_FD_TYPE_LINK; + + return net_unregister_fd((void *)net_link, type); +} + +static void net_set_fds(fd_set *fds) +{ + net_fd_t *iter; + + FD_ZERO(fds); + + mutex_lock(g_net_fd_tbl.mut); + for (iter = (net_fd_t *)list_first(&g_net_fd_tbl.fd_list); + iter != NULL; + iter = (net_fd_t *)list_next(iter)) + { + FD_SET(iter->fd, fds); + } + mutex_unlock(g_net_fd_tbl.mut); +} + +static void net_fd_dispatch(fd_set *fds) +{ + net_fd_t *iter; + + mutex_lock(g_net_fd_tbl.mut); + for (iter = (net_fd_t *)list_first(&g_net_fd_tbl.fd_list); + iter != NULL; + iter = (net_fd_t *)list_next(iter)) + { + if (FD_ISSET(iter->fd, fds)) + { + if (iter->type == NET_FD_TYPE_SOCK) + { + net_sock_handler handler = (net_sock_handler)iter->handler; + if (handler) + { + handler((net_sock_t *)iter->net_sl, iter->data); + } + } + else if (iter->type == NET_FD_TYPE_LINK) + { + net_link_handler handler = (net_link_handler)iter->handler; + if (handler) + { + handler((net_link_t *)iter->net_sl, iter->data); + } + } + } + } + mutex_unlock(g_net_fd_tbl.mut); +} + +/** Read the multiple fds and run the registered handler */ +int net_fds_read_run(long timeout) +{ + struct timeval tv; + int rc; + + if (timeout > 0) + { + c_time_t usec = time_from_msec(timeout); + + tv.tv_sec = time_sec(usec); + tv.tv_usec = time_usec(usec); + } + + while (1) + { + net_set_fds(&g_net_fd_tbl.rfds); + + rc = select(g_net_fd_tbl.max_fd+1, &g_net_fd_tbl.rfds, NULL, NULL, + timeout > 0 ? &tv : NULL); + + if (rc < 0) + { + if (errno != EINTR && errno != 0) + { + if (errno == EBADF) + { + d_error("[FIXME] socket should be closed here(%d:%s)", + errno, strerror(errno)); + } + else + { + d_error("Select error(%d:%s)", errno, strerror(errno)); + } + } + break; + } + + /* Timeout */ + if (rc == 0) + { + break; + } + + /* Dispatch handler */ + net_fd_dispatch(&g_net_fd_tbl.rfds); + } + + return 1; +} diff --git a/lib/core/src/unix/pkbuf.c b/lib/core/src/unix/pkbuf.c new file mode 100644 index 0000000000..28be862bde --- /dev/null +++ b/lib/core/src/unix/pkbuf.c @@ -0,0 +1,498 @@ +#include "core.h" +#define TRACE_MODULE _pkbuf +#include "core_pkbuf.h" +#include "core_errno.h" +#include "core_lib.h" +#include "core_debug.h" +#include "core_pool.h" + +#define MAX_NUM_OF_CLBUF 32 +#define MAX_NUM_OF_PKBUF 32 + +pool_declare(clbuf_pool, clbuf_t, MAX_NUM_OF_CLBUF); +pool_declare(pkbuf_pool, pkbuf_t, MAX_NUM_OF_PKBUF); + +#undef BOUNDARY +#define BOUNDARY 4 + +#define SIZEOF_CLUSTER_128 CORE_ALIGN(128+MAX_SIZEOF_HEADROOM, BOUNDARY) +#define SIZEOF_CLUSTER_256 CORE_ALIGN(256+MAX_SIZEOF_HEADROOM, BOUNDARY) +#define SIZEOF_CLUSTER_512 CORE_ALIGN(512+MAX_SIZEOF_HEADROOM, BOUNDARY) +#define SIZEOF_CLUSTER_1024 CORE_ALIGN(1024+MAX_SIZEOF_HEADROOM, BOUNDARY) +#define SIZEOF_CLUSTER_2048 CORE_ALIGN(2048+MAX_SIZEOF_HEADROOM, BOUNDARY) +#define SIZEOF_CLUSTER_8192 CORE_ALIGN(8192+MAX_SIZEOF_HEADROOM, BOUNDARY) + +#define MAX_NUM_OF_CLUSTER_128 32 +#define MAX_NUM_OF_CLUSTER_256 32 +#define MAX_NUM_OF_CLUSTER_512 32 +#define MAX_NUM_OF_CLUSTER_1024 32 +#define MAX_NUM_OF_CLUSTER_2048 32 +#define MAX_NUM_OF_CLUSTER_8192 32 + +typedef c_uint8_t cluster_128_t[SIZEOF_CLUSTER_128]; +typedef c_uint8_t cluster_256_t[SIZEOF_CLUSTER_256]; +typedef c_uint8_t cluster_512_t[SIZEOF_CLUSTER_512]; +typedef c_uint8_t cluster_1024_t[SIZEOF_CLUSTER_1024]; +typedef c_uint8_t cluster_2048_t[SIZEOF_CLUSTER_2048]; +typedef c_uint8_t cluster_8192_t[SIZEOF_CLUSTER_2048]; + +pool_declare(cluster_128_pool, cluster_128_t, MAX_NUM_OF_CLUSTER_128); +pool_declare(cluster_256_pool, cluster_256_t, MAX_NUM_OF_CLUSTER_256); +pool_declare(cluster_512_pool, cluster_512_t, MAX_NUM_OF_CLUSTER_512); +pool_declare(cluster_1024_pool, cluster_1024_t, MAX_NUM_OF_CLUSTER_1024); +pool_declare(cluster_2048_pool, cluster_2048_t, MAX_NUM_OF_CLUSTER_2048); +pool_declare(cluster_8192_pool, cluster_8192_t, MAX_NUM_OF_CLUSTER_8192); + +static mutex_id mutex; + +status_t pkbuf_init(void) +{ + mutex_create(&mutex, MUTEX_DEFAULT); + + pool_init(&clbuf_pool, MAX_NUM_OF_CLBUF); + pool_init(&pkbuf_pool, MAX_NUM_OF_PKBUF); + + pool_init(&cluster_128_pool, MAX_NUM_OF_CLUSTER_128); + pool_init(&cluster_256_pool, MAX_NUM_OF_CLUSTER_256); + pool_init(&cluster_512_pool, MAX_NUM_OF_CLUSTER_512); + pool_init(&cluster_1024_pool, MAX_NUM_OF_CLUSTER_1024); + pool_init(&cluster_2048_pool, MAX_NUM_OF_CLUSTER_2048); + pool_init(&cluster_8192_pool, MAX_NUM_OF_CLUSTER_8192); + + return CORE_OK; +} +status_t pkbuf_final(void) +{ + pool_final(&clbuf_pool); + pool_final(&pkbuf_pool); + + pool_final(&cluster_128_pool); + pool_final(&cluster_256_pool); + pool_final(&cluster_512_pool); + pool_final(&cluster_1024_pool); + pool_final(&cluster_2048_pool); + pool_final(&cluster_8192_pool); + + mutex_delete(mutex); + + return CORE_OK; +} + +void pkbuf_show(void) +{ + d_print("Pkbuf : Size = %d, Avail = %d\n",pool_size(&pkbuf_pool), + pool_avail(&pkbuf_pool)); + d_print("clfbuf : Size = %d, Avail = %d\n\n",pool_size(&clbuf_pool), + pool_avail(&clbuf_pool)); + + d_print("cluster128 : Size = %d, Avail = %d\n",pool_size(&cluster_128_pool), + pool_avail(&cluster_128_pool)); + d_print("cluster256 : Size = %d, Avail = %d\n",pool_size(&cluster_256_pool), + pool_avail(&cluster_256_pool)); + d_print("cluster512 : Size = %d, Avail = %d\n",pool_size(&cluster_512_pool), + pool_avail(&cluster_512_pool)); + d_print("cluster1024 : Size = %d, Avail = %d\n", + pool_size(&cluster_1024_pool), + pool_avail(&cluster_128_pool)); + d_print("cluster2048 : Size = %d, Avail = %d\n", + pool_size(&cluster_2048_pool), + pool_avail(&cluster_2048_pool)); + +} + +static clbuf_t* clbuf_alloc(c_uint16_t length); +static void clbuf_free(clbuf_t *clbuf); + +static clbuf_t* clbuf_alloc(c_uint16_t length) +{ + clbuf_t *clbuf = NULL; + c_uint8_t *cluster = NULL; + + pool_alloc_node(&clbuf_pool, &clbuf); + d_assert(clbuf, return NULL, "No more free clbuf. "); + + if (length <= 128) + { + pool_alloc_node(&cluster_128_pool, &cluster); + clbuf->size = SIZEOF_CLUSTER_128; + } + else if (length <= 256) + { + pool_alloc_node(&cluster_256_pool, &cluster); + clbuf->size = SIZEOF_CLUSTER_256; + } + else if (length <= 512) + { + pool_alloc_node(&cluster_512_pool, &cluster); + clbuf->size = SIZEOF_CLUSTER_512; + } + else if (length <= 1024) + { + pool_alloc_node(&cluster_1024_pool, &cluster); + clbuf->size = SIZEOF_CLUSTER_1024; + } + else if (length <= 2048) + { + pool_alloc_node(&cluster_2048_pool, &cluster); + clbuf->size = SIZEOF_CLUSTER_2048; + } + else + { + pool_alloc_node(&cluster_8192_pool, &cluster); + clbuf->size = SIZEOF_CLUSTER_8192; + } + + d_assert(cluster, pool_free_node(&clbuf_pool, clbuf); return NULL, + "No more free cluster. length:%d requested", length); + + clbuf->ref = 0; + clbuf->cluster = cluster; + + return clbuf; +} + +static void clbuf_free(clbuf_t *clbuf) +{ + d_assert(clbuf, return, "Null param"); + d_assert(clbuf->cluster, return, "clbuf has no cluster"); + + switch (clbuf->size) + { + case SIZEOF_CLUSTER_128: + pool_free_node(&cluster_128_pool, clbuf->cluster); + break; + case SIZEOF_CLUSTER_256: + pool_free_node(&cluster_256_pool, clbuf->cluster); + break; + case SIZEOF_CLUSTER_512: + pool_free_node(&cluster_512_pool, clbuf->cluster); + break; + case SIZEOF_CLUSTER_1024: + pool_free_node(&cluster_1024_pool, clbuf->cluster); + break; + case SIZEOF_CLUSTER_2048: + pool_free_node(&cluster_2048_pool, clbuf->cluster); + break; + case SIZEOF_CLUSTER_8192: + pool_free_node(&cluster_8192_pool, clbuf->cluster); + break; + default: + d_assert(0, return, "clbuf has invalid size %d", clbuf->size); + break; + } + + pool_free_node(&clbuf_pool, clbuf); + + return; +} + +pkbuf_t* pkbuf_alloc(c_uint16_t headroom, c_uint16_t length) +{ + pkbuf_t *np = NULL, *pnp, *ret; + clbuf_t *clbuf = NULL; + c_uint16_t rem_length; + + d_assert(headroom <= MAX_SIZEOF_HEADROOM, return NULL, + "Max size of headroom is %d, but %d requested", + MAX_SIZEOF_HEADROOM, headroom); + + clbuf = clbuf_alloc(length); + d_assert(clbuf, return NULL, "Can't allocate clbuf"); + + pool_alloc_node(&pkbuf_pool, &np); + d_assert(np, clbuf_free(clbuf); return NULL, "No more free pkbuf"); + ret = np; + + np->next = NULL; + np->clbuf = clbuf; + np->payload = (void*)CORE_ALIGN((c_uintptr_t)(clbuf->cluster + headroom), BOUNDARY); + np->tot_len = length; + np->len = c_min(length, clbuf->size - (np->payload - clbuf->cluster)); + np->flags = 0; + clbuf->ref = 1; + + pnp = np; + rem_length = length - np->len; + + while (rem_length > 0) + { + clbuf = clbuf_alloc(rem_length); + d_assert(clbuf, break, "Can't allocate clbuf"); + + pool_alloc_node(&pkbuf_pool, &np); + d_assert(np, clbuf_free(clbuf); break, "No more free pkbuf"); + + /* Chaining */ + pnp->next = np; + + np->next = NULL; + np->clbuf = clbuf; + np->payload = clbuf->cluster; + np->tot_len = rem_length; + np->len = c_min(rem_length, clbuf->size); + np->flags = 0; + clbuf->ref = 1; + + pnp = np; + rem_length -= np->len; + } + + /* Abnormal break */ + if (rem_length > 0) + { + if (ret) + pkbuf_free(ret); + ret = NULL; + } + + return ret; +} + +status_t pkbuf_header(pkbuf_t *pkbuf, c_int16_t increment) +{ + clbuf_t *clbuf; + + d_assert(pkbuf, return CORE_ERROR, "Null param"); + d_assert(pkbuf->clbuf, return CORE_ERROR, "pkbuf has no clbuf"); + d_assert(pkbuf->clbuf->cluster, return CORE_ERROR, "clbuf has no cluster"); + + clbuf = pkbuf->clbuf; + + /* No change */ + if (increment == 0) + return CORE_OK; + + if (increment > 0) + { + if (pkbuf->payload - clbuf->cluster < increment) + return CORE_ERROR; + } + else + { + if (pkbuf->len < -increment) + return CORE_ERROR; + } + + pkbuf->payload -= increment; + pkbuf->tot_len += increment; + pkbuf->len += increment; + + return CORE_OK; +} + +void pkbuf_free(pkbuf_t *pkbuf) +{ + pkbuf_t *p, *q; + + d_assert(pkbuf, return, "Null param"); + + p = pkbuf; + while (p) + { + d_assert(p->clbuf, return, "param 'pkbuf' has no clbuf"); + + q = p->next; + + mutex_lock(mutex); + p->clbuf->ref--; + mutex_unlock(mutex); + + if (p->clbuf->ref == 0) + clbuf_free(p->clbuf); + + pool_free_node(&pkbuf_pool, p); + + p = q; + } + + return; +} + +void pkbuf_join(pkbuf_t *h, pkbuf_t *t) +{ + pkbuf_t *p; + + d_assert(h, return, "Null param"); + d_assert(t, return, "Null param"); + + /* proceed to last pbuf of chain */ + for (p = h; p->next != NULL; p = p->next) + { + /* add total length of second chain to all totals of first chain */ + p->tot_len += t->tot_len; + } + + d_assert(p->tot_len == p->len, return, + "p->tot_len(%d) == p->len(%d) (of last pbuf in chain)", + p->tot_len, p->len); + + d_assert(p->next == NULL, return, "p->next == NULL"); + + /* add total length of second chain to last pbuf total of first chain */ + p->tot_len += t->tot_len; + + /* chain last pbuf of head (p) with first of tail (t) */ + p->next = t; + + /* p->next now references t, but the caller will drop its reference to t, + * so netto there is no change to the reference count of t. */ +} + +pkbuf_t* pkbuf_copy(pkbuf_t *pkbuf) +{ + pkbuf_t *p, *np, *pnp = NULL, *ret = NULL; + + d_assert(pkbuf, return NULL, "Null param"); + + p = pkbuf; + + while (p) + { + pool_alloc_node(&pkbuf_pool, &np); + d_assert(np, break, "No more free pkbuf. "); + if (ret == NULL) ret = np; + + if (pnp) + pnp->next = np; + + np->next = NULL; + np->clbuf = p->clbuf; + np->payload = p->payload; + np->tot_len = p->tot_len; + np->len = p->len; + np->flags = p->flags; + + mutex_lock(mutex); + p->clbuf->ref++; + mutex_unlock(mutex); + + pnp = np; + p = p->next; + } + + /* Abnormal break */ + if (p) + { + if (ret) + pkbuf_free(ret); + ret = NULL; + } + + return ret; +} + +pkbuf_t* pkbuf_copy_partial(pkbuf_t *pkbuf, c_uint16_t offset, c_uint16_t len) +{ + pkbuf_t *p, *np, *pnp = NULL, *ret = NULL; + c_uint16_t copied = 0, bytes = 0, skipped = 0; + + d_assert(pkbuf, return NULL, "Null param"); + + if (pkbuf->tot_len < offset + len) + return NULL; + + p = pkbuf; + + while (p) + { + bytes += p->len; + + if (bytes > offset) + { + pool_alloc_node(&pkbuf_pool, &np); + d_assert(np, break, "No more free pkbuf. "); + + /* First block */ + if (ret == NULL) + { + ret = np; + np->payload = p->payload + (offset - skipped); + np->tot_len = len; + np->len = p->len - (offset - skipped); + } + else + { + np->payload = p->payload; + np->tot_len = pnp->tot_len - pnp->len; + np->len = p->len; + } + + np->next = NULL; + np->flags = p->flags; + np->clbuf = p->clbuf; + + mutex_lock(mutex); + p->clbuf->ref++; + mutex_unlock(mutex); + + if (pnp) + pnp->next = np; + pnp = np; + + copied += np->len; + + /* Check the last block */ + if (copied >= len) + { + np->len -= copied - len; + break; + } + } + + skipped += p->len; + + p = p->next; + } + + /* Abnormal break */ + if (copied < len) + { + if (ret) + pkbuf_free(ret); + ret = NULL; + } + + return ret; +} + +status_t pkbuf_tobuf(pkbuf_t *pkbuf, void *buf, c_uint16_t *buflen) +{ + pkbuf_t *p; + c_uint16_t copied = 0; + + d_assert(pkbuf, return CORE_ERROR, "Null param"); + d_assert(buf, return CORE_ERROR, "Null param"); + d_assert(buflen, return CORE_ERROR, "Null param"); + + if (pkbuf->tot_len > *buflen) + return CORE_ERROR; + + *buflen = 0; + + p = pkbuf; + + while (p) + { + d_assert(p->clbuf, return CORE_ERROR, "pkbuf has no clbuf"); + d_assert(p->clbuf->cluster, return CORE_ERROR, "clbuf has no cluster"); + + memcpy(buf + copied, p->payload, p->len); + copied += p->len; + + p = p->next; + } + + d_assert(copied == pkbuf->tot_len, return CORE_ERROR, + "Copy length isn't same with total length"); + + *buflen = copied; + + return CORE_OK;; +} + +status_t pkbuf_tobuf_partial(pkbuf_t *pkbuf, void *buf, c_uint16_t *buflen, + c_uint16_t offset, c_uint16_t len) +{ + + return CORE_OK; +} diff --git a/lib/core/src/unix/rwlock.c b/lib/core/src/unix/rwlock.c new file mode 100644 index 0000000000..0416234da6 --- /dev/null +++ b/lib/core/src/unix/rwlock.c @@ -0,0 +1,102 @@ +#include "core.h" +#include "core_rwlock.h" +#include "core_pool.h" +#include "core_debug.h" +#include "core_general.h" +#include "core_param.h" + +typedef struct _rwlock_t { + pthread_rwlock_t rwlock; +} rwlock_t; + +pool_declare(rwlock_pool, rwlock_t, MAX_NUM_OF_RWLOCK); + +status_t rwlock_init(void) +{ + pool_init(&rwlock_pool, MAX_NUM_OF_RWLOCK); + return CORE_OK; +} + +status_t rwlock_final(void) +{ + pool_final(&rwlock_pool); + return CORE_OK; +} + +status_t rwlock_create(rwlock_id *id) +{ + rwlock_t *new_rwlock; + status_t stat; + + pool_alloc_node(&rwlock_pool, &new_rwlock); + d_assert(new_rwlock, return CORE_ENOMEM, "rwlock_pool(%d) is not enough\n", + MAX_NUM_OF_RWLOCK); + + if ((stat = pthread_rwlock_init(&new_rwlock->rwlock, NULL))) + { + return stat; + } + + *id = (rwlock_id)new_rwlock; + return CORE_OK; +} + +status_t rwlock_rdlock(rwlock_id id) +{ + status_t stat; + rwlock_t *rwlock = (rwlock_t *)id; + + stat = pthread_rwlock_rdlock(&rwlock->rwlock); + return stat; +} + +status_t rwlock_tryrdlock(rwlock_id id) +{ + status_t stat; + rwlock_t *rwlock = (rwlock_t *)id; + + stat = pthread_rwlock_tryrdlock(&rwlock->rwlock); + /* Normalize the return code. */ + if (stat == EBUSY) + stat = CORE_EBUSY; + return stat; +} + +status_t rwlock_wrlock(rwlock_id id) +{ + status_t stat; + rwlock_t *rwlock = (rwlock_t *)id; + + stat = pthread_rwlock_wrlock(&rwlock->rwlock); + return stat; +} + +status_t rwlock_trywrlock(rwlock_id id) +{ + status_t stat; + rwlock_t *rwlock = (rwlock_t *)id; + + stat = pthread_rwlock_trywrlock(&rwlock->rwlock); + /* Normalize the return code. */ + if (stat == EBUSY) + stat = CORE_EBUSY; + return stat; +} + +status_t rwlock_unlock(rwlock_id id) +{ + status_t stat; + rwlock_t *rwlock = (rwlock_t *)id; + + stat = pthread_rwlock_unlock(&rwlock->rwlock); + return stat; +} + +status_t rwlock_delete(rwlock_id id) +{ + status_t stat; + rwlock_t *rwlock = (rwlock_t *)id; + + stat = pthread_rwlock_destroy(&rwlock->rwlock); + return stat; +} diff --git a/lib/core/src/unix/semaphore.c b/lib/core/src/unix/semaphore.c new file mode 100644 index 0000000000..7a4f95b6fb --- /dev/null +++ b/lib/core/src/unix/semaphore.c @@ -0,0 +1,96 @@ +#include "core.h" +#include "core_arch_semaphore.h" +#include "core_errno.h" +#include "core_param.h" +#include "core_general.h" +#include "core_debug.h" +#include "core_pool.h" + +pool_declare(semaphore_pool, semaphore_t, MAX_NUM_OF_SEMAPHORE); + +status_t semaphore_init(void) +{ + pool_init(&semaphore_pool, MAX_NUM_OF_SEMAPHORE); + return CORE_OK; +} + +status_t semaphore_final(void) +{ + pool_final(&semaphore_pool); + return CORE_OK; +} + +status_t semaphore_create(semaphore_id *id, c_uint32_t value) +{ + semaphore_t *new_semaphore; + c_time_t now = time_now(); + char semname[64]; + + pool_alloc_node(&semaphore_pool, &new_semaphore); + d_assert(new_semaphore, return CORE_ENOMEM, + "semaphore_pool(%d) is not enough\n", + MAX_NUM_OF_SEMAPHORE); + + sprintf(semname, "/CoRe%" C_UINT64_T_HEX_FMT, now); + + new_semaphore->semaphore = sem_open(semname, O_CREAT | O_EXCL, 0644, value); + if (new_semaphore->semaphore == (sem_t *)SEM_FAILED) + { + return CORE_ERROR; + } + + sem_unlink(semname); + + *id = (semaphore_id)new_semaphore; + return CORE_OK; +} + +status_t semaphore_wait(semaphore_id id) +{ + status_t rv; + semaphore_t *semaphore = (semaphore_t *)id; + + rv = sem_wait(semaphore->semaphore); + return rv; +} + +#if HAVE_SEM_TIMEDWAIT +status_t semaphore_timedwait(semaphore_id id, c_time_t timeout) +{ + status_t rv; + c_time_t then; + struct timespec abstime; + semaphore_t *semaphore = (semaphore_t *)id; + + then = time_now() + timeout; + abstime.tv_sec = time_sec(then); + abstime.tv_nsec = time_usec(then) * 1000; /* nanosesemaphores */ + + rv = sem_timedwait(semaphore->semaphore, &abstime); + if (rv == -1 && ETIMEDOUT == errno) + { + return CORE_TIMEUP; + } + return rv; +} +#endif + +status_t semaphore_post(semaphore_id id) +{ + status_t rv; + semaphore_t *semaphore = (semaphore_t *)id; + + rv = sem_post(semaphore->semaphore); + return rv; +} + +status_t semaphore_delete(semaphore_id id) +{ + status_t rv; + semaphore_t *semaphore = (semaphore_t *)id; + + rv = sem_close(semaphore->semaphore); + pool_free_node(&semaphore_pool, semaphore); + + return rv; +} diff --git a/lib/core/src/unix/signal.c b/lib/core/src/unix/signal.c new file mode 100644 index 0000000000..26a7d20d5e --- /dev/null +++ b/lib/core/src/unix/signal.c @@ -0,0 +1,239 @@ +#include "core.h" +#include "core_signal.h" + +/* + * Replace standard signal() with the more reliable sigaction equivalent + * from W. Richard Stevens' "Advanced Programming in the UNIX Environment" + * (the version that does not automatically restart system calls). + */ +core_sigfunc_t *core_signal(int signo, core_sigfunc_t *func) +{ + struct sigaction act, oact; + + act.sa_handler = func; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; +#ifdef SA_INTERRUPT /* SunOS */ + act.sa_flags |= SA_INTERRUPT; +#endif +#if defined(__osf__) && defined(__alpha) + /* XXX jeff thinks this should be enabled whenever SA_NOCLDWAIT is defined */ + + /* this is required on Tru64 to cause child processes to + * disappear gracefully - XPG4 compatible + */ + if ((signo == SIGCHLD) && (func == SIG_IGN)) + { + act.sa_flags |= SA_NOCLDWAIT; + } +#endif +#if defined(__NetBSD__) || defined(DARWIN) + /* ignoring SIGCHLD or leaving the default disposition doesn't avoid zombies, + * and there is no SA_NOCLDWAIT flag, so catch the signal and reap status in + * the handler to avoid zombies + */ + if ((signo == SIGCHLD) && (func == SIG_IGN)) + { + act.sa_handler = avoid_zombies; + } +#endif + if (sigaction(signo, &act, &oact) < 0) + return SIG_ERR; + return oact.sa_handler; +} + +static void remove_sync_sigs(sigset_t *sig_mask) +{ +#ifdef SIGABRT + sigdelset(sig_mask, SIGABRT); +#endif +#ifdef SIGBUS + sigdelset(sig_mask, SIGBUS); +#endif +#ifdef SIGEMT + sigdelset(sig_mask, SIGEMT); +#endif +#ifdef SIGFPE + sigdelset(sig_mask, SIGFPE); +#endif +#ifdef SIGILL + sigdelset(sig_mask, SIGILL); +#endif +#ifdef SIGIOT + sigdelset(sig_mask, SIGIOT); +#endif +#ifdef SIGPIPE + sigdelset(sig_mask, SIGPIPE); +#endif +#ifdef SIGSEGV + sigdelset(sig_mask, SIGSEGV); +#endif +#ifdef SIGSYS + sigdelset(sig_mask, SIGSYS); +#endif +#ifdef SIGTRAP + sigdelset(sig_mask, SIGTRAP); +#endif +#ifdef SIGCHLD + sigdelset(sig_mask, SIGCHLD); +#endif +#ifdef SIGWINCH + sigdelset(sig_mask, SIGWINCH); +#endif + +/* the rest of the signals removed from the mask in this function + * absolutely must be removed; you cannot block synchronous signals + * (requirement of pthreads API) + * + * SIGUSR2 is being removed from the mask for the convenience of + * Purify users (Solaris, HP-UX, SGI) since Purify uses SIGUSR2 + */ +#ifdef SIGUSR2 + sigdelset(sig_mask, SIGUSR2); +#endif +} + +status_t signal_thread(int (*signal_handler)(int signum)) +{ + sigset_t sig_mask; + int (*sig_func)(int signum) = (int (*)(int))signal_handler; + + /* This thread will be the one responsible for handling signals */ + sigfillset(&sig_mask); + + /* On certain platforms, sigwait() returns EINVAL if any of various + * unblockable signals are included in the mask. This was first + * observed on AIX and Tru64. + */ +#ifdef SIGKILL + sigdelset(&sig_mask, SIGKILL); +#endif +#ifdef SIGSTOP + sigdelset(&sig_mask, SIGSTOP); +#endif +#ifdef SIGCONT + sigdelset(&sig_mask, SIGCONT); +#endif +#ifdef SIGWAITING + sigdelset(&sig_mask, SIGWAITING); +#endif + + /* no synchronous signals should be in the mask passed to sigwait() */ + remove_sync_sigs(&sig_mask); + + /* On AIX (4.3.3, at least), sigwait() won't wake up if the high- + * order bit of the second word of flags is turned on. sigdelset() + * returns an error when trying to turn this off, so we'll turn it + * off manually. + * + * Note that the private fields differ between 32-bit and 64-bit + * and even between _ALL_SOURCE and !_ALL_SOURCE. Except that on + * AIX 4.3 32-bit builds and 64-bit builds use the same definition. + * + * Applicable AIX fixes such that this is no longer needed: + * + * APAR IY23096 for AIX 51B, fix included in AIX 51C, and + * APAR IY24162 for 43X. + */ +#if defined(_AIX) +#if defined(__64BIT__) && defined(_AIXVERSION_510) +#ifdef _ALL_SOURCE + sig_mask.ss_set[3] &= 0x7FFFFFFF; +#else /* not _ALL_SOURCE */ + sig_mask.__ss_set[3] &= 0x7FFFFFFF; +#endif +#else /* not 64-bit build, or 64-bit build on 4.3 */ +#ifdef _ALL_SOURCE + sig_mask.hisigs &= 0x7FFFFFFF; +#else /* not _ALL_SOURCE */ + sig_mask.__hisigs &= 0x7FFFFFFF; +#endif +#endif +#endif /* _AIX */ + + while (1) { +#if HAVE_SIGWAIT + int signal_received; + + if (sigwait(&sig_mask, &signal_received) != 0) + { + /* handle sigwait() error here */ + } + + if (sig_func(signal_received) == 1) + { + return CORE_OK; + } +#elif HAVE_SIGSUSPEND + sigsuspend(&sig_mask); +#else +#error No sigwait() and no sigsuspend() +#endif + } +} + +status_t signal_init(void) +{ + sigset_t sig_mask; + int rv; + + /* All threads should mask out signals to be handled by + * the thread doing sigwait(). + * + * No thread should ever block synchronous signals. + * See the Solaris man page for pthread_sigmask() for + * some information. Solaris chooses to knock out such + * processes when a blocked synchronous signal is + * delivered, skipping any registered signal handler. + * AIX doesn't call a signal handler either. At least + * one level of linux+glibc does call the handler even + * when the synchronous signal is blocked. + */ + sigfillset(&sig_mask); + remove_sync_sigs(&sig_mask); + + if ((rv = pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) != 0) + { + rv = errno; + } + return rv; +} + +status_t signal_block(int signum) +{ +#if HAVE_SIGACTION + sigset_t sig_mask; + int rv; + + sigemptyset(&sig_mask); + + sigaddset(&sig_mask, signum); + + if ((rv = pthread_sigmask(SIG_BLOCK, &sig_mask, NULL)) != 0) + { + rv = errno; + } + return rv; +#else + return ENOTIMPL; +#endif +} + +status_t signal_unblock(int signum) +{ +#if HAVE_SIGACTION + sigset_t sig_mask; + int rv; + + sigemptyset(&sig_mask); + + sigaddset(&sig_mask, signum); + + if ((rv = pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) { + rv = errno; + } + return rv; +#else + return ENOTIMPL; +#endif +} diff --git a/lib/core/src/unix/start.c b/lib/core/src/unix/start.c new file mode 100644 index 0000000000..afcf85f09f --- /dev/null +++ b/lib/core/src/unix/start.c @@ -0,0 +1,84 @@ +#include "core.h" +#include "core_general.h" +#include "core_debug.h" +#include "core_pool.h" +#include "core_msgq.h" +#include "core_tlv.h" +#include "core_timer.h" +#include "core_mutex.h" +#include "core_cond.h" +#include "core_rwlock.h" +#include "core_semaphore.h" +#include "core_thread.h" +#include "core_net.h" +#include "core_file.h" +#include "core_pkbuf.h" + +status_t core_app_initialize(int *argc, + const char * const * *argv, + const char * const * *env) +{ + /* An absolute noop. At present, only Win32 requires this stub, but it's + * required in order to move command arguments passed through the service + * control manager into the process, and it's required to fix the char* + * data passed in from win32 unicode into utf-8, win32's core internal fmt. + */ + return core_initialize(); +} + +static int initialized = 0; + +status_t core_initialize(void) +{ + if (initialized++) + { + return CORE_OK; + } + + /* IMPORTANT: Mutex should be initialized firtly because node-pool + * framework uses mutex and it will be used by other xxx_init() */ + mutex_init(); + semaphore_init(); + cond_init(); + rwlock_init(); + thread_init(); + net_init(); + file_init(); + pkbuf_init(); + tlv_init(); + tm_init(); + msgq_init(); + d_msg_init(); + + return CORE_OK; +} + +void core_terminate(void) +{ + initialized--; + if (initialized) { + return; + } + + /* Reverse ordered finalization */ + d_msg_final(); + msgq_final(); + tm_final(); + tlv_final(); + pkbuf_final(); + tlv_init(); + file_final(); + net_final(); + thread_final(); + rwlock_final(); + cond_final(); + semaphore_final(); + mutex_final(); + + return; +} + +void core_terminate2(void) +{ + core_terminate(); +} diff --git a/lib/core/src/unix/thread.c b/lib/core/src/unix/thread.c new file mode 100644 index 0000000000..e0c1c043dd --- /dev/null +++ b/lib/core/src/unix/thread.c @@ -0,0 +1,178 @@ +#include "core.h" +#include "core_thread.h" +#include "core_errno.h" +#include "core_param.h" +#include "core_general.h" +#define TRACE_MODULE _thread +#include "core_debug.h" +#include "core_pool.h" +#include "core_semaphore.h" + +typedef struct _thread_t { + pthread_t thread; + void *data; + thread_start_t func; + + semaphore_id semaphore; +} thread_t; + +struct thread_stop_info { + pthread_t thread; + semaphore_id semaphore; +}; + +struct threadattr_t { + pthread_attr_t attr; +}; + +pool_declare(thread_pool, thread_t, MAX_NUM_OF_THREAD); +pool_declare(threadattr_pool, threadattr_t, MAX_NUM_OF_THREADATTR); + +static struct thread_stop_info thread_stop_info; + +int thread_should_stop(void) +{ + return (thread_stop_info.thread == pthread_self()); +} + +status_t thread_init(void) +{ + pool_init(&thread_pool, MAX_NUM_OF_THREAD); + pool_init(&threadattr_pool, MAX_NUM_OF_THREADATTR); + + memset(&thread_stop_info, 0, sizeof(thread_stop_info)); + + semaphore_create(&thread_stop_info.semaphore, 0); + return CORE_OK; +} + +status_t thread_final(void) +{ + pool_final(&thread_pool); + pool_final(&threadattr_pool); + + semaphore_delete(thread_stop_info.semaphore); + return CORE_OK; +} + +status_t threadattr_create(threadattr_t **new) +{ + status_t stat; + + pool_alloc_node(&threadattr_pool, &(*new)); + d_assert((*new), return CORE_ENOMEM, "threadattr_pool(%d) is not enough\n", + MAX_NUM_OF_THREADATTR); + stat = pthread_attr_init(&(*new)->attr); + + if (stat == 0) + { + return CORE_OK; + } + + return stat; +} + +status_t threadattr_stacksize_set( + threadattr_t *attr, size_t stacksize) +{ + int stat; + + stat = pthread_attr_setstacksize(&attr->attr, stacksize); + if (stat == 0) + { + return CORE_OK; + } + + return stat; +} + +status_t threadattr_delete(threadattr_t *attr) +{ + status_t stat; + + stat = pthread_attr_destroy(&attr->attr); + pool_free_node(&threadattr_pool, attr); + + if (stat == 0) + { + return CORE_OK; + } + + return stat; +} + +static void *dummy_worker(void *opaque) +{ + void *func = NULL; + thread_t *thread = (thread_t *)opaque; + + thread->thread = pthread_self(); + semaphore_post(thread->semaphore); + d_trace(3, "[%d] dummy_worker post semaphore\n", thread->thread); + + if (!thread_should_stop()) + func = thread->func(thread->data); + + d_trace(3, "[%d] thread stopped = %d\n", + thread->thread, thread_should_stop()); + semaphore_post(thread_stop_info.semaphore); + d_trace(3, "[%d] post semaphore for therad_stop_info.semaphore\n", + thread->thread); + + return func; +} + +status_t thread_create(thread_id *id, + threadattr_t *attr, thread_start_t func, void *data) +{ + status_t stat; + pthread_attr_t *temp; + thread_t *new = NULL; + + pool_alloc_node(&thread_pool, &new); + d_assert(new, return CORE_ENOMEM, "thread_pool(%d) is not enough\n", + MAX_NUM_OF_THREAD); + memset(new, 0, sizeof(thread_id)); + + new->data = data; + new->func = func; + + semaphore_create(&new->semaphore, 0); + + if (attr) + temp = &attr->attr; + else + temp = NULL; + + if ((stat = pthread_create(&new->thread, temp, dummy_worker, new)) != 0) + { + return stat; + } + + d_trace(3, "thread_create wait\n"); + semaphore_wait(new->semaphore); + d_trace(3, "thread_create done\n"); + + *id = (thread_id)new; + + return CORE_OK; +} + +status_t thread_delete(thread_id id) +{ + thread_t *thread = (thread_t *)id; + + thread_stop_info.thread = thread->thread; + d_trace(3, "thread_stop_info.thread for %d\n", thread_stop_info.thread); + semaphore_wait(thread_stop_info.semaphore); + d_trace(3, "semaphore_wait done\n"); + thread_stop_info.thread = 0; + + pthread_join(thread->thread, 0); + + semaphore_delete(thread->semaphore); + pool_free_node(&thread_pool, thread); + d_trace(3, "delete thread-related memory\n"); + + return CORE_OK; +} diff --git a/lib/core/src/unix/time.c b/lib/core/src/unix/time.c new file mode 100644 index 0000000000..e0dd4dd31b --- /dev/null +++ b/lib/core/src/unix/time.c @@ -0,0 +1,255 @@ +#include "core.h" +#include "core_time.h" + +static c_int32_t get_offset(struct tm *tm) +{ +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + return tm->tm_gmtoff; +#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) + return tm->__tm_gmtoff; +#else +#error cannot support tm->tm_gmtoff +#endif +} + +status_t time_ansi_put(c_time_t *result, time_t input) +{ + *result = (c_time_t)input * USEC_PER_SEC; + return CORE_OK; +} + +/* NB NB NB NB This returns GMT!!!!!!!!!! */ +c_time_t time_now(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * USEC_PER_SEC + tv.tv_usec; +} + +void core_sleep(c_time_t t) +{ +#ifdef OS2 + DosSleep(t/1000); +#elif defined(BEOS) + snooze(t); +#elif defined(NETWARE) + delay(t/1000); +#else + struct timeval tv; + tv.tv_usec = t % USEC_PER_SEC; + tv.tv_sec = t / USEC_PER_SEC; + select(0, NULL, NULL, NULL, &tv); +#endif +} + +static void explode_time(time_exp_t *xt, c_time_t t, + c_int32_t offset, int use_localtime) +{ + struct tm tm; + time_t tt = (t / USEC_PER_SEC) + offset; + xt->tm_usec = t % USEC_PER_SEC; + +#if defined (_POSIX_THREAD_SAFE_FUNCTIONS) + if (use_localtime) + localtime_r(&tt, &tm); + else + gmtime_r(&tt, &tm); +#else + if (use_localtime) + tm = *localtime(&tt); + else + tm = *gmtime(&tt); +#endif + + xt->tm_sec = tm.tm_sec; + xt->tm_min = tm.tm_min; + xt->tm_hour = tm.tm_hour; + xt->tm_mday = tm.tm_mday; + xt->tm_mon = tm.tm_mon; + xt->tm_year = tm.tm_year; + xt->tm_wday = tm.tm_wday; + xt->tm_yday = tm.tm_yday; + xt->tm_isdst = tm.tm_isdst; + xt->tm_gmtoff = get_offset(&tm); +} + +status_t time_exp_tz(time_exp_t *result, + c_time_t input, c_int32_t offs) +{ + explode_time(result, input, offs, 0); + result->tm_gmtoff = offs; + return CORE_OK; +} + +status_t time_exp_gmt(time_exp_t *result, c_time_t input) +{ + return time_exp_tz(result, input, 0); +} + +status_t time_exp_lt(time_exp_t *result, c_time_t input) +{ +#if defined(__EMX__) + /* EMX gcc (OS/2) has a timezone global we can use */ + return time_exp_tz(result, input, -timezone); +#else + explode_time(result, input, 0, 1); + return CORE_OK; +#endif /* __EMX__ */ +} + +status_t time_exp_get(c_time_t *t, time_exp_t *xt) +{ + time_t year = xt->tm_year; + time_t days; + static const int dayoffset[12] = + {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275}; + + /* shift new year to 1st March in order to make leap year calc easy */ + + if (xt->tm_mon < 2) + year--; + + /* Find number of days since 1st March 1900 (in the Gregorian calendar). */ + + days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4; + days += dayoffset[xt->tm_mon] + xt->tm_mday - 1; + days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */ + days = ((days * 24 + xt->tm_hour) * 60 + xt->tm_min) * 60 + xt->tm_sec; + + if (days < 0) { + return CORE_EBADDATE; + } + *t = days * USEC_PER_SEC + xt->tm_usec; + return CORE_OK; +} + +status_t time_exp_gmt_get(c_time_t *t, + time_exp_t *xt) +{ + status_t status = time_exp_get(t, xt); + if (status == CORE_OK) + *t -= (time_t) xt->tm_gmtoff * USEC_PER_SEC; + return status; +} + +const char month_snames[12][4] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; +const char day_snames[7][4] = +{ + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +status_t rfc822_date(char *date_str, c_time_t t) +{ + time_exp_t xt; + const char *s; + int real_year; + + time_exp_gmt(&xt, t); + + /* example: "Sat, 08 Jan 2000 18:31:41 GMT" */ + /* 12345678901234567890123456789 */ + + s = &day_snames[xt.tm_wday][0]; + *date_str++ = *s++; + *date_str++ = *s++; + *date_str++ = *s++; + *date_str++ = ','; + *date_str++ = ' '; + *date_str++ = xt.tm_mday / 10 + '0'; + *date_str++ = xt.tm_mday % 10 + '0'; + *date_str++ = ' '; + s = &month_snames[xt.tm_mon][0]; + *date_str++ = *s++; + *date_str++ = *s++; + *date_str++ = *s++; + *date_str++ = ' '; + real_year = 1900 + xt.tm_year; + /* This routine isn't y10k ready. */ + *date_str++ = real_year / 1000 + '0'; + *date_str++ = real_year % 1000 / 100 + '0'; + *date_str++ = real_year % 100 / 10 + '0'; + *date_str++ = real_year % 10 + '0'; + *date_str++ = ' '; + *date_str++ = xt.tm_hour / 10 + '0'; + *date_str++ = xt.tm_hour % 10 + '0'; + *date_str++ = ':'; + *date_str++ = xt.tm_min / 10 + '0'; + *date_str++ = xt.tm_min % 10 + '0'; + *date_str++ = ':'; + *date_str++ = xt.tm_sec / 10 + '0'; + *date_str++ = xt.tm_sec % 10 + '0'; + *date_str++ = ' '; + *date_str++ = 'G'; + *date_str++ = 'M'; + *date_str++ = 'T'; + *date_str++ = 0; + return CORE_OK; +} + +status_t core_ctime(char *date_str, c_time_t t) +{ + time_exp_t xt; + const char *s; + int real_year; + + /* example: "Wed Jun 30 21:49:08 1993" */ + /* 123456789012345678901234 */ + + time_exp_lt(&xt, t); + s = &day_snames[xt.tm_wday][0]; + *date_str++ = *s++; + *date_str++ = *s++; + *date_str++ = *s++; + *date_str++ = ' '; + s = &month_snames[xt.tm_mon][0]; + *date_str++ = *s++; + *date_str++ = *s++; + *date_str++ = *s++; + *date_str++ = ' '; + *date_str++ = xt.tm_mday / 10 + '0'; + *date_str++ = xt.tm_mday % 10 + '0'; + *date_str++ = ' '; + *date_str++ = xt.tm_hour / 10 + '0'; + *date_str++ = xt.tm_hour % 10 + '0'; + *date_str++ = ':'; + *date_str++ = xt.tm_min / 10 + '0'; + *date_str++ = xt.tm_min % 10 + '0'; + *date_str++ = ':'; + *date_str++ = xt.tm_sec / 10 + '0'; + *date_str++ = xt.tm_sec % 10 + '0'; + *date_str++ = ' '; + real_year = 1900 + xt.tm_year; + *date_str++ = real_year / 1000 + '0'; + *date_str++ = real_year % 1000 / 100 + '0'; + *date_str++ = real_year % 100 / 10 + '0'; + *date_str++ = real_year % 10 + '0'; + *date_str++ = 0; + + return CORE_OK; +} + +status_t core_strftime(char *s, size_t *retsize, size_t max, + const char *format, time_exp_t *xt) +{ + struct tm tm; + memset(&tm, 0, sizeof tm); + tm.tm_sec = xt->tm_sec; + tm.tm_min = xt->tm_min; + tm.tm_hour = xt->tm_hour; + tm.tm_mday = xt->tm_mday; + tm.tm_mon = xt->tm_mon; + tm.tm_year = xt->tm_year; + tm.tm_wday = xt->tm_wday; + tm.tm_yday = xt->tm_yday; + tm.tm_isdst = xt->tm_isdst; +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + tm.tm_gmtoff = xt->tm_gmtoff; +#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) + tm.__tm_gmtoff = xt->tm_gmtoff; +#endif + (*retsize) = strftime(s, max, format, &tm); + return CORE_OK; +} diff --git a/lib/core/src/version.c b/lib/core/src/version.c new file mode 100644 index 0000000000..582d139e22 --- /dev/null +++ b/lib/core/src/version.c @@ -0,0 +1,19 @@ +#include "core_version.h" +#include "core_general.h" /* for CORE_STRINGIFY */ + +CORE_DECLARE(void) core_version(core_version_t *pvsn) +{ + pvsn->major = CORE_MAJOR_VERSION; + pvsn->minor = CORE_MINOR_VERSION; + pvsn->patch = CORE_PATCH_VERSION; +#ifdef CORE_IS_DEV_VERSION + pvsn->is_dev = 1; +#else + pvsn->is_dev = 0; +#endif +} + +CORE_DECLARE(const char *) core_version_string(void) +{ + return CORE_VERSION_STRING; +} diff --git a/lib/core/test/Makefile.am b/lib/core/test/Makefile.am new file mode 100644 index 0000000000..2c92a31ca2 --- /dev/null +++ b/lib/core/test/Makefile.am @@ -0,0 +1,27 @@ +## Process this file with automake to produce Makefile.in. + +bin_PROGRAMS = testcore + +nodist_testcore_SOURCES = \ + abts.c testds.c testfsm.c testnetlib.c testthread.c testtlv.c \ + testaes.c testfile.c testlock.c testsha.c testtime.c testutil.c \ + testdir.c testfilecopy.c testmsgq.c testsleep.c testtimer.c \ + abts.h abts_tests.h testutil.h + +testcore_LDADD = \ + $(top_srcdir)/lib/core/src/libcore.la \ + -lpthread -lsctp + +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib/core/include/arch/@OSDIR@ \ + -I$(top_srcdir)/lib/core/include + +AM_CFLAGS = \ + -Wall -Werror @OSCFLAGS@ \ + -Wno-unused-function + +TESTS = testcore + +MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = -R data +MOSTLYCLEANFILES = core *.stackdump diff --git a/lib/core/test/abts.c b/lib/core/test/abts.c new file mode 100644 index 0000000000..f2d01bb983 --- /dev/null +++ b/lib/core/test/abts.c @@ -0,0 +1,458 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "abts.h" +#include "abts_tests.h" +#include "testutil.h" + +#define ABTS_STAT_SIZE 6 +static char status[ABTS_STAT_SIZE] = {'|', '/', '-', '|', '\\', '-'}; +static int curr_char; +static int verbose = 1; +static int exclude = 0; +static int quiet = 0; +static int list_tests = 0; + +const char **testlist = NULL; + +static int find_test_name(const char *testname) { + int i; + for (i = 0; testlist[i] != NULL; i++) { + if (!strcmp(testlist[i], testname)) { + return 1; + } + } + return 0; +} + +/* Determine if the test should be run at all */ +static int should_test_run(const char *testname) { + int found = 0; + if (list_tests == 1) { + return 0; + } + if (testlist == NULL) { + return 1; + } + found = find_test_name(testname); + if ((found && !exclude) || (!found && exclude)) { + return 1; + } + return 0; +} + +static void reset_status(void) +{ + curr_char = 0; +} + +static void update_status(void) +{ + if (!quiet) { + curr_char = (curr_char + 1) % ABTS_STAT_SIZE; + fprintf(stdout, "\b%c", status[curr_char]); + fflush(stdout); + } +} + +static void end_suite(abts_suite *suite) +{ + if (suite != NULL) { + sub_suite *last = suite->tail; + if (!quiet) { + fprintf(stdout, "\b"); + fflush(stdout); + } + if (last->failed == 0) { + fprintf(stdout, "SUCCESS\n"); + fflush(stdout); + } + else { + fprintf(stdout, "FAILED %d of %d\n", last->failed, last->num_test); + fflush(stdout); + } + } +} + +abts_suite *abts_add_suite(abts_suite *suite, const char *suite_name_full) +{ + sub_suite *subsuite; + char *p; + const char *suite_name; + curr_char = 0; + + /* Only end the suite if we actually ran it */ + if (suite && suite->tail &&!suite->tail->not_run) { + end_suite(suite); + } + + subsuite = malloc(sizeof(*subsuite)); + subsuite->num_test = 0; + subsuite->failed = 0; + subsuite->next = NULL; + /* suite_name_full may be an absolute path depending on __FILE__ + * expansion */ + suite_name = strrchr(suite_name_full, '/'); + if (suite_name) { + suite_name++; + } else { + suite_name = suite_name_full; + } + p = strrchr(suite_name, '.'); + if (p) { + subsuite->name = memcpy(calloc(p - suite_name + 1, 1), + suite_name, p - suite_name); + } + else { + subsuite->name = suite_name; + } + + if (list_tests) { + fprintf(stdout, "%s\n", subsuite->name); + } + + subsuite->not_run = 0; + + if (suite == NULL) { + suite = malloc(sizeof(*suite)); + suite->head = subsuite; + suite->tail = subsuite; + } + else { + suite->tail->next = subsuite; + suite->tail = subsuite; + } + + if (!should_test_run(subsuite->name)) { + subsuite->not_run = 1; + return suite; + } + + reset_status(); + fprintf(stdout, "%-20s: ", subsuite->name); + update_status(); + fflush(stdout); + + return suite; +} + +void abts_run_test(abts_suite *ts, test_func f, void *value) +{ + abts_case tc; + sub_suite *ss; + + if (!should_test_run(ts->tail->name)) { + return; + } + ss = ts->tail; + + tc.failed = 0; + tc.suite = ss; + + ss->num_test++; + update_status(); + + f(&tc, value); + + if (tc.failed) { + ss->failed++; + } +} + +static int report(abts_suite *suite) +{ + int count = 0; + sub_suite *dptr; + + if (suite && suite->tail &&!suite->tail->not_run) { + end_suite(suite); + } + + for (dptr = suite->head; dptr; dptr = dptr->next) { + count += dptr->failed; + } + + if (list_tests) { + return 0; + } + + if (count == 0) { + printf("All tests passed.\n"); + return 0; + } + + dptr = suite->head; + fprintf(stdout, "%-15s\t\tTotal\tFail\tFailed %%\n", "Failed Tests"); + fprintf(stdout, "===================================================\n"); + while (dptr != NULL) { + if (dptr->failed != 0) { + float percent = ((float)dptr->failed / (float)dptr->num_test); + fprintf(stdout, "%-15s\t\t%5d\t%4d\t%6.2f%%\n", dptr->name, + dptr->num_test, dptr->failed, percent * 100); + } + dptr = dptr->next; + } + return 1; +} + +void abts_log_message(const char *fmt, ...) +{ + va_list args; + update_status(); + + if (verbose) { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + fflush(stderr); + } +} + +void abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected == actual) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected != actual) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_size_equal(abts_case *tc, size_t expected, size_t actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected == actual) return; + + tc->failed = TRUE; + if (verbose) { + /* Note that the comparison is type-exact, reporting must be a best-fit */ + fprintf(stderr, "Line %d: expected %lu, but saw %lu\n", lineno, + (unsigned long)expected, (unsigned long)actual); + fflush(stderr); + } +} + +void abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (!expected && !actual) return; + if (expected && actual) + if (!strcmp(expected, actual)) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_str_nequal(abts_case *tc, const char *expected, const char *actual, + size_t n, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (!strncmp(expected, actual, n)) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_ptr_null(abts_case *tc, const void *ptr, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (ptr == NULL) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: Expected NULL, but saw <%p>\n", lineno, ptr); + fflush(stderr); + } +} + +void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (ptr != NULL) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: Expected not NULL, but saw <%p>\n", lineno, ptr); + fflush(stderr); + } +} + +void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected == actual) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%p>, but saw <%p>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_fail(abts_case *tc, const char *message, int lineno) +{ + update_status(); + if (tc->failed) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: %s\n", lineno, message); + fflush(stderr); + } +} + +void abts_assert(abts_case *tc, const char *message, int condition, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (condition) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: %s\n", lineno, message); + fflush(stderr); + } +} + +void abts_true(abts_case *tc, int condition, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (condition) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: Condition is false, but expected true\n", lineno); + fflush(stderr); + } +} + +void abts_false(abts_case *tc, int condition, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (!condition) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: Condition is true, but expected false\n", lineno); + fflush(stderr); + } +} + +void abts_not_impl(abts_case *tc, const char *message, int lineno) +{ + update_status(); + + tc->suite->not_impl++; + if (verbose) { + fprintf(stderr, "Line %d: %s\n", lineno, message); + fflush(stderr); + } +} + +int main(int argc, const char *const argv[]) { + int i; + int rv; + int list_provided = 0; + abts_suite *suite = NULL; + + test_initialize(); + + quiet = !isatty(STDOUT_FILENO); + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-v")) { + verbose = 1; + continue; + } + if (!strcmp(argv[i], "-x")) { + exclude = 1; + continue; + } + if (!strcmp(argv[i], "-l")) { + list_tests = 1; + continue; + } + if (!strcmp(argv[i], "-q")) { + quiet = 1; + continue; + } + if (argv[i][0] == '-') { + fprintf(stderr, "Invalid option: `%s'\n", argv[i]); + exit(1); + } + list_provided = 1; + } + + if (list_provided) { + /* Waste a little space here, because it is easier than counting the + * number of tests listed. Besides it is at most three char *. + */ + testlist = calloc(argc + 1, sizeof(char *)); + for (i = 1; i < argc; i++) { + testlist[i - 1] = argv[i]; + } + } + + for (i = 0; i < (sizeof(alltests) / sizeof(struct testlist *)); i++) { + suite = alltests[i].func(suite); + } + + rv = report(suite); + return rv; +} + diff --git a/lib/core/test/abts.h b/lib/core/test/abts.h new file mode 100644 index 0000000000..211805077f --- /dev/null +++ b/lib/core/test/abts.h @@ -0,0 +1,112 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif + +#ifndef ABTS_H +#define ABTS_H + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +struct sub_suite { + const char *name; + int num_test; + int failed; + int not_run; + int not_impl; + struct sub_suite *next; +}; +typedef struct sub_suite sub_suite; + +struct abts_suite { + sub_suite *head; + sub_suite *tail; +}; +typedef struct abts_suite abts_suite; + +struct abts_case { + int failed; + sub_suite *suite; +}; +typedef struct abts_case abts_case; + +typedef void (*test_func)(abts_case *tc, void *data); + +#define ADD_SUITE(suite) abts_add_suite(suite, __FILE__); + +abts_suite *abts_add_suite(abts_suite *suite, const char *suite_name); +void abts_run_test(abts_suite *ts, test_func f, void *value); +void abts_log_message(const char *fmt, ...); + +void abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno); +void abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno); +void abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno); +void abts_str_nequal(abts_case *tc, const char *expected, const char *actual, + size_t n, int lineno); +void abts_ptr_null(abts_case *tc, const void *ptr, int lineno); +void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno); +void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno); +void abts_true(abts_case *tc, int condition, int lineno); +void abts_false(abts_case *tc, int condition, int lineno); +void abts_fail(abts_case *tc, const char *message, int lineno); +void abts_not_impl(abts_case *tc, const char *message, int lineno); +void abts_assert(abts_case *tc, const char *message, int condition, int lineno); +void abts_size_equal(abts_case *tc, size_t expected, size_t actual, int lineno); + +/* Convenience macros. Ryan hates these! */ +#define ABTS_INT_EQUAL(a, b, c) abts_int_equal(a, b, c, __LINE__) +#define ABTS_INT_NEQUAL(a, b, c) abts_int_nequal(a, b, c, __LINE__) +#define ABTS_STR_EQUAL(a, b, c) abts_str_equal(a, b, c, __LINE__) +#define ABTS_STR_NEQUAL(a, b, c, d) abts_str_nequal(a, b, c, d, __LINE__) +#define ABTS_PTR_NULL(a, b) abts_ptr_null(a, b, __LINE__) +#define ABTS_PTR_NOTNULL(a, b) abts_ptr_notnull(a, b, __LINE__) +#define ABTS_PTR_EQUAL(a, b, c) abts_ptr_equal(a, b, c, __LINE__) +#define ABTS_TRUE(a, b) abts_true(a, b, __LINE__); +#define ABTS_FALSE(a, b) abts_false(a, b, __LINE__); +#define ABTS_FAIL(a, b) abts_fail(a, b, __LINE__); +#define ABTS_NOT_IMPL(a, b) abts_not_impl(a, b, __LINE__); +#define ABTS_ASSERT(a, b, c) abts_assert(a, b, c, __LINE__); + +#define ABTS_SIZE_EQUAL(a, b, c) abts_size_equal(a, b, c, __LINE__) + + +abts_suite *run_tests(abts_suite *suite); +abts_suite *run_tests1(abts_suite *suite); + + +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/lib/core/test/abts_tests.h b/lib/core/test/abts_tests.h new file mode 100644 index 0000000000..9c074c46ef --- /dev/null +++ b/lib/core/test/abts_tests.h @@ -0,0 +1,43 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef APR_TEST_INCLUDES +#define APR_TEST_INCLUDES + +#include "abts.h" +#include "testutil.h" + +const struct testlist { + abts_suite *(*func)(abts_suite *suite); +} alltests[] = { + {testds}, + {testfsm}, + {testtlv}, + {testaes}, + {testsha2}, + {testnetlib}, + {testtime}, + {testtimer}, + {testthread}, + {testlock}, + {testfile}, + {testfilecopy}, + {testdir}, + {testmsgq}, + {testsleep}, +}; + +#endif /* APR_TEST_INCLUDES */ diff --git a/lib/core/test/testaes.c b/lib/core/test/testaes.c new file mode 100644 index 0000000000..ff6ea62303 --- /dev/null +++ b/lib/core/test/testaes.c @@ -0,0 +1,391 @@ +#include "core_aes.h" +#include "core_aes_cmac.h" +#include "testutil.h" + +typedef struct { + unsigned char *key; + unsigned int *rk; + int key_bits; + unsigned char input[16]; + unsigned char cipher_output[16]; + unsigned char decipher_output[16]; +} aes_test_vector_t; + +static void aes_test1(abts_case *tc, void *data) +{ + const int key_bits = 128; + unsigned int rk[RKLENGTH(128)]; + unsigned char key[16] = + "\x00\x01\x02\x03\x05\x06\x07\x08\x0A\x0B\x0C\x0D\x0F\x10\x11\x12"; + unsigned char pt[16] = "\x50\x68\x12\xA4\x5F\x08\xC8\x89\xB9\x7F\x59\x80\x03\x8B\x83\x59"; + unsigned char ct[16]; + unsigned char expected[16] = + "\xD8\xF5\x32\x53\x82\x89\xEF\x7D\x06\xB5\x06\xA4\xFD\x5B\xE9\xC9"; + int nrounds; + int rc; + + nrounds = aes_setup_enc(rk, key, key_bits); + aes_encrypt(rk ,nrounds, pt, ct); + + rc = memcmp(ct, expected, 16); + + ABTS_INT_EQUAL(tc, 0, rc); +} + +static void aes_test2(abts_case *tc, void *data) +{ + unsigned char tmp[16]; + int nrounds; + int rc; + aes_test_vector_t test_vector[3]; + int i; + + + test_vector[0].key_bits = 128; + test_vector[0].key = + malloc(sizeof(char)*KEYLENGTH(test_vector[0].key_bits)); + test_vector[0].rk = + malloc(sizeof(unsigned int)*RKLENGTH(test_vector[0].key_bits)); + memcpy(test_vector[0].key, + "\x95\xA8\xEE\x8E\x89\x97\x9B\x9E" + "\xFD\xCB\xC6\xEB\x97\x97\x52\x8D", + KEYLENGTH(test_vector[0].key_bits)); + memcpy(test_vector[0].input, + "\x4E\xC1\x37\xA4\x26\xDA\xBF\x8A" + "\xA0\xBE\xB8\xBC\x0C\x2B\x89\xD6", + 16); + memcpy(test_vector[0].cipher_output, + "\xD9\xB6\x5D\x12\x32\xBA\x01\x99" + "\xCD\xBD\x48\x7B\x2A\x1F\xD6\x46", + 16); + memcpy(test_vector[0].decipher_output, + "\x95\x70\xC3\x43\x63\x56\x5B\x39" + "\x35\x03\xA0\x01\xC0\xE2\x3B\x65", + 16); + + test_vector[1].key_bits = 192; + test_vector[1].key = + malloc(sizeof(char)*KEYLENGTH(test_vector[1].key_bits)); + test_vector[1].rk = + malloc(sizeof(unsigned int)*RKLENGTH(test_vector[1].key_bits)); + memcpy(test_vector[1].key, + "\x95\xA8\xEE\x8E\x89\x97\x9B\x9E" + "\xFD\xCB\xC6\xEB\x97\x97\x52\x8D" + "\x43\x2D\xC2\x60\x61\x55\x38\x18", + KEYLENGTH(test_vector[1].key_bits)); + memcpy(test_vector[1].input , + "\x4E\xC1\x37\xA4\x26\xDA\xBF\x8A" + "\xA0\xBE\xB8\xBC\x0C\x2B\x89\xD6", + 16); + memcpy(test_vector[1].cipher_output, + "\xB1\x8B\xB3\xE7\xE1\x07\x32\xBE" + "\x13\x58\x44\x3A\x50\x4D\xBB\x49", + 16); + memcpy(test_vector[1].decipher_output, + "\x29\xDF\xD7\x5B\x85\xCE\xE4\xDE" + "\x6E\x26\xA8\x08\xCD\xC2\xC9\xC3", + 16); + + test_vector[2].key_bits = 256; + test_vector[2].key = + malloc(sizeof(char)*KEYLENGTH(test_vector[2].key_bits)); + test_vector[2].rk = + malloc(sizeof(unsigned int)*RKLENGTH(test_vector[2].key_bits)); + memcpy(test_vector[2].key, + "\x95\xA8\xEE\x8E\x89\x97\x9B\x9E" + "\xFD\xCB\xC6\xEB\x97\x97\x52\x8D" + "\x43\x2D\xC2\x60\x61\x55\x38\x18" + "\xEA\x63\x5E\xC5\xD5\xA7\x72\x7E", + KEYLENGTH(test_vector[2].key_bits)); + memcpy(test_vector[2].input , + "\x4E\xC1\x37\xA4\x26\xDA\xBF\x8A" + "\xA0\xBE\xB8\xBC\x0C\x2B\x89\xD6", + 16); + memcpy(test_vector[2].cipher_output, + "\x2F\x9C\xFD\xDB\xFF\xCD\xE6\xB9" + "\xF3\x7E\xF8\xE4\x0D\x51\x2C\xF4", + 16); + memcpy(test_vector[2].decipher_output, + "\x11\x0A\x35\x45\xCE\x49\xB8\x4B" + "\xBB\x7B\x35\x23\x61\x08\xFA\x6E", + 16); + + for (i=0; i<3; i++) + { + nrounds = aes_setup_enc(test_vector[i].rk, test_vector[i].key, + test_vector[i].key_bits); + aes_encrypt(test_vector[i].rk ,nrounds, test_vector[i].input, tmp); + + rc = memcmp(tmp, test_vector[i].cipher_output, 16); + ABTS_INT_EQUAL(tc, 0, rc); + + nrounds = aes_setup_dec(test_vector[i].rk, test_vector[i].key, + test_vector[i].key_bits); + aes_decrypt(test_vector[i].rk ,nrounds, test_vector[i].input, tmp); + rc = memcmp(tmp, test_vector[i].decipher_output, 16); + ABTS_INT_EQUAL(tc, 0, rc); + + free(test_vector[i].key); + free(test_vector[i].rk); + } +} + +#if 0 + Case #1: Encrypting 16 bytes (1 block) using AES-CBC with 128-bit key + Key : 0x06a9214036b8a15b512e03d534120006 + IV : 0x3dafba429d9eb430b422da802c9fac41 + Plaintext : "Single block msg" + Ciphertext: 0xe353779c1079aeb82708942dbe77181a + + Case #2: Encrypting 32 bytes (2 blocks) using AES-CBC with 128-bit key + Key : 0xc286696d887c9aa0611bbb3e2025a45a + IV : 0x562e17996d093d28ddb3ba695a2e6f58 + Plaintext : 0x000102030405060708090a0b0c0d0e0f + 101112131415161718191a1b1c1d1e1f + Ciphertext: 0xd296cd94c2cccf8a3a863028b5e1dc0a + 7586602d253cfff91b8266bea6d61ab1 + + Case #3: Encrypting 48 bytes (3 blocks) using AES-CBC with 128-bit key + Key : 0x6c3ea0477630ce21a2ce334aa746c2cd + IV : 0xc782dc4c098c66cbd9cd27d825682c81 + Plaintext : "This is a 48-byte message (exactly 3 AES blocks)" + Ciphertext: 0xd0a02b3836451753d493665d33f0e886 + 2dea54cdb293abc7506939276772f8d5 + 021c19216bad525c8579695d83ba2684 + + Case #4: Encrypting 64 bytes (4 blocks) using AES-CBC with 128-bit key + Key : 0x56e47a38c5598974bc46903dba290349 + IV : 0x8ce82eefbea0da3c44699ed7db51b7d9 + Plaintext : 0xa0a1a2a3a4a5a6a7a8a9aaabacadaeaf + b0b1b2b3b4b5b6b7b8b9babbbcbdbebf + c0c1c2c3c4c5c6c7c8c9cacbcccdcecf + d0d1d2d3d4d5d6d7d8d9dadbdcdddedf + Ciphertext: 0xc30e32ffedc0774e6aff6af0869f71aa + 0f3af07a9a31a9c684db207eb0ef8e4e + 35907aa632c3ffdf868bb7b29d3d46ad + 83ce9f9a102ee99d49a53e87f4c3da55 +#endif + +typedef struct { + unsigned char key[33]; + int key_bits; + unsigned char ivec[33]; + unsigned char plain[65]; + unsigned int plainlen; + unsigned char cipher[65]; + unsigned int cipherlen; +} aes_cbc_test_vector_t; + +static void aes_test3(abts_case *tc, void *data) +{ + aes_cbc_test_vector_t tv[5] = { + { + "\x06\xa9\x21\x40\x36\xb8\xa1\x5b\x51\x2e\x03\xd5\x34\x12\x00\x06", + 128, + "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30\xb4\x22\xda\x80\x2c\x9f\xac\x41", + "Single block msg", + 16, + "\xe3\x53\x77\x9c\x10\x79\xae\xb8\x27\x08\x94\x2d\xbe\x77\x18\x1a", + 16 + }, { + "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0\x61\x1b\xbb\x3e\x20\x25\xa4\x5a", + 128, + "\x56\x2e\x17\x99\x6d\x09\x3d\x28\xdd\xb3\xba\x69\x5a\x2e\x6f\x58", + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + 32, + "\xd2\x96\xcd\x94\xc2\xcc\xcf\x8a\x3a\x86\x30\x28\xb5\xe1\xdc\x0a" + "\x75\x86\x60\x2d\x25\x3c\xff\xf9\x1b\x82\x66\xbe\xa6\xd6\x1a\xb1", + 32 + }, { + + "\x6c\x3e\xa0\x47\x76\x30\xce\x21\xa2\xce\x33\x4a\xa7\x46\xc2\xcd", + 128, + "\xc7\x82\xdc\x4c\x09\x8c\x66\xcb\xd9\xcd\x27\xd8\x25\x68\x2c\x81", + "This is a 48-byte message (exactly 3 AES blocks)", + 48, + "\xd0\xa0\x2b\x38\x36\x45\x17\x53\xd4\x93\x66\x5d\x33\xf0\xe8\x86" + "\x2d\xea\x54\xcd\xb2\x93\xab\xc7\x50\x69\x39\x27\x67\x72\xf8\xd5" + "\x02\x1c\x19\x21\x6b\xad\x52\x5c\x85\x79\x69\x5d\x83\xba\x26\x84", + 48 + }, { + "\x56\xe4\x7a\x38\xc5\x59\x89\x74\xbc\x46\x90\x3d\xba\x29\x03\x49", + 128, + "\x8c\xe8\x2e\xef\xbe\xa0\xda\x3c\x44\x69\x9e\xd7\xdb\x51\xb7\xd9", + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf", + 64, + "\xc3\x0e\x32\xff\xed\xc0\x77\x4e\x6a\xff\x6a\xf0\x86\x9f\x71\xaa" + "\x0f\x3a\xf0\x7a\x9a\x31\xa9\xc6\x84\xdb\x20\x7e\xb0\xef\x8e\x4e" + "\x35\x90\x7a\xa6\x32\xc3\xff\xdf\x86\x8b\xb7\xb2\x9d\x3d\x46\xad" + "\x83\xce\x9f\x9a\x10\x2e\xe9\x9d\x49\xa5\x3e\x87\xf4\xc3\xda\x55", + 64 + }, { + "\x56\xe4\x7a\x38\xc5\x59\x89\x74\xbc\x46\x90\x3d\xba\x29\x03\x49", + 128, + "\x8c\xe8\x2e\xef\xbe\xa0\xda\x3c\x44\x69\x9e\xd7\xdb\x51\xb7\xd9", + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd", + 62, + "\xc3\x0e\x32\xff\xed\xc0\x77\x4e\x6a\xff\x6a\xf0\x86\x9f\x71\xaa" + "\x0f\x3a\xf0\x7a\x9a\x31\xa9\xc6\x84\xdb\x20\x7e\xb0\xef\x8e\x4e" + "\x35\x90\x7a\xa6\x32\xc3\xff\xdf\x86\x8b\xb7\xb2\x9d\x3d\x46\xad" + "\x5d\x96\x74\x07\xe9\x86\x0c\x0b\x50\x80\x4a\xfb\x69\xc1\x13\xaa", + 64 + } + }; + + unsigned char out[128]; + unsigned int i, rc, outlen; + c_uint8_t ivec[32]; + + for (i = 0; i < 5; i++) + { + outlen = sizeof(out); + memcpy(ivec, tv[i].ivec, 16); + aes_cbc_encrypt(tv[i].key, tv[i].key_bits, ivec, + tv[i].plain, tv[i].plainlen, out, &outlen); + ABTS_INT_EQUAL(tc, tv[i].cipherlen, outlen); + rc = memcmp(tv[i].cipher, out, tv[i].cipherlen); + ABTS_INT_EQUAL(tc, 0, rc); + + outlen = sizeof(out); + memcpy(ivec, tv[i].ivec, 16); + aes_cbc_decrypt(tv[i].key, tv[i].key_bits, ivec, + tv[i].cipher, tv[i].cipherlen, out, &outlen); + ABTS_INT_EQUAL(tc, tv[i].cipherlen, outlen); + rc = memcmp(tv[i].plain, out, tv[i].plainlen); + ABTS_INT_EQUAL(tc, 0, rc); + } +} + +/* RFC 4493 + + -------------------------------------------------- + Subkey Generation + K 2b7e1516 28aed2a6 abf71588 09cf4f3c + AES-128(key,0) 7df76b0c 1ab899b3 3e42f047 b91b546f + K1 fbeed618 35713366 7c85e08f 7236a8de + K2 f7ddac30 6ae266cc f90bc11e e46d513b + -------------------------------------------------- + + -------------------------------------------------- + Example 1: len = 0 + M + AES-CMAC bb1d6929 e9593728 7fa37d12 9b756746 + -------------------------------------------------- + + Example 2: len = 16 + M 6bc1bee2 2e409f96 e93d7e11 7393172a + AES-CMAC 070a16b4 6b4d4144 f79bdd9d d04a287c + -------------------------------------------------- + + Example 3: len = 40 + M 6bc1bee2 2e409f96 e93d7e11 7393172a + ae2d8a57 1e03ac9c 9eb76fac 45af8e51 + 30c81c46 a35ce411 + AES-CMAC dfa66747 de9ae630 30ca3261 1497c827 + -------------------------------------------------- + + Example 4: len = 64 + M 6bc1bee2 2e409f96 e93d7e11 7393172a + ae2d8a57 1e03ac9c 9eb76fac 45af8e51 + 30c81c46 a35ce411 e5fbc119 1a0a52ef + f69f2445 df4f9b17 ad2b417b e66c3710 + AES-CMAC 51f0bebf 7e3b9d92 fc497417 79363cfe + -------------------------------------------------- +*/ + +static void cmac_test(abts_case *tc, void *data) +{ + c_uint8_t key[16] = { + 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c + }; + + c_uint8_t msg[4][64] = { + { + /* Empty string */ + }, + { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96, + 0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a + }, { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96, + 0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c, + 0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11 + }, { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96, + 0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c, + 0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11, + 0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef, + 0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17, + 0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10 + } + }; + + c_uint32_t msglen[4] = {0, 16, 40, 64}; + + c_uint8_t cmac_answer[4][16] = { + { + 0xbb,0x1d,0x69,0x29,0xe9,0x59,0x37,0x28, + 0x7f,0xa3,0x7d,0x12,0x9b,0x75,0x67,0x46 + }, { + 0x07,0x0a,0x16,0xb4,0x6b,0x4d,0x41,0x44, + 0xf7,0x9b,0xdd,0x9d,0xd0,0x4a,0x28,0x7c + }, { + 0xdf,0xa6,0x67,0x47,0xde,0x9a,0xe6,0x30, + 0x30,0xca,0x32,0x61,0x14,0x97,0xc8,0x27 + }, { + 0x51,0xf0,0xbe,0xbf,0x7e,0x3b,0x9d,0x92, + 0xfc,0x49,0x74,0x17,0x79,0x36,0x3c,0xfe + } + }; + + c_uint8_t cmac[16]; + + int i, rc; + status_t rv; + + for (i = 0; i < 4; i++) + { + rv = aes_cmac_calculate(cmac, key, msg[i], msglen[i]); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rc = memcmp(cmac, cmac_answer[i], 16); + ABTS_INT_EQUAL(tc, 0, rc); + } + + for (i = 0; i < 4; i++) + { + rv = aes_cmac_verify(cmac_answer[i], key, msg[i], msglen[i]); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + } + + key[0] = 0; + for (i = 0; i < 4; i++) + { + rv = aes_cmac_verify(cmac_answer[i], key, msg[i], msglen[i]); + ABTS_INT_EQUAL(tc, ERR_INVALID_CMAC, rv); + } +} + +abts_suite *testaes(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, aes_test1, NULL); + abts_run_test(suite, aes_test2, NULL); + abts_run_test(suite, aes_test3, NULL); + abts_run_test(suite, cmac_test, NULL); + + return suite; +} diff --git a/lib/core/test/testdir.c b/lib/core/test/testdir.c new file mode 100644 index 0000000000..72206d5d56 --- /dev/null +++ b/lib/core/test/testdir.c @@ -0,0 +1,124 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core_file.h" +#include "testutil.h" + +static void test_mkdir(abts_case *tc, void *data) +{ + status_t rv; + file_info_t finfo; + + rv = dir_make("data/testdir", FILE_UREAD | FILE_UWRITE | FILE_UEXECUTE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_stat(&finfo, "data/testdir", FILE_INFO_TYPE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_INT_EQUAL(tc, FILE_DIR, finfo.filetype); +} + +static void test_mkdir_recurs(abts_case *tc, void *data) +{ + status_t rv; + file_info_t finfo; + + rv = dir_make_recursive("data/one/two/three", + FILE_UREAD | FILE_UWRITE | FILE_UEXECUTE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_stat(&finfo, "data/one", FILE_INFO_TYPE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_INT_EQUAL(tc, FILE_DIR, finfo.filetype); + + rv = file_stat(&finfo, "data/one/two", FILE_INFO_TYPE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_INT_EQUAL(tc, FILE_DIR, finfo.filetype); + + rv = file_stat(&finfo, "data/one/two/three", FILE_INFO_TYPE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_INT_EQUAL(tc, FILE_DIR, finfo.filetype); +} + +static void test_remove(abts_case *tc, void *data) +{ + status_t rv; + file_info_t finfo; + + rv = dir_remove("data/testdir"); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_stat(&finfo, "data/testdir", FILE_INFO_TYPE); + ABTS_INT_EQUAL(tc, 1, STATUS_IS_ENOENT(rv)); +} + +static void test_removeall_fail(abts_case *tc, void *data) +{ + status_t rv; + + rv = dir_remove("data/one"); + ABTS_INT_EQUAL(tc, 1, STATUS_IS_ENOTEMPTY(rv)); +} + +static void test_removeall(abts_case *tc, void *data) +{ + status_t rv; + + rv = dir_remove("data/one/two/three"); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = dir_remove("data/one/two"); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = dir_remove("data/one"); + ABTS_INT_EQUAL(tc, CORE_OK, rv); +} + +static void test_remove_notthere(abts_case *tc, void *data) +{ + status_t rv; + + rv = dir_remove("data/notthere"); + ABTS_INT_EQUAL(tc, 1, STATUS_IS_ENOENT(rv)); +} + +static void test_mkdir_twice(abts_case *tc, void *data) +{ + status_t rv; + + rv = dir_make("data/testdir", FILE_UREAD | FILE_UWRITE | FILE_UEXECUTE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = dir_make("data/testdir", FILE_UREAD | FILE_UWRITE | FILE_UEXECUTE); + ABTS_INT_EQUAL(tc, 1, STATUS_IS_EEXIST(rv)); + + rv = dir_remove("data/testdir"); + ABTS_INT_EQUAL(tc, CORE_OK, rv); +} + +abts_suite *testdir(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_mkdir, NULL); + abts_run_test(suite, test_mkdir_recurs, NULL); + abts_run_test(suite, test_remove, NULL); + abts_run_test(suite, test_removeall_fail, NULL); + abts_run_test(suite, test_removeall, NULL); + abts_run_test(suite, test_remove_notthere, NULL); + abts_run_test(suite, test_mkdir_twice, NULL); + + return suite; +} diff --git a/lib/core/test/testds.c b/lib/core/test/testds.c new file mode 100644 index 0000000000..b52ff453d3 --- /dev/null +++ b/lib/core/test/testds.c @@ -0,0 +1,814 @@ +#include "core_pool.h" +#include "core_list.h" +#include "core_queue.h" +#include "core_ringbuf.h" +#include "testutil.h" + + +/***************************************************************************** + * test for core_pool.h + */ +typedef struct { + char m1; + int m2; +} pt_type1; + +#define SIZE_OF_TPOOL1 5 +#define SIZE_OF_TPOOL2 5 + +typedef char type_of_tpool1; +typedef pt_type1 type_of_tpool2; + +pool_declare(tpool1, type_of_tpool1, SIZE_OF_TPOOL1); +pool_declare(tpool2, type_of_tpool2, SIZE_OF_TPOOL2); + +static void pool_test_core1(abts_case *tc, void *data, int start) +{ + int i, j, n; + + type_of_tpool1 *org[SIZE_OF_TPOOL1+1]; + type_of_tpool1 *node[SIZE_OF_TPOOL1+1]; + + pool_init(&tpool1, SIZE_OF_TPOOL1); + + /* Check basic members */ + n = pool_size(&tpool1); + ABTS_INT_EQUAL(tc, SIZE_OF_TPOOL1, n); + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, SIZE_OF_TPOOL1, n); + n = pool_used(&tpool1); + ABTS_INT_EQUAL(tc, 0, n); + + /* Allocation up to start index */ + for (i = 0; i < start; i++) + { + pool_alloc_node(&tpool1, &node[i]); + /* Check not null */ + ABTS_PTR_NOTNULL(tc, node[i]); + /* Check the number of available nodes */ + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, SIZE_OF_TPOOL1 - (i + 1), n); + } + + /* Free all allocated nodes */ + for (i = 0; i < start; i++) + { + pool_free_node(&tpool1, node[i]); + /* Check the number of available nodes */ + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, SIZE_OF_TPOOL1 - start + (i + 1), n); + } + + /* Allocation up to maximum pool size */ + for (i = 0; i < SIZE_OF_TPOOL1; i++) + { + pool_alloc_node(&tpool1, &node[i]); + org[i] = node[i]; + /* Check not null */ + ABTS_PTR_NOTNULL(tc, node[i]); + /* Check the number of available nodes */ + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, SIZE_OF_TPOOL1 - (i + 1), n); + } + + /* Free all allocated */ + for (i = 0; i < SIZE_OF_TPOOL1; i++) + { + pool_free_node(&tpool1, node[i]); + /* Check the number of available nodes */ + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, i + 1, n); + } + + /* Check that addresses of nodes are same with original ones */ + n = 0; + for (i = 0; i < SIZE_OF_TPOOL1; i++) + { + pool_alloc_node(&tpool1, &node[i]); + for (j = 0; j < SIZE_OF_TPOOL1; j++) + { + if (node[i] == org[j]) + n++; + } + } + + /* Free all allocated */ + for (i = 0; i < SIZE_OF_TPOOL1; i++) + { + pool_free_node(&tpool1, node[i]); + /* Check the number of available nodes */ + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, i + 1, n); + } + + pool_final(&tpool1); +} + +static void pool_test_core2(abts_case *tc, void *data, int start) +{ + int i, j, n; + + type_of_tpool2 *org[SIZE_OF_TPOOL2+1]; + type_of_tpool2 *node[SIZE_OF_TPOOL2+1]; + + pool_init(&tpool1, SIZE_OF_TPOOL2); + + /* Check basic members */ + n = pool_size(&tpool1); + ABTS_INT_EQUAL(tc, SIZE_OF_TPOOL2, n); + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, SIZE_OF_TPOOL2, n); + n = pool_used(&tpool1); + ABTS_INT_EQUAL(tc, 0, n); + + /* Allocation up to start index */ + for (i = 0; i < start; i++) + { + pool_alloc_node(&tpool1, &node[i]); + /* Check not null */ + ABTS_PTR_NOTNULL(tc, node[i]); + /* Check the number of available nodes */ + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, SIZE_OF_TPOOL2 - (i + 1), n); + } + + /* Free all allocated nodes */ + for (i = 0; i < start; i++) + { + pool_free_node(&tpool1, node[i]); + /* Check the number of available nodes */ + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, SIZE_OF_TPOOL2 - start + (i + 1), n); + } + + /* Allocation up to maximum pool size */ + for (i = 0; i < SIZE_OF_TPOOL2; i++) + { + pool_alloc_node(&tpool1, &node[i]); + org[i] = node[i]; + /* Check not null */ + ABTS_PTR_NOTNULL(tc, node[i]); + /* Check the number of available nodes */ + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, SIZE_OF_TPOOL2 - (i + 1), n); + } + + /* Free all allocated */ + for (i = 0; i < SIZE_OF_TPOOL2; i++) + { + pool_free_node(&tpool1, node[i]); + /* Check the number of available nodes */ + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, i + 1, n); + } + + /* Check that addresses of nodes are same with original ones */ + n = 0; + for (i = 0; i < SIZE_OF_TPOOL2; i++) + { + pool_alloc_node(&tpool1, &node[i]); + for (j = 0; j < SIZE_OF_TPOOL2; j++) + { + if (node[i] == org[j]) + n++; + } + } + + /* Free all allocated */ + for (i = 0; i < SIZE_OF_TPOOL2; i++) + { + pool_free_node(&tpool1, node[i]); + /* Check the number of available nodes */ + n = pool_avail(&tpool1); + ABTS_INT_EQUAL(tc, i + 1, n); + } + + pool_final(&tpool1); +} + +static void pool_test1(abts_case *tc, void *data) +{ + int i; + + for (i = 0; i < SIZE_OF_TPOOL1; i++) + pool_test_core1(tc, data, i); +} + +static void pool_test2(abts_case *tc, void *data) +{ + int i; + + for (i = 0; i < SIZE_OF_TPOOL2; i++) + pool_test_core2(tc, data, i); +} + + + +/***************************************************************************** + * test for core_list.h + */ +typedef struct { + lnode_t node; + int m1; +} lt_type1; + +list_t tlist1; + +int lttype1_compare(lt_type1 *pnode1, lt_type1 *pnode2) +{ + if (pnode1->m1 == pnode2->m1) + return 0; + else if (pnode1->m1 < pnode2->m1) + return -1; + else + return 1; +} + +#define SIZE_OF_lt_type1 16 + +static void list_test1(abts_case *tc, void *data) +{ + int i; + + lt_type1 *iter, node[SIZE_OF_lt_type1]; + + for (i = 0; i < SIZE_OF_lt_type1; i++) + node[i].m1 = i; + + /* Initialize head of list */ + list_init(&tlist1); + + /* Check list is empty */ + ABTS_TRUE(tc, list_is_empty(&tlist1)); + + /* Confirm that any node can't be get */ + iter = list_first(&tlist1); + ABTS_PTR_NULL(tc, iter); + + /* Add a node */ + list_append(&tlist1, &node[0]); + + /* Iterate from the first. And check the pointers */ + iter = list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_next(iter); + ABTS_PTR_NULL(tc, iter); + + /* Iterate from the last. And check the pointers */ + iter = list_last(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_prev(iter); + ABTS_PTR_NULL(tc, iter); + + /* Add two nodes */ + list_append(&tlist1, &node[1]); + list_append(&tlist1, &node[2]); + + /* Iterate from the first. And check the pointers */ + iter = list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = list_next(iter); + ABTS_PTR_NULL(tc, iter); + + /* Iterate from the last. And check the pointers */ + iter = list_last(&tlist1); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = list_prev(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = list_prev(iter); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_prev(iter); + ABTS_PTR_NULL(tc, iter); + + /* Remove all nodes */ + list_remove(&tlist1, &node[0]); + list_remove(&tlist1, &node[1]); + list_remove(&tlist1, &node[2]); + + /* Check list is empty */ + ABTS_TRUE(tc, list_is_empty(&tlist1)); +} + +static void list_test2(abts_case *tc, void *data) +{ + int i; + + lt_type1 *iter, node[SIZE_OF_lt_type1]; + + for (i = 0; i < SIZE_OF_lt_type1; i++) + node[i].m1 = i; + + /* Initialize head of list */ + list_init(&tlist1); + + /* Check list is empty */ + ABTS_TRUE(tc, list_is_empty(&tlist1)); + + /* Confirm that any node can't be get */ + iter = list_first(&tlist1); + ABTS_PTR_NULL(tc, iter); + + /* Add a node */ + list_prepend(&tlist1, &node[0]); + + /* Iterate from the first. And check the pointers */ + iter = list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_next(iter); + ABTS_PTR_NULL(tc, iter); + + /* Iterate from the last. And check the pointers */ + iter = list_last(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_prev(iter); + ABTS_PTR_NULL(tc, iter); + + /* Add two nodes */ + list_prepend(&tlist1, &node[1]); + list_prepend(&tlist1, &node[2]); + + /* Iterate from the first. And check the pointers */ + iter = list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_next(iter); + ABTS_PTR_NULL(tc, iter); + + /* Iterate from the last. And check the pointers */ + iter = list_last(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_prev(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = list_prev(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = list_prev(iter); + ABTS_PTR_NULL(tc, iter); + + /* Remove all nodes */ + list_remove(&tlist1, &node[2]); + list_remove(&tlist1, &node[1]); + list_remove(&tlist1, &node[0]); + + /* Check list is empty */ + ABTS_TRUE(tc, list_is_empty(&tlist1)); +} + +static void list_test3(abts_case *tc, void *data) +{ + int i; + + lt_type1 *iter, node[SIZE_OF_lt_type1]; + + for (i = 0; i < SIZE_OF_lt_type1; i++) + node[i].m1 = i; + + /* Initialize head of list */ + list_init(&tlist1); + + /* Add three nodes */ + for (i = 0; i < 3; i++) + list_append(&tlist1, &node[i]); + + /* Iterate from the first. And check the pointers */ + i = 0; iter = list_first(&tlist1); + while (iter) + { + ABTS_PTR_EQUAL(tc, &node[i++], iter); + iter = list_next(iter); + } + ABTS_INT_EQUAL(tc, 3, i); + + /* Iterate from the last. And check the pointers */ + i = 0; iter = list_last(&tlist1); + while (iter) + { + ABTS_PTR_EQUAL(tc, &node[3 - (++i)], iter); + iter = list_prev(iter); + } + ABTS_INT_EQUAL(tc, 3, i); + + /* Insert three nodes by list_insert_prev() */ + list_insert_prev(&tlist1, &node[0], &node[3]); + list_insert_prev(&tlist1, &node[1], &node[4]); + list_insert_prev(&tlist1, &node[2], &node[5]); + + /* Iterate from the first. And check the pointers */ + iter = list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[3], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[4], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[5], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = list_next(iter); + ABTS_PTR_NULL(tc, iter); + + /* Remove three nodes inserted by list_insert_prev() */ + list_remove(&tlist1, &node[3]); + list_remove(&tlist1, &node[4]); + list_remove(&tlist1, &node[5]); + + /* Iterate from the first. And check the pointers */ + iter = list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = list_next(iter); + ABTS_PTR_NULL(tc, iter); +} + +static void list_test4(abts_case *tc, void *data) +{ + int i; + + lt_type1 *iter, node[SIZE_OF_lt_type1]; + + for (i = 0; i < SIZE_OF_lt_type1; i++) + node[i].m1 = i; + + /* Initialize head of list */ + list_init(&tlist1); + + /* Add three nodes */ + for (i = 0; i < 3; i++) + list_append(&tlist1, &node[i]); + + /* Iterate from the first. And check the pointers */ + i = 0; iter = list_first(&tlist1); + while (iter) + { + ABTS_PTR_EQUAL(tc, &node[i++], iter); + iter = list_next(iter); + } + ABTS_INT_EQUAL(tc, 3, i); + + /* Iterate from the last. And check the pointers */ + i = 0; iter = list_last(&tlist1); + while (iter) + { + ABTS_PTR_EQUAL(tc, &node[3 - (++i)], iter); + iter = list_prev(iter); + } + ABTS_INT_EQUAL(tc, 3, i); + + /* Insert three nodes by list_insert_next() */ + list_insert_next(&tlist1, &node[0], &node[3]); + list_insert_next(&tlist1, &node[1], &node[4]); + list_insert_next(&tlist1, &node[2], &node[5]); + + /* Iterate from the first. And check the pointers */ + iter = list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[3], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[4], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[5], iter); + iter = list_next(iter); + ABTS_PTR_NULL(tc, iter); + + /* Remove three nodes inserted by list_insert_next() */ + list_remove(&tlist1, &node[3]); + list_remove(&tlist1, &node[4]); + list_remove(&tlist1, &node[5]); + + /* Iterate from the first. And check the pointers */ + iter = list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = list_next(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = list_next(iter); + ABTS_PTR_NULL(tc, iter); +} + +static void list_test5(abts_case *tc, void *data) +{ + int i, j; + + /* List up posssible oders with four nodes */ + int od[24][4] = { + {0,1,2,3}, {0,1,3,2}, {0,2,1,3}, {0,2,3,1}, {0,3,1,2}, {0,3,2,1}, + {1,0,2,3}, {1,0,3,2}, {1,2,0,3}, {1,2,3,0}, {1,3,0,2}, {1,3,2,0}, + {2,1,0,3}, {2,1,3,0}, {2,0,1,3}, {2,0,3,1}, {2,3,1,0}, {2,3,0,1}, + {3,1,2,0}, {3,1,0,2}, {3,2,1,0}, {3,2,0,1}, {3,0,1,2}, {3,0,2,1} + }; + + lt_type1 *iter, node[SIZE_OF_lt_type1]; + + for (i = 0; i < SIZE_OF_lt_type1; i++) + node[i].m1 = i; + + for (i = 0; i < 24; i++) + { + /* Initialize head of list */ + list_init(&tlist1); + + /* Add four nodes using predefined orders */ + for (j = 0; j < 4; j++) + list_insert_sorted(&tlist1, &node[od[i][j]], <type1_compare); + + /* Iterate from the first. And check the SORTED */ + j = 0; iter = list_first(&tlist1); + while (iter) + { + ABTS_INT_EQUAL(tc, iter->m1, j++); + iter = list_next(iter); + } + } +} + + + +/***************************************************************************** + * test for core_queue.h + */ +typedef struct { + int m1; +} qt_type1; + +#define SIZE_OF_TQUE1 4 +#define SIZE_OF_TQUE2 3 + +typedef int type_of_tque1; +typedef qt_type1 type_of_tque2; + +que_declare(tque1, type_of_tque1, SIZE_OF_TQUE1); +que_declare(tque2, type_of_tque2, SIZE_OF_TQUE2); +que_declare(tque3, type_of_tque2 *, SIZE_OF_TQUE2); + +static void que_test1(abts_case *tc, void *data) +{ + int i, r; + + type_of_tque1 n, node[SIZE_OF_TQUE1+1]; + + n = 0; + for (i = 0; i < SIZE_OF_TQUE1; i++) + node[i] = i; + + /* Initialize queue */ + que_init(&tque1, SIZE_OF_TQUE1); + + /* Check basic members */ + ABTS_TRUE(tc, que_is_empty(&tque1)); + ABTS_FALSE(tc, que_is_full(&tque1)); + ABTS_INT_EQUAL(tc, SIZE_OF_TQUE1, que_avail(&tque1)); + ABTS_INT_EQUAL(tc, 0, que_used(&tque1)); + + /* Push a node */ + r = que_push(&tque1, &node[0]); + ABTS_INT_EQUAL(tc, 1, r); + + /* Check queue status */ + ABTS_FALSE(tc, que_is_empty(&tque1)); + ABTS_FALSE(tc, que_is_full(&tque1)); + ABTS_INT_EQUAL(tc, SIZE_OF_TQUE1 - 1, que_avail(&tque1)); + ABTS_INT_EQUAL(tc, 1, que_used(&tque1)); + + /* Pop a node */ + r = que_pop(&tque1, &n); + ABTS_INT_EQUAL(tc, 0, r); + + /* Check queue status */ + ABTS_TRUE(tc, que_is_empty(&tque1)); + ABTS_FALSE(tc, que_is_full(&tque1)); + ABTS_INT_EQUAL(tc, SIZE_OF_TQUE1, que_avail(&tque1)); + ABTS_INT_EQUAL(tc, 0, que_used(&tque1)); + + /* Push nodes up to queue size */ + for (i = 0; i < SIZE_OF_TQUE1; i++) + { + r = que_push(&tque1, &node[i]); + ABTS_INT_EQUAL(tc, i + 1, r); + } + + /* Check queue status */ + ABTS_FALSE(tc, que_is_empty(&tque1)); + ABTS_TRUE(tc, que_is_full(&tque1)); + ABTS_INT_EQUAL(tc, 0, que_avail(&tque1)); + ABTS_INT_EQUAL(tc, SIZE_OF_TQUE1, que_used(&tque1)); + + /* Push a node to full queue */ + r = que_push(&tque1, &node[0]); + ABTS_INT_EQUAL(tc, -1, r); + + /* Pop all pushed nodes and check pop order */ + for (i = 0; i < SIZE_OF_TQUE1; i++) + { + r = que_pop(&tque1, &n); + ABTS_INT_EQUAL(tc, node[i], n); + ABTS_INT_EQUAL(tc, SIZE_OF_TQUE1 - (i + 1), r); + } + + /* Check queue status */ + ABTS_TRUE(tc, que_is_empty(&tque1)); + ABTS_FALSE(tc, que_is_full(&tque1)); + ABTS_INT_EQUAL(tc, SIZE_OF_TQUE1, que_avail(&tque1)); + ABTS_INT_EQUAL(tc, 0, que_used(&tque1)); + + /* Pop a node from empty queue */ + r = que_pop(&tque1, &n); + ABTS_INT_EQUAL(tc, -1, r); +} + + + +/***************************************************************************** + * test for core_ringbuf.h + */ + +#define SIZE_OF_TRBUF1 7 +rbuf_declare(trbuf1, SIZE_OF_TRBUF1); + +#define SIZE_OF_TRBUF2 7 +rbuf_declare_ext(trbuf2); +char trbuf2_ext_buf[SIZE_OF_TRBUF2]; + +static void rbuf_test1(abts_case *tc, void *data) +{ + int i, n; + char wbuf[32]; + char rbuf[32]; + + for (i = 0; i < 26; i++) + wbuf[i] = 'a' + i; + + rbuf_init(&trbuf1, SIZE_OF_TRBUF1); + + /* Check basic members */ + ABTS_TRUE(tc, rbuf_is_empty(&trbuf1)); + ABTS_FALSE(tc, rbuf_is_full(&trbuf1)); + ABTS_INT_EQUAL(tc, SIZE_OF_TRBUF1, rbuf_free_bytes(&trbuf1)); + ABTS_INT_EQUAL(tc, 0, rbuf_bytes(&trbuf1)); + + /* Write 3 bytes */ + n = rbuf_write(&trbuf1, wbuf, 3); + ABTS_INT_EQUAL(tc, 3, n); + + /* Check basic members */ + ABTS_FALSE(tc, rbuf_is_empty(&trbuf1)); + ABTS_FALSE(tc, rbuf_is_full(&trbuf1)); + ABTS_INT_EQUAL(tc, SIZE_OF_TRBUF1 - 3, rbuf_free_bytes(&trbuf1)); + ABTS_INT_EQUAL(tc, 3, rbuf_bytes(&trbuf1)); + + /* Read 3 bytes */ + n = rbuf_read(&trbuf1, rbuf, 3); rbuf[3] = 0; + ABTS_INT_EQUAL(tc, 3, n); + ABTS_STR_EQUAL(tc, "abc", rbuf); + + /* Check basic members */ + ABTS_TRUE(tc, rbuf_is_empty(&trbuf1)); + ABTS_FALSE(tc, rbuf_is_full(&trbuf1)); + ABTS_INT_EQUAL(tc, SIZE_OF_TRBUF1, rbuf_free_bytes(&trbuf1)); + ABTS_INT_EQUAL(tc, 0, rbuf_bytes(&trbuf1)); + + /* Write 3 bytes */ + n = rbuf_write(&trbuf1, wbuf, 3); + ABTS_INT_EQUAL(tc, 3, n); + + /* Write 5 bytes, but only 4 bytes shall be written */ + n = rbuf_write(&trbuf1, wbuf + 3, 5); + ABTS_INT_EQUAL(tc, 4, n); + + /* Write 1 bytes to full buffer */ + n = rbuf_write(&trbuf1, wbuf, 1); + ABTS_INT_EQUAL(tc, -1, n); + + /* Read 2 bytes */ + n = rbuf_read(&trbuf1, rbuf, 2); rbuf[2] = 0; + ABTS_INT_EQUAL(tc, 2, n); + ABTS_STR_EQUAL(tc, "ab", rbuf); + + /* Read 5 bytes */ + n = rbuf_read(&trbuf1, rbuf, 5); rbuf[5] = 0; + ABTS_INT_EQUAL(tc, 5, n); + ABTS_STR_EQUAL(tc, "cdefg", rbuf); + + /* Check basic members */ + ABTS_TRUE(tc, rbuf_is_empty(&trbuf1)); + ABTS_FALSE(tc, rbuf_is_full(&trbuf1)); + ABTS_INT_EQUAL(tc, SIZE_OF_TRBUF1, rbuf_free_bytes(&trbuf1)); + ABTS_INT_EQUAL(tc, 0, rbuf_bytes(&trbuf1)); + + /* Read 1 bytes from empty buffer */ + n = rbuf_read(&trbuf1, rbuf, 1); + ABTS_INT_EQUAL(tc, -1, n); +} + +static void rbuf_test2(abts_case *tc, void *data) +{ + int i, n; + char wbuf[32]; + char rbuf[32]; + + for (i = 0; i < 26; i++) + wbuf[i] = 'a' + i; + + rbuf_init_ext(&trbuf2, SIZE_OF_TRBUF1, trbuf2_ext_buf); + + /* Check basic members */ + ABTS_TRUE(tc, rbuf_is_empty(&trbuf2)); + ABTS_FALSE(tc, rbuf_is_full(&trbuf2)); + ABTS_INT_EQUAL(tc, SIZE_OF_TRBUF2, rbuf_free_bytes(&trbuf2)); + ABTS_INT_EQUAL(tc, 0, rbuf_bytes(&trbuf2)); + + /* Write 3 bytes */ + n = rbuf_write(&trbuf2, wbuf, 3); + ABTS_INT_EQUAL(tc, 3, n); + + /* Check basic members */ + ABTS_FALSE(tc, rbuf_is_empty(&trbuf2)); + ABTS_FALSE(tc, rbuf_is_full(&trbuf2)); + ABTS_INT_EQUAL(tc, SIZE_OF_TRBUF2 - 3, rbuf_free_bytes(&trbuf2)); + ABTS_INT_EQUAL(tc, 3, rbuf_bytes(&trbuf2)); + + /* Read 3 bytes */ + n = rbuf_read(&trbuf2, rbuf, 3); rbuf[3] = 0; + ABTS_INT_EQUAL(tc, 3, n); + ABTS_STR_EQUAL(tc, "abc", rbuf); + + /* Check basic members */ + ABTS_TRUE(tc, rbuf_is_empty(&trbuf2)); + ABTS_FALSE(tc, rbuf_is_full(&trbuf2)); + ABTS_INT_EQUAL(tc, SIZE_OF_TRBUF2, rbuf_free_bytes(&trbuf2)); + ABTS_INT_EQUAL(tc, 0, rbuf_bytes(&trbuf2)); + + /* Write 3 bytes */ + n = rbuf_write(&trbuf2, wbuf, 3); + ABTS_INT_EQUAL(tc, 3, n); + + /* Write 5 bytes, but only 4 bytes shall be written */ + n = rbuf_write(&trbuf2, wbuf + 3, 5); + ABTS_INT_EQUAL(tc, 4, n); + + /* Write 1 bytes to full buffer */ + n = rbuf_write(&trbuf2, wbuf, 1); + ABTS_INT_EQUAL(tc, -1, n); + + /* Read 2 bytes */ + n = rbuf_read(&trbuf2, rbuf, 2); rbuf[2] = 0; + ABTS_INT_EQUAL(tc, 2, n); + ABTS_STR_EQUAL(tc, "ab", rbuf); + + /* Read 5 bytes */ + n = rbuf_read(&trbuf2, rbuf, 5); rbuf[5] = 0; + ABTS_INT_EQUAL(tc, 5, n); + ABTS_STR_EQUAL(tc, "cdefg", rbuf); + + /* Check basic members */ + ABTS_TRUE(tc, rbuf_is_empty(&trbuf2)); + ABTS_FALSE(tc, rbuf_is_full(&trbuf2)); + ABTS_INT_EQUAL(tc, SIZE_OF_TRBUF2, rbuf_free_bytes(&trbuf2)); + ABTS_INT_EQUAL(tc, 0, rbuf_bytes(&trbuf2)); + + /* Read 1 bytes from empty buffer */ + n = rbuf_read(&trbuf2, rbuf, 1); + ABTS_INT_EQUAL(tc, -1, n); + + n = rbuf_skip_write_pos(&trbuf2, 5); + ABTS_INT_EQUAL(tc, 5, n); + n = rbuf_skip_read_pos(&trbuf2, 5); + ABTS_INT_EQUAL(tc, 5, n); +} + +abts_suite *testds(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, pool_test1, NULL); + abts_run_test(suite, pool_test2, NULL); + + abts_run_test(suite, list_test1, NULL); + abts_run_test(suite, list_test2, NULL); + abts_run_test(suite, list_test3, NULL); + abts_run_test(suite, list_test4, NULL); + abts_run_test(suite, list_test5, NULL); + + abts_run_test(suite, que_test1, NULL); + + abts_run_test(suite, rbuf_test1, NULL); + abts_run_test(suite, rbuf_test2, NULL); + + return suite; +} diff --git a/lib/core/test/testfile.c b/lib/core/test/testfile.c new file mode 100644 index 0000000000..0ef96fb297 --- /dev/null +++ b/lib/core/test/testfile.c @@ -0,0 +1,684 @@ +#include "core_file.h" +#include "testutil.h" + +#define DIRNAME "data" +#define FILENAME DIRNAME "/file_datafile.txt" +#define TESTSTR "This is the file data file." + +#define TESTREAD_BLKSIZE 1024 +#define FILE_BUFFERSIZE 4096 /* This should match FILE's buffer size. */ + + +static void test_file_init(abts_case *tc, void *data) +{ + status_t rv; + file_info_t finfo; + size_t bytes; + file_t *filetest = NULL; + + rv = dir_make("data", FILE_UREAD | FILE_UWRITE | FILE_UEXECUTE); + + rv = file_stat(&finfo, "data", FILE_INFO_TYPE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_INT_EQUAL(tc, FILE_DIR, finfo.filetype); + + rv = file_open(&filetest, FILENAME, + FILE_WRITE | FILE_CREATE, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + bytes = strlen(TESTSTR); + rv = file_write(filetest, TESTSTR, &bytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + file_close(filetest); + +} + +static void test_open_noreadwrite(abts_case *tc, void *data) +{ + status_t rv; + file_t *thefile = NULL; + + rv = file_open(&thefile, FILENAME, + FILE_CREATE | FILE_EXCL, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_TRUE(tc, rv != CORE_OK); + ABTS_INT_EQUAL(tc, 1, STATUS_IS_EACCES(rv)); + ABTS_PTR_EQUAL(tc, NULL, thefile); +} + +static void test_open_excl(abts_case *tc, void *data) +{ + status_t rv; + file_t *thefile = NULL; + + rv = file_open(&thefile, FILENAME, + FILE_CREATE | FILE_EXCL | FILE_WRITE, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_TRUE(tc, rv != CORE_OK); + ABTS_INT_EQUAL(tc, 1, STATUS_IS_EEXIST(rv)); + ABTS_PTR_EQUAL(tc, NULL, thefile); +} + +static void test_open_read(abts_case *tc, void *data) +{ + status_t rv; + file_t *filetest = NULL; + + rv = file_open(&filetest, FILENAME, + FILE_READ, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_PTR_NOTNULL(tc, filetest); + file_close(filetest); +} + +static void link_existing(abts_case *tc, void *data) +{ + status_t rv; + + rv = file_link("data/file_datafile.txt", "data/file_datafile2.txt"); + file_remove("data/file_datafile2.txt"); + ABTS_ASSERT(tc, "Couldn't create hardlink to file", rv == CORE_OK); +} + +static void link_nonexisting(abts_case *tc, void *data) +{ + status_t rv; + + rv = file_link("data/does_not_exist.txt", "data/fake.txt"); + ABTS_ASSERT(tc, "", rv != CORE_OK); +} + +static void test_read(abts_case *tc, void *data) +{ + status_t rv; + size_t nbytes = 256; + char *str = malloc(nbytes + 1); + file_t *filetest = NULL; + + rv = file_open(&filetest, FILENAME, + FILE_READ, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + + CORE_ASSERT_OK(tc, "Opening test file " FILENAME, rv); + rv = file_read(filetest, str, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, strlen(TESTSTR), nbytes); + ABTS_STR_EQUAL(tc, TESTSTR, str); + + free(str); + + file_close(filetest); +} + +static void test_readzero(abts_case *tc, void *data) +{ + status_t rv; + size_t nbytes = 0; + char *str = NULL; + file_t *filetest; + + rv = file_open(&filetest, FILENAME, FILE_READ, FILE_OS_DEFAULT); + CORE_ASSERT_OK(tc, "Opening test file " FILENAME, rv); + + rv = file_read(filetest, str, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, 0, nbytes); + + file_close(filetest); +} + +static void test_filename(abts_case *tc, void *data) +{ + const char *str; + status_t rv; + file_t *filetest = NULL; + + rv = file_open(&filetest, FILENAME, + FILE_READ, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + CORE_ASSERT_OK(tc, "Opening test file " FILENAME, rv); + + rv = file_name_get(&str, filetest); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_STR_EQUAL(tc, FILENAME, str); + + file_close(filetest); +} + +static void test_fileclose(abts_case *tc, void *data) +{ + char str; + status_t rv; + size_t one = 1; + file_t *filetest = NULL; + + rv = file_open(&filetest, FILENAME, + FILE_READ, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + CORE_ASSERT_OK(tc, "Opening test file " FILENAME, rv); + + rv = file_close(filetest); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + /* We just closed the file, so this should fail */ + rv = file_read(filetest, &str, &one); + ABTS_INT_EQUAL(tc, 1, STATUS_IS_EBADF(rv)); +} + +static void test_file_remove(abts_case *tc, void *data) +{ + status_t rv; + file_t *filetest = NULL; + + rv = file_remove(FILENAME); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_open(&filetest, FILENAME, FILE_READ, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_INT_EQUAL(tc, 1, STATUS_IS_ENOENT(rv)); +} + +static void test_open_write(abts_case *tc, void *data) +{ + status_t rv; + file_t *filetest = NULL; + + filetest = NULL; + rv = file_open(&filetest, FILENAME, + FILE_WRITE, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_INT_EQUAL(tc, 1, STATUS_IS_ENOENT(rv)); + ABTS_PTR_EQUAL(tc, NULL, filetest); +} + +static void test_open_writecreate(abts_case *tc, void *data) +{ + status_t rv; + file_t *filetest = NULL; + + filetest = NULL; + rv = file_open(&filetest, FILENAME, + FILE_WRITE | FILE_CREATE, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + file_close(filetest); +} + +static void test_write(abts_case *tc, void *data) +{ + status_t rv; + size_t bytes = strlen(TESTSTR); + file_t *filetest = NULL; + + rv = file_open(&filetest, FILENAME, + FILE_WRITE | FILE_CREATE, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_write(filetest, TESTSTR, &bytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + file_close(filetest); +} + +static void test_open_readwrite(abts_case *tc, void *data) +{ + status_t rv; + file_t *filetest = NULL; + + filetest = NULL; + rv = file_open(&filetest, FILENAME, + FILE_READ | FILE_WRITE, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_PTR_NOTNULL(tc, filetest); + + file_close(filetest); +} + +static void test_seek(abts_case *tc, void *data) +{ + status_t rv; + off_t offset = 5; + size_t nbytes = 256; + char *str = malloc(nbytes + 1); + file_t *filetest = NULL; + + rv = file_open(&filetest, FILENAME, + FILE_READ, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + CORE_ASSERT_OK(tc, "Open test file " FILENAME, rv); + + rv = file_read(filetest, str, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, strlen(TESTSTR), nbytes); + ABTS_STR_EQUAL(tc, TESTSTR, str); + + memset(str, 0, nbytes + 1); + + rv = file_seek(filetest, SEEK_SET, &offset); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_read(filetest, str, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, strlen(TESTSTR) - 5, nbytes); + ABTS_STR_EQUAL(tc, TESTSTR + 5, str); + + file_close(filetest); + + /* Test for regression of sign error bug with SEEK_END and + buffered files. */ + rv = file_open(&filetest, FILENAME, + FILE_READ, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + CORE_ASSERT_OK(tc, "Open test file " FILENAME, rv); + + offset = -5; + rv = file_seek(filetest, SEEK_END, &offset); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, strlen(TESTSTR) - 5, nbytes); + + memset(str, 0, nbytes + 1); + nbytes = 256; + rv = file_read(filetest, str, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, 5, nbytes); + ABTS_STR_EQUAL(tc, TESTSTR + strlen(TESTSTR) - 5, str); + + free(str); + + file_close(filetest); +} + +static void test_getc(abts_case *tc, void *data) +{ + file_t *f = NULL; + status_t rv; + char ch; + + rv = file_open(&f, FILENAME, FILE_READ, 0); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + file_getc(&ch, f); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_INT_EQUAL(tc, (int)TESTSTR[0], (int)ch); + file_close(f); +} + +static void test_gets(abts_case *tc, void *data) +{ + file_t *f = NULL; + status_t rv; + char *str = malloc(256); + + rv = file_open(&f, FILENAME, FILE_READ, 0); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_gets(str, 256, f); + /* Only one line in the test file, so FILE will encounter EOF on the first + * call to gets, but we should get CORE_OK on this call and + * CORE_EOF on the next. + */ + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_STR_EQUAL(tc, TESTSTR, str); + rv = file_gets(str, 256, f); + ABTS_INT_EQUAL(tc, CORE_EOF, rv); + ABTS_STR_EQUAL(tc, "", str); + + free(str); + file_close(f); +} + +static void test_bigread(abts_case *tc, void *data) +{ + file_t *f = NULL; + status_t rv; + char buf[FILE_BUFFERSIZE * 2]; + size_t nbytes; + + /* Create a test file with known content. + */ + rv = file_open(&f, "data/created_file", + FILE_CREATE | FILE_WRITE | FILE_TRUNCATE, + FILE_UREAD | FILE_UWRITE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + nbytes = FILE_BUFFERSIZE; + memset(buf, 0xFE, nbytes); + + rv = file_write(f, buf, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, FILE_BUFFERSIZE, nbytes); + + rv = file_close(f); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + f = NULL; + rv = file_open(&f, "data/created_file", FILE_READ, 0); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + nbytes = sizeof buf; + rv = file_read(f, buf, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, FILE_BUFFERSIZE, nbytes); + + rv = file_close(f); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_remove("data/created_file"); + ABTS_INT_EQUAL(tc, CORE_OK, rv); +} + +/* This is a horrible name for this function. We are testing FILE, not how + * Apache uses FILE. And, this function tests _way_ too much stuff. + */ +static void test_mod_neg(abts_case *tc, void *data) +{ + status_t rv; + file_t *f; + const char *s; + int i; + size_t nbytes; + char buf[8192]; + off_t cur; + const char *fname = "data/modneg.dat"; + + rv = file_open(&f, fname, + FILE_CREATE | FILE_WRITE, FILE_UREAD | FILE_UWRITE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + s = "body56789\n"; + nbytes = strlen(s); + rv = file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); + + for (i = 0; i < 7980; i++) { + s = "0"; + nbytes = strlen(s); + rv = file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); + } + + s = "end456789\n"; + nbytes = strlen(s); + rv = file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); + + for (i = 0; i < 10000; i++) { + s = "1"; + nbytes = strlen(s); + rv = file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); + } + + rv = file_close(f); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_open(&f, fname, FILE_READ, 0); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_gets(buf, 11, f); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_STR_EQUAL(tc, "body56789\n", buf); + + cur = 0; + rv = file_seek(f, FILE_CUR, &cur); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_ASSERT(tc, "File Pointer Mismatch, expected 10", cur == 10); + + nbytes = sizeof(buf); + rv = file_read(f, buf, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, nbytes, sizeof(buf)); + + cur = -((off_t)nbytes - 7980); + rv = file_seek(f, FILE_CUR, &cur); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_ASSERT(tc, "File Pointer Mismatch, expected 7990", cur == 7990); + + rv = file_gets(buf, 11, f); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_STR_EQUAL(tc, "end456789\n", buf); + + rv = file_close(f); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_remove(fname); + ABTS_INT_EQUAL(tc, CORE_OK, rv); +} + +/* Test that the contents of file FNAME are equal to data EXPECT of + * length EXPECTLEN. */ +static void file_contents_equal(abts_case *tc, + const char *fname, + const void *expect, + size_t expectlen) +{ + void *actual = malloc(expectlen); + file_t *f; + + CORE_ASSERT_OK(tc, "open file", + file_open(&f, fname, FILE_READ, + 0)); + CORE_ASSERT_OK(tc, "read from file", + file_read_full(f, actual, expectlen, NULL)); + + ABTS_ASSERT(tc, "matched expected file contents", + memcmp(expect, actual, expectlen) == 0); + + CORE_ASSERT_OK(tc, "close file", file_close(f)); + + free(actual); +} + +#define LINE1 "this is a line of text\n" +#define LINE2 "this is a second line of text\n" + +static void test_puts(abts_case *tc, void *data) +{ + file_t *f; + const char *fname = "data/testputs.txt"; + + CORE_ASSERT_OK(tc, "open file for writing", + file_open(&f, fname, + FILE_WRITE|FILE_CREATE|FILE_TRUNCATE, + FILE_OS_DEFAULT)); + CORE_ASSERT_OK(tc, "write line to file", + file_puts(LINE1, f)); + CORE_ASSERT_OK(tc, "write second line to file", + file_puts(LINE2, f)); + + CORE_ASSERT_OK(tc, "close for writing", + file_close(f)); + + file_contents_equal(tc, fname, LINE1 LINE2, strlen(LINE1 LINE2)); +} + +static void test_writev(abts_case *tc, void *data) +{ + file_t *f; + size_t nbytes; + struct iovec vec[5]; + const char *fname = "data/testwritev.txt"; + + CORE_ASSERT_OK(tc, "open file for writing", + file_open(&f, fname, + FILE_WRITE|FILE_CREATE|FILE_TRUNCATE, + FILE_OS_DEFAULT)); + + vec[0].iov_base = LINE1; + vec[0].iov_len = strlen(LINE1); + + CORE_ASSERT_OK(tc, "writev of size 1 to file", + file_writev(f, vec, 1, &nbytes)); + + file_contents_equal(tc, fname, LINE1, strlen(LINE1)); + + vec[0].iov_base = LINE1; + vec[0].iov_len = strlen(LINE1); + vec[1].iov_base = LINE2; + vec[1].iov_len = strlen(LINE2); + vec[2].iov_base = LINE1; + vec[2].iov_len = strlen(LINE1); + vec[3].iov_base = LINE1; + vec[3].iov_len = strlen(LINE1); + vec[4].iov_base = LINE2; + vec[4].iov_len = strlen(LINE2); + + CORE_ASSERT_OK(tc, "writev of size 5 to file", + file_writev(f, vec, 5, &nbytes)); + + CORE_ASSERT_OK(tc, "close for writing", + file_close(f)); + + file_contents_equal(tc, fname, LINE1 LINE1 LINE2 LINE1 LINE1 LINE2, + strlen(LINE1)*4 + strlen(LINE2)*2); + +} + +static void test_writev_full(abts_case *tc, void *data) +{ + file_t *f; + size_t nbytes; + struct iovec vec[5]; + const char *fname = "data/testwritev_full.txt"; + + CORE_ASSERT_OK(tc, "open file for writing", + file_open(&f, fname, + FILE_WRITE|FILE_CREATE|FILE_TRUNCATE, + FILE_OS_DEFAULT)); + + vec[0].iov_base = LINE1; + vec[0].iov_len = strlen(LINE1); + vec[1].iov_base = LINE2; + vec[1].iov_len = strlen(LINE2); + vec[2].iov_base = LINE1; + vec[2].iov_len = strlen(LINE1); + vec[3].iov_base = LINE1; + vec[3].iov_len = strlen(LINE1); + vec[4].iov_base = LINE2; + vec[4].iov_len = strlen(LINE2); + + CORE_ASSERT_OK(tc, "writev_full of size 5 to file", + file_writev_full(f, vec, 5, &nbytes)); + + ABTS_SIZE_EQUAL(tc, strlen(LINE1)*3 + strlen(LINE2)*2, nbytes); + + CORE_ASSERT_OK(tc, "close for writing", + file_close(f)); + + file_contents_equal(tc, fname, LINE1 LINE2 LINE1 LINE1 LINE2, + strlen(LINE1)*3 + strlen(LINE2)*2); + +} + +static void test_truncate(abts_case *tc, void *data) +{ + status_t rv; + file_t *f; + const char *fname = "data/testtruncate.dat"; + const char *s; + size_t nbytes; + file_info_t finfo; + + file_remove(fname); + + rv = file_open(&f, fname, + FILE_CREATE | FILE_WRITE, FILE_UREAD | FILE_UWRITE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + s = "some data"; + nbytes = strlen(s); + rv = file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); + + rv = file_close(f); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_open(&f, fname, + FILE_TRUNCATE | FILE_WRITE, FILE_UREAD | FILE_UWRITE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_close(f); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + rv = file_stat(&finfo, fname, FILE_INFO_SIZE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_ASSERT(tc, "File size mismatch, expected 0 (empty)", finfo.size == 0); + + rv = file_remove(fname); + ABTS_INT_EQUAL(tc, CORE_OK, rv); +} + +static void test_fail_write_flush(abts_case *tc, void *data) +{ + file_t *f; + const char *fname = "data/testflush.dat"; + status_t rv; + char buf[FILE_BUFFERSIZE]; + int n; + + file_remove(fname); + + CORE_ASSERT_OK(tc, "open test file", + file_open(&f, fname, + FILE_CREATE|FILE_READ, + FILE_UREAD|FILE_UWRITE)); + + memset(buf, 'A', sizeof buf); + + /* Try three writes. One of these should fail when it exceeds the + * internal buffer and actually tries to write to the file, which + * was opened read-only and hence should be unwritable. */ + for (n = 0, rv = CORE_OK; n < 4 && rv == CORE_OK; n++) { + size_t bytes = sizeof buf; + rv = file_write(f, buf, &bytes); + } + + ABTS_ASSERT(tc, "failed to write to read-only buffered fd", + rv != CORE_OK); + + file_close(f); +} + +abts_suite *testfile(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_file_init, NULL); + abts_run_test(suite, test_open_noreadwrite, NULL); + abts_run_test(suite, test_open_excl, NULL); + abts_run_test(suite, test_open_read, NULL); + abts_run_test(suite, test_open_readwrite, NULL); + abts_run_test(suite, link_existing, NULL); + abts_run_test(suite, link_nonexisting, NULL); + abts_run_test(suite, test_read, NULL); + abts_run_test(suite, test_readzero, NULL); + abts_run_test(suite, test_seek, NULL); + abts_run_test(suite, test_filename, NULL); + abts_run_test(suite, test_fileclose, NULL); + abts_run_test(suite, test_file_remove, NULL); + abts_run_test(suite, test_open_write, NULL); + abts_run_test(suite, test_open_writecreate, NULL); + abts_run_test(suite, test_write, NULL); + abts_run_test(suite, test_getc, NULL); + abts_run_test(suite, test_gets, NULL); + abts_run_test(suite, test_puts, NULL); + abts_run_test(suite, test_writev, NULL); + abts_run_test(suite, test_writev_full, NULL); + abts_run_test(suite, test_bigread, NULL); + abts_run_test(suite, test_mod_neg, NULL); + abts_run_test(suite, test_truncate, NULL); + abts_run_test(suite, test_fail_write_flush, NULL); + + return suite; +} + diff --git a/lib/core/test/testfilecopy.c b/lib/core/test/testfilecopy.c new file mode 100644 index 0000000000..2750bf7ed6 --- /dev/null +++ b/lib/core/test/testfilecopy.c @@ -0,0 +1,163 @@ +#include "core_file.h" +#include "testutil.h" + +#define DIRNAME "data" +#define FILENAME1 DIRNAME "/file_datafile.txt" +#define TESTSTR1 "This is the file data file." +#define FILENAME2 DIRNAME "/mmap_datafile.txt" +#define TESTSTR2 "This is the MMAP data file." + +static void test_filecopy_init(abts_case *tc, void *data) +{ + status_t rv; + file_info_t finfo; + size_t bytes; + file_t *filetest = NULL; + + rv = dir_make("data", FILE_UREAD | FILE_UWRITE | FILE_UEXECUTE); + + rv = file_stat(&finfo, "data", FILE_INFO_TYPE); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + ABTS_INT_EQUAL(tc, FILE_DIR, finfo.filetype); + + rv = file_open(&filetest, FILENAME1, + FILE_WRITE | FILE_CREATE, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + bytes = strlen(TESTSTR1); + rv = file_write(filetest, TESTSTR1, &bytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + file_close(filetest); + + rv = file_open(&filetest, FILENAME2, + FILE_WRITE | FILE_CREATE, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + bytes = strlen(TESTSTR2); + rv = file_write(filetest, TESTSTR2, &bytes); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + + file_close(filetest); +} + +static void copy_helper(abts_case *tc, const char *from, const char * to, + file_perms_t perms, int append) +{ + status_t rv; + status_t dest_rv; + file_info_t copy; + file_info_t orig; + file_info_t dest; + + dest_rv = file_stat(&dest, to, FILE_INFO_SIZE); + + if (!append) { + rv = file_copy(from, to, perms); + } + else { + rv = file_append(from, to, perms); + } + CORE_ASSERT_OK(tc, "Error copying file", rv); + + rv = file_stat(&orig, from, FILE_INFO_SIZE); + CORE_ASSERT_OK(tc, "Couldn't stat original file", rv); + + rv = file_stat(©, to, FILE_INFO_SIZE); + CORE_ASSERT_OK(tc, "Couldn't stat copy file", rv); + + if (!append) { + ABTS_ASSERT(tc, "File size differs", orig.size == copy.size); + } + else { + ABTS_ASSERT(tc, "File size differs", + ((dest_rv == CORE_OK) + ? dest.size : 0) + orig.size == copy.size); + } +} + +static void copy_short_file(abts_case *tc, void *data) +{ + status_t rv; + + /* make absolutely sure that the dest file doesn't exist. */ + file_remove("data/file_copy.txt"); + + copy_helper(tc, "data/file_datafile.txt", "data/file_copy.txt", + FILE_SOURCE_PERMS, 0); + rv = file_remove("data/file_copy.txt"); + CORE_ASSERT_OK(tc, "Couldn't remove copy file", rv); +} + +static void copy_over_existing(abts_case *tc, void *data) +{ + status_t rv; + + /* make absolutely sure that the dest file doesn't exist. */ + file_remove("data/file_copy.txt"); + + /* This is a cheat. I don't want to create a new file, so I just copy + * one file, then I copy another. If the second copy succeeds, then + * this works. + */ + copy_helper(tc, "data/file_datafile.txt", "data/file_copy.txt", + FILE_SOURCE_PERMS, 0); + + copy_helper(tc, "data/mmap_datafile.txt", "data/file_copy.txt", + FILE_SOURCE_PERMS, 0); + + rv = file_remove("data/file_copy.txt"); + CORE_ASSERT_OK(tc, "Couldn't remove copy file", rv); +} + +static void append_nonexist(abts_case *tc, void *data) +{ + status_t rv; + + /* make absolutely sure that the dest file doesn't exist. */ + file_remove("data/file_copy.txt"); + + copy_helper(tc, "data/file_datafile.txt", "data/file_copy.txt", + FILE_SOURCE_PERMS, 0); + rv = file_remove("data/file_copy.txt"); + CORE_ASSERT_OK(tc, "Couldn't remove copy file", rv); +} + +static void append_exist(abts_case *tc, void *data) +{ + status_t rv; + + /* make absolutely sure that the dest file doesn't exist. */ + file_remove("data/file_copy.txt"); + + /* This is a cheat. I don't want to create a new file, so I just copy + * one file, then I copy another. If the second copy succeeds, then + * this works. + */ + copy_helper(tc, "data/file_datafile.txt", "data/file_copy.txt", + FILE_SOURCE_PERMS, 0); + + copy_helper(tc, "data/mmap_datafile.txt", "data/file_copy.txt", + FILE_SOURCE_PERMS, 1); + + rv = file_remove("data/file_copy.txt"); + CORE_ASSERT_OK(tc, "Couldn't remove copy file", rv); +} + +abts_suite *testfilecopy(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_filecopy_init, NULL); + + abts_run_test(suite, copy_short_file, NULL); + abts_run_test(suite, copy_over_existing, NULL); + + abts_run_test(suite, append_nonexist, NULL); + abts_run_test(suite, append_exist, NULL); + + return suite; +} + diff --git a/lib/core/test/testfsm.c b/lib/core/test/testfsm.c new file mode 100644 index 0000000000..b93d5b60bd --- /dev/null +++ b/lib/core/test/testfsm.c @@ -0,0 +1,298 @@ +#include "core_fsm.h" +#include "testutil.h" + +enum bomb_signal_t { + UP_SIG = FSM_USER_SIG, + DOWN_SIG, + ARM_SIG +}; + +typedef struct _tick_event_t { + fsm_event_t event; +} tick_event_t; + +typedef struct _bomb_t { + fsm_t fsm; + c_uint8_t timeout; + c_uint8_t code; + c_uint8_t defuse; +} bomb_t; + +void bomb_initial(bomb_t *s, fsm_event_t *e); +void bomb_setting(bomb_t *s, fsm_event_t *e); +void bomb_timing(bomb_t *s, fsm_event_t *e); + +void bomb_create(bomb_t *s, uint8_t defuse) +{ + fsm_create(&s->fsm, (fsm_handler_t)&bomb_initial, (fsm_handler_t)0); + s->defuse = defuse; +} + +void bomb_initial(bomb_t *s, fsm_event_t *e) +{ + s->timeout = 10; + FSM_TRAN(s, &bomb_setting); +} + +void bomb_setting(bomb_t *s, fsm_event_t *e) +{ + tick_event_t *te = (tick_event_t*)e; + switch (te->event) + { + case UP_SIG: + { + if (s->timeout < 12) + { + ++s->timeout; + } + break; + } + case DOWN_SIG: { + if (s->timeout > 8) + { + --s->timeout; + } + break; + } + case ARM_SIG: + { + FSM_TRAN(s, &bomb_timing); + break; + } + } +} + +void bomb_timing(bomb_t *s, fsm_event_t *e) +{ + tick_event_t *te = (tick_event_t*)e; + switch (te->event) + { + case FSM_ENTRY_SIG: + { + s->code = 0; + break; + } + case UP_SIG: + { + s->code <<= 1; + s->code |= 1; + break; + } + case DOWN_SIG: + { + s->code <<= 1; + break; + } + case ARM_SIG: + { + if (s->code == s->defuse) + { + FSM_TRAN(s, &bomb_setting); + break; + } + } + } +} + +static void fsm_test1(abts_case *tc, void *data) +{ + bomb_t bomb; + tick_event_t tick_event; + + bomb_create(&bomb, 14); + + fsm_init((fsm_t *)&bomb, (fsm_event_t*)0); + ABTS_PTR_EQUAL(tc, &bomb_setting, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 10, bomb.timeout); + + tick_event.event = UP_SIG; + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_setting, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 11, bomb.timeout); + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_setting, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 12, bomb.timeout); + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_setting, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 12, bomb.timeout); + + tick_event.event = DOWN_SIG; + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_setting, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 11, bomb.timeout); + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_setting, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 10, bomb.timeout); + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_setting, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 9, bomb.timeout); + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_setting, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 8, bomb.timeout); + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_setting, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 8, bomb.timeout); + + tick_event.event = ARM_SIG; + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_timing, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 0, bomb.code); + + tick_event.event = UP_SIG; + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_timing, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 1, bomb.code); + + tick_event.event = UP_SIG; + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_timing, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 3, bomb.code); + + tick_event.event = UP_SIG; + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_timing, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 7, bomb.code); + + tick_event.event = DOWN_SIG; + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_timing, ((fsm_t*)&bomb)->state); + ABTS_INT_EQUAL(tc, 14, bomb.code); + + tick_event.event = ARM_SIG; + fsm_dispatch((fsm_t *)&bomb, (fsm_event_t*)&tick_event); + ABTS_PTR_EQUAL(tc, &bomb_setting, ((fsm_t*)&bomb)->state); +} + +enum alarm_signal_t { + TICK_SIG = FSM_USER_SIG, + ALARM_SET_SIG, + ALARM_ON_SIG, + ALARM_OFF_SIG, + ALARM_SIG, + CLOCK_12H_SIG, + CLOCK_24H_SIG, + TIME_SIG, + TERMINATE_SIG +}; + +typedef struct _alarm_t { + fsm_t fsm; + c_uint32_t time; +} alarm_t; + +typedef struct _set_event_t { + fsm_event_t event; + c_uint8_t digit; +} set_event_t; + +typedef struct _time_event_t { + fsm_event_t event; + c_uint8_t current_time; +} time_event_t; + +void alarm_initial(alarm_t *s, fsm_event_t *e); +void alarm_off(alarm_t *s, fsm_event_t *e); +void alarm_on(alarm_t *s, fsm_event_t *e); + +void alarm_initial(alarm_t *s, fsm_event_t *e) +{ + s->time = 12*60; + FSM_TRAN(s, &alarm_off); +} + +void alarm_off(alarm_t *s, fsm_event_t *e) +{ + set_event_t *ae = (set_event_t*)e; + switch (ae->event) + { + case FSM_ENTRY_SIG: + { + s->time = (s->time/60)*100 + s->time%60; + break; + } + case FSM_EXIT_SIG: + { + s->time = (s->time/100)*60 + s->time%100; + break; + } + case ALARM_ON_SIG: + { + FSM_TRAN(s, &alarm_on); + break; + } + case ALARM_SET_SIG: + { + c_uint32_t alarm = (10 * s->time + + ae->digit) % 10000; + if ((alarm / 100 < 24) && (alarm % 100 < 60)) + { + s->time = alarm; + } + else + { + s->time = 0; + } + break; + } + } +} + +void alarm_on(alarm_t *s, fsm_event_t *e) +{ + time_event_t *ae = (time_event_t*)e; + switch (ae->event) + { + case FSM_ENTRY_SIG: + { + break; + } + case ALARM_SET_SIG: + { + break; + } + case ALARM_OFF_SIG: + { + FSM_TRAN(s, &alarm_off); + break; + } + } +} + +static void fsm_test2(abts_case *tc, void *data) +{ + alarm_t alarm; + set_event_t set_event; + time_event_t time_event; + + fsm_create((fsm_t *)&alarm, (fsm_handler_t)&alarm_initial, (fsm_handler_t)0); + + fsm_init((fsm_t *)&alarm, (fsm_event_t*)0); + ABTS_PTR_EQUAL(tc, &alarm_off, ((fsm_t*)&alarm)->state); + ABTS_INT_EQUAL(tc, 1200, alarm.time); + + set_event.event = ALARM_ON_SIG; + fsm_dispatch((fsm_t *)&alarm, (fsm_event_t*)&set_event); + ABTS_PTR_EQUAL(tc, &alarm_on, ((fsm_t*)&alarm)->state); + ABTS_INT_EQUAL(tc, 720, alarm.time); + + time_event.event = ALARM_OFF_SIG; + fsm_dispatch((fsm_t *)&alarm, (fsm_event_t*)&time_event); + ABTS_PTR_EQUAL(tc, &alarm_off, ((fsm_t*)&alarm)->state); + ABTS_INT_EQUAL(tc, 1200, alarm.time); + + set_event.event = ALARM_SET_SIG; + set_event.digit = 0; + fsm_dispatch((fsm_t *)&alarm, (fsm_event_t*)&set_event); + ABTS_PTR_EQUAL(tc, &alarm_off, ((fsm_t*)&alarm)->state); + ABTS_INT_EQUAL(tc, 2000, alarm.time); +} + +abts_suite *testfsm(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, fsm_test1, NULL); + abts_run_test(suite, fsm_test2, NULL); + + return suite; +} diff --git a/lib/core/test/testlock.c b/lib/core/test/testlock.c new file mode 100644 index 0000000000..5df5dd2c99 --- /dev/null +++ b/lib/core/test/testlock.c @@ -0,0 +1,393 @@ +#include "core_thread.h" +#include "core_mutex.h" +#include "core_cond.h" +#include "core_rwlock.h" +#include "core_semaphore.h" +#include "core_time.h" +#include "testutil.h" + +#define MAX_ITER 40000 +#define MAX_COUNTER 10000 +#define MAX_RETRY 3 + +static void *THREAD_FUNC thread_rwlock_func(void *data); +static void *THREAD_FUNC thread_mutex_function(void *data); +static void *THREAD_FUNC thread_cond_producer(void *data); +static void *THREAD_FUNC thread_cond_consumer(void *data); + +static mutex_id mutex; +static rwlock_id rwlock; +static semaphore_id semaphore; +static int i = 0, x = 0; + +static int buff[MAX_COUNTER]; + +struct { + mutex_id mutex; + int nput; + int nval; +} put; + +struct { + mutex_id mutex; + cond_id cond; + int nready; +} nready; + +static mutex_id timeout_mutex; +static cond_id timeout_cond; + +static void *THREAD_FUNC thread_rwlock_func(void *data) +{ + int exitLoop = 1; + + while (1) + { + rwlock_rdlock(rwlock); + if (i == MAX_ITER) + exitLoop = 0; + rwlock_unlock(rwlock); + + if (!exitLoop) + break; + + rwlock_wrlock(rwlock); + if (i != MAX_ITER) + { + i++; + x++; + } + rwlock_unlock(rwlock); + } + return NULL; +} + +static void *THREAD_FUNC thread_mutex_function(void *data) +{ + int exitLoop = 1; + + /* slight delay to allow things to settle */ + core_sleep (1); + + while (1) + { + mutex_lock(mutex); + if (i == MAX_ITER) + exitLoop = 0; + else + { + i++; + x++; + } + mutex_unlock(mutex); + + if (!exitLoop) + break; + } + return NULL; +} + +static void *THREAD_FUNC thread_cond_producer(void *data) +{ + for (;;) + { + mutex_lock(put.mutex); + if (put.nput >= MAX_COUNTER) + { + mutex_unlock(put.mutex); + return NULL; + } + buff[put.nput] = put.nval; + put.nput++; + put.nval++; + mutex_unlock(put.mutex); + + mutex_lock(nready.mutex); + if (nready.nready == 0) + cond_signal(nready.cond); + nready.nready++; + mutex_unlock(nready.mutex); + + *((int *) data) += 1; + } + + return NULL; +} + +static void *THREAD_FUNC thread_cond_consumer(void *data) +{ + int i; + + for (i = 0; i < MAX_COUNTER; i++) + { + mutex_lock(nready.mutex); + while (nready.nready == 0) + cond_wait(nready.cond, nready.mutex); + nready.nready--; + mutex_unlock(nready.mutex); + + if (buff[i] != i) + printf("buff[%d] = %d\n", i, buff[i]); + } + + return NULL; +} + +static void *THREAD_FUNC thread_semaphore_function(void *data) +{ + int exitLoop = 1; + + /* slight delay to allow things to settle */ + core_sleep (1); + + while (1) + { + semaphore_wait(semaphore); + if (i == MAX_ITER) + exitLoop = 0; + else + { + i++; + x++; + } + semaphore_post(semaphore); + + if (!exitLoop) + break; + } + return NULL; +} + +static void test_mutex(abts_case *tc, void *data) +{ + thread_id t1, t2, t3, t4; + status_t s1, s2, s3, s4; + + s1 = mutex_create(&mutex, MUTEX_DEFAULT); + ABTS_INT_EQUAL(tc, CORE_OK, s1); + + i = 0; + x = 0; + + s1 = thread_create(&t1, NULL, thread_mutex_function, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, s1); + s2 = thread_create(&t2, NULL, thread_mutex_function, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, s2); + s3 = thread_create(&t3, NULL, thread_mutex_function, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, s3); + s4 = thread_create(&t4, NULL, thread_mutex_function, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, s4); + + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t1)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t2)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t3)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t4)); + + ABTS_INT_EQUAL(tc, MAX_ITER, x); + + CORE_ASSERT_OK(tc, "delete mutex", mutex_delete(mutex)); +} + +static void test_thread_rwlock(abts_case *tc, void *data) +{ + thread_id t1, t2, t3, t4; + status_t s1, s2, s3, s4; + + s1 = rwlock_create(&rwlock); + if (s1 == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "rwlocks not implemented"); + return; + } + CORE_ASSERT_OK(tc, "rwlock_create", s1); + + i = 0; + x = 0; + + s1 = thread_create(&t1, NULL, thread_rwlock_func, NULL); + CORE_ASSERT_OK(tc, "create thread 1", s1); + s2 = thread_create(&t2, NULL, thread_rwlock_func, NULL); + CORE_ASSERT_OK(tc, "create thread 2", s2); + s3 = thread_create(&t3, NULL, thread_rwlock_func, NULL); + CORE_ASSERT_OK(tc, "create thread 3", s3); + s4 = thread_create(&t4, NULL, thread_rwlock_func, NULL); + CORE_ASSERT_OK(tc, "create thread 4", s4); + + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t1)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t2)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t3)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t4)); + + ABTS_INT_EQUAL(tc, MAX_ITER, x); + + CORE_ASSERT_OK(tc, "delete rwlock", rwlock_delete(rwlock)); +} + +static void test_cond(abts_case *tc, void *data) +{ + thread_id p1, p2, p3, p4, c1; + status_t s0, s1, s2, s3, s4; + int count1, count2, count3, count4; + int sum; + + CORE_ASSERT_OK(tc, "create put mutex", + mutex_create(&put.mutex, MUTEX_DEFAULT)); + + CORE_ASSERT_OK(tc, "create nready mutex", + mutex_create(&nready.mutex, MUTEX_DEFAULT)); + + CORE_ASSERT_OK(tc, "create condvar", + cond_create(&nready.cond)); + + count1 = count2 = count3 = count4 = 0; + put.nput = put.nval = 0; + nready.nready = 0; + i = 0; + x = 0; + + s0 = thread_create(&p1, NULL, thread_cond_producer, &count1); + ABTS_INT_EQUAL(tc, CORE_OK, s0); + s1 = thread_create(&p2, NULL, thread_cond_producer, &count2); + ABTS_INT_EQUAL(tc, CORE_OK, s1); + s2 = thread_create(&p3, NULL, thread_cond_producer, &count3); + ABTS_INT_EQUAL(tc, CORE_OK, s2); + s3 = thread_create(&p4, NULL, thread_cond_producer, &count4); + ABTS_INT_EQUAL(tc, CORE_OK, s3); + s4 = thread_create(&c1, NULL, thread_cond_consumer, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, s4); + + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(p1)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(p2)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(p3)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(p4)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(c1)); + + CORE_ASSERT_OK(tc, "delete condvar", + cond_delete(nready.cond)); + CORE_ASSERT_OK(tc, "delete ready mutex", mutex_delete(nready.mutex)); + CORE_ASSERT_OK(tc, "delete put mutex", mutex_delete(put.mutex)); + + sum = count1 + count2 + count3 + count4; + ABTS_INT_EQUAL(tc, MAX_COUNTER, sum); +} + +static void test_timeoutcond(abts_case *tc, void *data) +{ + status_t s; + c_time_t timeout; + c_time_t begin, end; + int i; + + s = mutex_create(&timeout_mutex, MUTEX_DEFAULT); + ABTS_INT_EQUAL(tc, CORE_OK, s); + + s = cond_create(&timeout_cond); + ABTS_INT_EQUAL(tc, CORE_OK, s); + + timeout = time_from_sec(1); + + for (i = 0; i < MAX_RETRY; i++) + { + mutex_lock(timeout_mutex); + + begin = time_now(); + s = cond_timedwait(timeout_cond, timeout_mutex, timeout); + end = time_now(); + mutex_unlock(timeout_mutex); + + if (s != CORE_OK && !STATUS_IS_TIMEUP(s)) + { + continue; + } + ABTS_INT_EQUAL(tc, 1, STATUS_IS_TIMEUP(s)); + ABTS_ASSERT(tc, + "Timer returned too late", end - begin - timeout < 100000); + break; + } + ABTS_ASSERT(tc, "Too many retries", i < MAX_RETRY); + CORE_ASSERT_OK(tc, "Unable to delete the conditional", + cond_delete(timeout_cond)); + CORE_ASSERT_OK(tc, "Unable to delete the mutex", + mutex_delete(timeout_mutex)); +} + +static void test_semaphore(abts_case *tc, void *data) +{ + thread_id t1, t2, t3, t4; + status_t s1, s2, s3, s4; + + s1 = semaphore_create(&semaphore, 1); + ABTS_INT_EQUAL(tc, CORE_OK, s1); + + i = 0; + x = 0; + + s1 = thread_create(&t1, NULL, thread_semaphore_function, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, s1); + s2 = thread_create(&t2, NULL, thread_semaphore_function, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, s2); + s3 = thread_create(&t3, NULL, thread_semaphore_function, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, s3); + s4 = thread_create(&t4, NULL, thread_semaphore_function, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, s4); + + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t1)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t2)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t3)); + ABTS_INT_EQUAL(tc, CORE_OK, thread_delete(t4)); + + ABTS_INT_EQUAL(tc, MAX_ITER, x); + + CORE_ASSERT_OK(tc, "delete semaphore", semaphore_delete(semaphore)); +} + +#if HAVE_SEM_TIMEDWAIT +static semaphore_id timeout_semaphore; +static void test_timeoutsemaphore(abts_case *tc, void *data) +{ + status_t s; + c_time_t timeout; + c_time_t begin, end; + int i; + + s = semaphore_create(&timeout_semaphore, 0); + ABTS_INT_EQUAL(tc, CORE_OK, s); + + timeout = time_from_sec(1); + + for (i = 0; i < MAX_RETRY; i++) + { + begin = time_now(); + s = semaphore_timedwait(timeout_semaphore, timeout); + end = time_now(); + + if (s != CORE_OK && !STATUS_IS_TIMEUP(s)) + { + continue; + } + ABTS_INT_EQUAL(tc, 1, STATUS_IS_TIMEUP(s)); + ABTS_ASSERT(tc, + "Timer returned too late", end - begin - timeout < 100000); + break; + } + ABTS_ASSERT(tc, "Too many retries", i < MAX_RETRY); + CORE_ASSERT_OK(tc, "Unable to delete the semaphore", + semaphore_delete(timeout_semaphore)); +} +#endif + +abts_suite *testlock(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_mutex, NULL); + abts_run_test(suite, test_thread_rwlock, NULL); + abts_run_test(suite, test_cond, NULL); + abts_run_test(suite, test_timeoutcond, NULL); + abts_run_test(suite, test_semaphore, NULL); +#if HAVE_SEM_TIMEDWAIT + abts_run_test(suite, test_timeoutsemaphore, NULL); +#endif + + return suite; +} diff --git a/lib/core/test/testmsgq.c b/lib/core/test/testmsgq.c new file mode 100644 index 0000000000..474fead625 --- /dev/null +++ b/lib/core/test/testmsgq.c @@ -0,0 +1,188 @@ +#include "core_msgq.h" +#include "testutil.h" + +#if 0 +static thread_id *s1; +static thread_id *r1; + +static void *THREAD_FUNC thread_send(void *data); +static void *THREAD_FUNC thread_recv(void *data); + +static void *THREAD_FUNC thread_send(void *data) +{ + +} + +static void *THREAD_FUNC thread_recv(void *data) +{ + +} +#endif + +char msg[16][24] = { + {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}, + {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28}, + {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, + {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}, + {0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58}, + {0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, + {0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78}, + {0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88}, + {0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98}, + {0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8}, + {0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8}, + {0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8}, + {0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8}, + {0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8}, + {0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8}, + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} +}; + +char rmsg[16][24]; + +int msglen[16] = {3, 4, 5, 6, 7, 8, 1, 2, 11, 12, 13, 14, 15, 16, 17, 18}; + +msgq_id md; + +static void msgq_test1(abts_case *tc, void *data) +{ + int i, n; + + msgq_init(); + + /* Basic test */ + md = msgq_create(5, 8, 0); + ABTS_INT_NEQUAL(tc, 0, md); + + n = msgq_send(md, msg[0], msglen[0]); + ABTS_INT_EQUAL(tc, msglen[0], n); + + n = msgq_recv(md, rmsg[0], 8); + ABTS_INT_EQUAL(tc, msglen[0], n); + + n = memcmp(msg[0], rmsg[0], msglen[0]); + ABTS_INT_EQUAL(tc, 0, n); + + msgq_delete(md); + + /* Test with send() and recv() function up to queue size */ + md = msgq_create(5, 8, 0); + ABTS_INT_NEQUAL(tc, 0, md); + + for (i = 0; i < 5; i++) + { + n = msgq_send(md, msg[i], msglen[i]); + ABTS_INT_EQUAL(tc, msglen[i], n); + } + + for (i = 0; i < 5; i++) + { + n = msgq_recv(md, rmsg[i], 8); + ABTS_INT_EQUAL(tc, msglen[i], n); + + n = memcmp(msg[i], rmsg[i], msglen[i]); + ABTS_INT_EQUAL(tc, 0, n); + } + + msgq_delete(md); + + /* Test with send() and timedrecv() function up to queue size */ + md = msgq_create(5, 8, 0); + ABTS_INT_NEQUAL(tc, 0, md); + + for (i = 0; i < 5; i++) + { + n = msgq_send(md, msg[i], msglen[i]); + ABTS_INT_EQUAL(tc, msglen[i], n); + } + + for (i = 0; i < 5; i++) + { + n = msgq_timedrecv(md, rmsg[i], 8, 0); + ABTS_INT_EQUAL(tc, msglen[i], n); + + n = memcmp(msg[i], rmsg[i], msglen[i]); + ABTS_INT_EQUAL(tc, 0, n); + } + + msgq_delete(md); +} + +static void msgq_test2(abts_case *tc, void *data) +{ + int i, n; + + msgq_init(); + + md = msgq_create(5, 8, MSGQ_O_NONBLOCK); + ABTS_INT_NEQUAL(tc, 0, md); + + /* fill up the queue */ + for (i = 0; i < 5; i++) + { + n = msgq_send(md, msg[i], msglen[i]); + ABTS_INT_EQUAL(tc, msglen[i], n); + } + + /* Now, there is no room to send. + * Confirm that send() returns CORE_EGAIN */ + n = msgq_send(md, msg[0], msglen[0]); + ABTS_INT_EQUAL(tc, CORE_EAGAIN, n); + + /* empty queue */ + for (i = 0; i < 5; i++) + { + n = msgq_recv(md, rmsg[i], 8); + ABTS_INT_EQUAL(tc, msglen[i], n); + + n = memcmp(msg[i], rmsg[i], msglen[i]); + ABTS_INT_EQUAL(tc, 0, n); + } + + /* Now, there is no sent buffer to be read. + * Confirm that recv() return CORE_EGAIN */ + n = msgq_recv(md, rmsg[i], 8); + ABTS_INT_EQUAL(tc, CORE_EAGAIN, n); + + msgq_delete(md); +} + +static void msgq_test3(abts_case *tc, void *data) +{ + int i, j, n; + + msgq_init(); + + md = msgq_create(16, 24, MSGQ_O_BLOCK); + ABTS_INT_NEQUAL(tc, 0, md); + + /* Repeat 10 times */ + for (j = 0; j < 10; j++) + { + /* Cycle repeatedly by queue depth */ + for (i = 0; i < 16; i++) + { + n = msgq_send(md, msg[i], 24); + ABTS_INT_EQUAL(tc, 24, n); + + n = msgq_recv(md, rmsg[i], 24); + ABTS_INT_EQUAL(tc, 24, n); + + n = memcmp(msg[i], rmsg[i], 24); + ABTS_INT_EQUAL(tc, 0, n); + } + } + + msgq_delete(md); +} + +abts_suite *testmsgq(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, msgq_test1, NULL); + abts_run_test(suite, msgq_test2, NULL); + abts_run_test(suite, msgq_test3, NULL); + + return suite; +} diff --git a/lib/core/test/testnetlib.c b/lib/core/test/testnetlib.c new file mode 100644 index 0000000000..bc41ccd33d --- /dev/null +++ b/lib/core/test/testnetlib.c @@ -0,0 +1,835 @@ +#define TRACE_MODULE _testnetlib +#include "core_debug.h" +#include "core_net.h" +#include "testutil.h" + +#define TEST_SERVER_PORT 5121 +#define TEST_BUFFER_SIZE 1024 + +#define TEST_MAX_NUM 4 + +#define DISABLE_FTPTEST 1 +#define DISABLE_LINKTEST 1 + +static char buffer[TEST_BUFFER_SIZE]; +static int tcp_server_started = 0; +static int udp_server_started = 0; +static int sctp_stream_server_started = 0; +static int sctp_seq_server_started = 0; + +pthread_t tserver_tid,userver_tid,streamserver_tid, seqserver_tid; +net_sock_t *tserver_sock,*userver_sock,*streamserver_sock,*seqserver_sock; + +static void *tcp_session_main(void *param) +{ + int rc; + + net_sock_t *net_sock = (net_sock_t *)param; + while (1) + { + rc = net_read(net_sock, buffer, TEST_BUFFER_SIZE, 1); + if (rc > 0) + { + if (!strncmp(buffer, "QUIT",4)) + { + break; + } + else + { + /* Send received data */ + rc = net_send(net_sock, buffer, rc); + } + } + else if (rc == 0) + { + /* Timeout */ + } + else + { + printf("error = %d\n", net_sock->sndrcv_errno); + break; + } + } + + net_close(net_sock); + + return NULL; +} + +static void start_tcp_session(net_sock_t *net_sock) +{ + pthread_t tid; + + pthread_create(&tid, NULL, tcp_session_main, (void *)net_sock); + pthread_detach(tid); + return; +} + +static void *tcp_server_main(void *param) +{ + int rc; + net_sock_t *new_sock; + + rc = net_listen(&tserver_sock, SOCK_STREAM, IPPROTO_TCP, TEST_SERVER_PORT); + if (rc != 0) + { + d_error("net_tcp_listen Error(rc = %d)\n",rc); + return NULL; + } + + tcp_server_started = 1; + + while (1) + { + rc = net_accept(&new_sock, tserver_sock, 1); + if (rc >0) + { + /* New connection arrived. Start session */ + start_tcp_session(new_sock); + } + else if (rc == 0) + { + /* Timeout */ + } + else + { + /* Error occured */ + break; + } + } + + return NULL; +} + +static void start_tcp_server() +{ + pthread_create(&tserver_tid, NULL, tcp_server_main, NULL); + while (tcp_server_started == 0) + { + sleep(1); + } + return; +} + +static void stop_tcp_server() +{ + net_close(tserver_sock); + pthread_join(tserver_tid, NULL); +} + +static void *udp_server_main(void *param) +{ + int rc; + + rc = net_listen(&userver_sock, + SOCK_DGRAM, IPPROTO_UDP, TEST_SERVER_PORT); + if (rc != 0) + { + d_error("net_udp Error(rc = %d)\n",rc); + return NULL; + } + + udp_server_started = 1; + + while (1) + { + d_trace(1,"Wait for data....\n"); + rc = net_read(userver_sock, buffer, TEST_BUFFER_SIZE, 2); + if (rc >0) + { + d_trace(1,"RECV %d bytes\n", rc); + if (!strncmp(buffer, "QUIT",4)) + { + break; + } + else + { + /* Send received data */ + rc = net_send(userver_sock, buffer, rc); + d_trace(1,"SEND %d bytes\n", rc); + if (rc == -1) + { + printf("error = %d\n", userver_sock->sndrcv_errno); + } + } + } + else if (rc == 0) + { + /* Timeout */ + } + else + { + /* Error occured */ + break; + } + } + + return NULL; +} + +static void start_udp_server() +{ + pthread_create(&userver_tid, NULL, udp_server_main, NULL); + while (udp_server_started == 0) + { + sleep(1); + } + return; +} + +static void stop_udp_server() +{ + net_close(userver_sock); + pthread_join(userver_tid, NULL); +} + +static void *sctp_stream_session_main(void *param) +{ + int rc; + + net_sock_t *net_sock = (net_sock_t *)param; + while (1) + { + rc = net_read(net_sock, buffer, TEST_BUFFER_SIZE, 1); + if (rc > 0) + { + if (!strncmp(buffer, "QUIT",4)) + { + break; + } + else + { + /* Send received data */ + rc = net_send(net_sock, buffer, rc); + } + } + else if (rc == 0) + { + /* Timeout */ + } + else + { + if (rc != -2 && net_sock->sndrcv_errno != EAGAIN) + break; + } + } + + net_close(net_sock); + + return NULL; +} + +static void start_stream_sctp_session(net_sock_t *net_sock) +{ + pthread_t tid; + + pthread_create(&tid, NULL, sctp_stream_session_main, (void *)net_sock); + pthread_detach(tid); + return; +} + +static void *sctp_stream_server_main(void *param) +{ + int rc; + net_sock_t *new_sock; + + rc = net_listen(&streamserver_sock, + SOCK_STREAM, IPPROTO_SCTP, TEST_SERVER_PORT); + if (rc != 0) + { + d_error("net_sctp_listen Error(rc = %d)\n",rc); + return NULL; + } + + sctp_stream_server_started = 1; + + while (1) + { + rc = net_accept(&new_sock, streamserver_sock, 1); + if (rc >0) + { + /* New connection arrived. Start session */ + start_stream_sctp_session(new_sock); + } + else if (rc == 0) + { + /* Timeout */ + } + else + { + /* Error occured */ + break; + } + } + + return NULL; +} + +static void start_stream_sctp_server() +{ + pthread_create(&streamserver_tid, NULL, sctp_stream_server_main, NULL); + while (sctp_stream_server_started == 0) + { + sleep(1); + } + return; +} + +static void stop_stream_sctp_server() +{ + net_close(streamserver_sock); + pthread_join(streamserver_tid, NULL); +} + +static void *sctp_seq_server_main(void *param) +{ + int rc; + + rc = net_listen(&seqserver_sock, + SOCK_SEQPACKET, IPPROTO_SCTP, TEST_SERVER_PORT); + if (rc != 0) + { + d_error("net_sctp Error(rc = %d)\n",rc); + return NULL; + } + + sctp_seq_server_started = 1; + + while (1) + { + d_trace(1,"Wait for data....\n"); + rc = net_read(seqserver_sock, buffer, TEST_BUFFER_SIZE, 2); + if (rc >0) + { + d_trace(1,"RECV %d bytes\n", rc); + if (!strncmp(buffer, "QUIT",4)) + { + break; + } + else + { + /* Send received data */ + rc = net_send(seqserver_sock, buffer, rc); + d_trace(1,"SEND %d bytes\n", rc); + if (rc == -1) + { + printf("error = %d\n", seqserver_sock->sndrcv_errno); + } + } + } + else if (rc == 0) + { + /* Timeout */ + } + else + { + /* Error occured */ + if (rc != -2 && seqserver_sock->sndrcv_errno != EAGAIN) + break; + } + } + + return NULL; +} + +static void start_seq_sctp_server() +{ + pthread_create(&seqserver_tid, NULL, sctp_seq_server_main, NULL); + while (sctp_seq_server_started == 0) + { + sleep(1); + } + return; +} + +static void stop_seq_sctp_server() +{ + net_close(seqserver_sock); + pthread_join(seqserver_tid, NULL); +} + +static void netlib1(abts_case *tc, void *data) +{ + int rc = 0; + net_sock_t *net_sock; + char inputbuf[TEST_MAX_NUM][20]; + char outputbuf[TEST_MAX_NUM][20]; + int i; + + /* Start TCP server */ + start_tcp_server(); + + rc = net_open(&net_sock, "127.0.0.1", 0, + TEST_SERVER_PORT, SOCK_STREAM, IPPROTO_TCP, 0); + ABTS_INT_EQUAL(tc, 0, rc); + for (i=0; i< TEST_MAX_NUM; i++) + { + sprintf(inputbuf[i],"asdf%d",i); + rc = net_send(net_sock, inputbuf[i], strlen(inputbuf[i])+1); + ABTS_INT_EQUAL(tc, strlen(inputbuf[i])+1, rc); + } + + for (i=0; i< TEST_MAX_NUM; i++) + { + memset(outputbuf[i], 0, sizeof(outputbuf[i])); + rc = 0; + while (1) + { + int n; + n = net_read(net_sock, outputbuf[i], 6, 1); + rc += n; + if (n == 0 || n == 6) + break; + } + ABTS_INT_EQUAL(tc, 6, rc); + ABTS_INT_EQUAL(tc, 6, strlen(outputbuf[i])+1); + ABTS_STR_EQUAL(tc, inputbuf[i], outputbuf[i]); + } + /* Send QUIT */ + rc = net_send(net_sock, "QUIT", 4); + ABTS_INT_EQUAL(tc, 4, rc); + + /* Close */ + rc = net_close(net_sock); + ABTS_INT_EQUAL(tc, 0, rc); + + /* Stop TCP server */ + stop_tcp_server(); +} + +static void netlib2(abts_case *tc, void *data) +{ + int rc = 0; + net_sock_t *net_sock[TEST_MAX_NUM]; + char inputbuf[TEST_MAX_NUM][20]; + char outputbuf[TEST_MAX_NUM][20]; + int i; + + /* Start TCP server */ + start_tcp_server(); + + /* Connect to invalid port */ + for (i =0 ; isndrcv_errno == EAGAIN) + continue; + rc += n; + if (n == 0 || n == 6) + break; + } + ABTS_INT_EQUAL(tc, 6, rc); + ABTS_INT_EQUAL(tc, 6, strlen(outputbuf[i])+1); + ABTS_STR_EQUAL(tc, inputbuf[i], outputbuf[i]); + } + + for (i = 0 ; i< TEST_MAX_NUM; i++) + { + rc = net_close(net_sock[i]); + ABTS_INT_EQUAL(tc, 0, rc); + } + + stop_stream_sctp_server(); +} + +static void netlib5(abts_case *tc, void *data) +{ + int rc = 0; + net_sock_t *net_sock[TEST_MAX_NUM]; + char inputbuf[TEST_MAX_NUM][25]; + char outputbuf[TEST_MAX_NUM][25]; + int i; + + /* Connect to invalid port. + * In SCTP cases, net_open should be success always + */ + for (i =0 ; isndrcv_errno == EAGAIN) + continue; + rc += n; + if (n == 0 || n == 6) + break; + } + ABTS_INT_EQUAL(tc, 6, rc); + ABTS_INT_EQUAL(tc, 6, strlen(outputbuf[i])+1); + ABTS_STR_EQUAL(tc, inputbuf[i], outputbuf[i]); + } + + for (i = 0 ; i< TEST_MAX_NUM; i++) + { + rc = net_close(net_sock[i]); + ABTS_INT_EQUAL(tc, 0, rc); + } + + stop_seq_sctp_server(); +} + +static void netlib6(abts_case *tc, void *data) +{ + int rc; + net_ftp_t *ftp_session = NULL; + char *homedir = NULL; + int remote_size = 0; + int local_size = 0; + char host[] = "127.0.0.1:21"; + int i; + +#if DISABLE_FTPTEST + return; +#endif + rc = net_ftp_open(host, + "susia", + "ich3lie", + 0,&ftp_session); + ABTS_INT_EQUAL(tc, 0, rc); + ABTS_PTR_NOTNULL(tc, ftp_session); + + homedir = getenv("HOME"); + if (homedir) + { + char filename[100]; + struct stat statbuff; + sprintf(filename,"%s/.bashrc",homedir); + + if (stat(filename, &statbuff) == 0) + { + remote_size= statbuff.st_size; + } + } + rc = net_ftp_get(ftp_session,".bashrc",NULL); + ABTS_INT_EQUAL(tc, 0, rc); + { + struct stat statbuff; + + rc = stat(".bashrc", &statbuff); + ABTS_INT_EQUAL(tc, 0, rc); + local_size= statbuff.st_size; + ABTS_INT_EQUAL(tc, local_size, remote_size); + } + + for (i=0; i < 20; i++) + { + rc = net_ftp_get(ftp_session,".bashrc","bashrc"); + ABTS_INT_EQUAL(tc, 0, rc); + { + struct stat statbuff; + rc = stat("bashrc", &statbuff); + ABTS_INT_EQUAL(tc, 0, rc); + local_size= statbuff.st_size; + ABTS_INT_EQUAL(tc, local_size, remote_size); + } + rc = net_ftp_put(ftp_session,"bashrc", NULL); + ABTS_INT_EQUAL(tc, 0, rc); + + unlink("bashrc"); + } + + rc = net_ftp_quit(ftp_session); + ABTS_INT_EQUAL(tc, 0, rc); + + rc = net_ftp_close(ftp_session); + ABTS_INT_EQUAL(tc, 0, rc); +} + +#if LINUX == 1 +static void filter_updu(char *buf, int len) +{ + unsigned short proto = 0x88B6; + struct ethhdr *eth_hdr = NULL; + + eth_hdr = (struct ethhdr *)buf; + if (ntohs(eth_hdr->h_proto) == proto) + { + d_print_hex(buf, len); + } +} + +static void netlib7(abts_case *tc, void *data) +{ + net_link_t *net_link = NULL; + int promisc = 1; + int rc; + int max_count = 10; + char buf[1024]; + +#if DISABLE_LINKTEST + return; +#endif + rc = net_link_open(&net_link, "eth0", ETH_P_ALL); + ABTS_INT_EQUAL(tc, 0, rc); + ABTS_PTR_NOTNULL(tc, net_link); + rc = net_link_promisc(net_link, promisc); + ABTS_INT_EQUAL(tc, 0, rc); +#if 0 + d_print("HW addr of %s : ",net_link->ifname); + d_print_hex(net_link->hwaddr.sa_data, 6); +#endif + while (max_count-- > 0) + { + rc = net_link_read(net_link, buf, 1024, 1); + ABTS_TRUE(tc, rc > 0); + filter_updu(buf, rc); + } + rc = net_link_close(net_link); + ABTS_INT_EQUAL(tc, 0, rc); +} + +static int make_test_updu(char *src_addr, char *dst_addr, char *buf, int len) +{ + unsigned short proto = 0x88B6; + struct ethhdr *eth_hdr = NULL; + int rc = sizeof(struct ethhdr); + char *ptr = buf; + + eth_hdr = (struct ethhdr *)buf; + memcpy(eth_hdr->h_source, src_addr, 6); + memcpy(eth_hdr->h_dest, dst_addr, 6); + eth_hdr->h_proto = htons(proto); + /* Fill the data */ + rc += sprintf(ptr+rc,"Hellow World"); + d_print_hex(buf, rc); + return rc; +} + +static void netlib8(abts_case *tc, void *data) +{ + net_link_t *net_link = NULL; + int promisc = 1; + int rc; + int max_count = 1; + char buf[1024]; +#if 0 + char dst_addr[6] = {'\x00','\x00','\x00','\x11','\x22','\x33'}; +#else + char dst_addr[6] = {'\xff','\xff','\xff','\xff','\xff','\xff'}; +#endif + +#if DISABLE_LINKTEST + return; +#endif + + rc = net_link_open(&net_link, "eth0", ETH_P_ALL); + ABTS_INT_EQUAL(tc, 0, rc); + ABTS_PTR_NOTNULL(tc, net_link); + rc = net_link_promisc(net_link, promisc); + ABTS_INT_EQUAL(tc, 0, rc); + while (max_count-- > 0) + { + rc = make_test_updu(net_link->hwaddr.sa_data, dst_addr,buf,1024); + + rc = net_link_write(net_link, buf, rc); + ABTS_TRUE(tc, rc > 0); + } + rc = net_link_close(net_link); + ABTS_INT_EQUAL(tc, 0, rc); +} +#endif + +abts_suite *testnetlib(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, netlib1, NULL); + abts_run_test(suite, netlib2, NULL); + abts_run_test(suite, netlib3, NULL); + abts_run_test(suite, netlib4, NULL); + abts_run_test(suite, netlib5, NULL); + abts_run_test(suite, netlib6, NULL); +#if LINUX == 1 + abts_run_test(suite, netlib7, NULL); + abts_run_test(suite, netlib8, NULL); +#endif + + return suite; +} diff --git a/lib/core/test/testsha.c b/lib/core/test/testsha.c new file mode 100644 index 0000000000..17d1643d82 --- /dev/null +++ b/lib/core/test/testsha.c @@ -0,0 +1,163 @@ +#include "core_debug.h" +#include "core_sha1.h" +#include "core_sha2.h" +#include "testutil.h" + +static void sha1_test1(abts_case *tc, void *data) +{ + c_uint8_t msg1[] = "abc"; + c_uint8_t msg2[] = "abcdbcdecdefdefgefghfghighij" + "hijkijkljklmklmnlmnomnopnopq"; + + c_uint8_t digest1[] = { + 0xa9,0x99,0x3e,0x36,0x47,0x06,0x81,0x6a, + 0xba,0x3e,0x25,0x71,0x78,0x50,0xc2,0x6c, + 0x9c,0xd0,0xd8,0x9d + }; + c_uint8_t digest2[] = { + 0x84,0x98,0x3e,0x44,0x1c,0x3b,0xd2,0x6e, + 0xba,0xae,0x4a,0xa1,0xf9,0x51,0x29,0xe5, + 0xe5,0x46,0x70,0xf1 + }; + c_uint8_t digest3[] = { + 0x34,0xaa,0x97,0x3c,0xd4,0xc4,0xda,0xa4, + 0xf6,0x1e,0xeb,0x2b,0xdb,0xad,0x27,0x31, + 0x65,0x34,0x01,0x6f, + }; + + c_uint8_t digest[20]; + int i; + + sha1_ctx ctx; + + sha1_init(&ctx); + sha1_update(&ctx, msg1, sizeof(msg1) - 1); + sha1_final(&ctx, digest); + ABTS_INT_EQUAL(tc, 0, memcmp(digest1, digest, 20)); + + sha1_init(&ctx); + sha1_update(&ctx, msg2, sizeof(msg2) - 1); + sha1_final(&ctx, digest); + ABTS_INT_EQUAL(tc, 0, memcmp(digest2, digest, 20)); + + sha1_init(&ctx); + for (i = 0; i < 1000000; i++) + sha1_update(&ctx, (c_uint8_t*)"a", 1); + sha1_final(&ctx, digest); + ABTS_INT_EQUAL(tc, 0, memcmp(digest3, digest, 20)); + +} + +static void sha2_test1(abts_case *tc, void *data) +{ + char *vectors[4][3] = + { /* SHA-224 */ + { + "\x23\x09\x7d\x22\x34\x05\xd8\x22\x86\x42\xa4\x77\xbd\xa2\x55\xb3\x2a\xad\xbc\xe4\xbd\xa0\xb3\xf7\xe3\x6c\x9d\xa7", + "\x75\x38\x8b\x16\x51\x27\x76\xcc\x5d\xba\x5d\xa1\xfd\x89\x01\x50\xb0\xc6\x45\x5c\xb4\xf5\x8b\x19\x52\x52\x25\x25", + "\x20\x79\x46\x55\x98\x0c\x91\xd8\xbb\xb4\xc1\xea\x97\x61\x8a\x4b\xf0\x3f\x42\x58\x19\x48\xb2\xee\x4e\xe7\xad\x67", + }, + /* SHA-\x25\x6 */ + { + "\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad", + "\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1", + "\xcd\xc7\x6e\x5c\x99\x14\xfb\x92\x81\xa1\xc7\xe2\x84\xd7\x3e\x67\xf1\x80\x9a\x48\xa4\x97\x20\x0e\x04\x6d\x39\xcc\xc7\x11\x2c\xd0", + }, + /* SHA-\x38\x4 */ + { + "\xcb\x00\x75\x3f\x45\xa3\x5e\x8b\xb5\xa0\x3d\x69\x9a\xc6\x50\x07\x27\x2c\x32\xab\x0e\xde\xd1\x63\x1a\x8b\x60\x5a\x43\xff\x5b\xed" + "\x80\x86\x07\x2b\xa1\xe7\xcc\x23\x58\xba\xec\xa1\x34\xc8\x25\xa7", + "\x09\x33\x0c\x33\xf7\x11\x47\xe8\x3d\x19\x2f\xc7\x82\xcd\x1b\x47\x53\x11\x1b\x17\x3b\x3b\x05\xd2\x2f\xa0\x80\x86\xe3\xb0\xf7\x12" + "\xfc\xc7\xc7\x1a\x55\x7e\x2d\xb9\x66\xc3\xe9\xfa\x91\x74\x60\x39", + "\x9d\x0e\x18\x09\x71\x64\x74\xcb\x08\x6e\x83\x4e\x31\x0a\x4a\x1c\xed\x14\x9e\x9c\x00\xf2\x48\x52\x79\x72\xce\xc5\x70\x4c\x2a\x5b" + "\x07\xb8\xb3\xdc\x38\xec\xc4\xeb\xae\x97\xdd\xd8\x7f\x3d\x89\x85", + }, + /* SHA-\x51\x2 */ + { + "\xdd\xaf\x35\xa1\x93\x61\x7a\xba\xcc\x41\x73\x49\xae\x20\x41\x31\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2\x0a\x9e\xee\xe6\x4b\x55\xd3\x9a" + "\x21\x92\x99\x2a\x27\x4f\xc1\xa8\x36\xba\x3c\x23\xa3\xfe\xeb\xbd\x45\x4d\x44\x23\x64\x3c\xe8\x0e\x2a\x9a\xc9\x4f\xa5\x4c\xa4\x9f", + "\x8e\x95\x9b\x75\xda\xe3\x13\xda\x8c\xf4\xf7\x28\x14\xfc\x14\x3f\x8f\x77\x79\xc6\xeb\x9f\x7f\xa1\x72\x99\xae\xad\xb6\x88\x90\x18" + "\x50\x1d\x28\x9e\x49\x00\xf7\xe4\x33\x1b\x99\xde\xc4\xb5\x43\x3a\xc7\xd3\x29\xee\xb6\xdd\x26\x54\x5e\x96\xe5\x5b\x87\x4b\xe9\x09", + "\xe7\x18\x48\x3d\x0c\xe7\x69\x64\x4e\x2e\x42\xc7\xbc\x15\xb4\x63\x8e\x1f\x98\xb1\x3b\x20\x44\x28\x56\x32\xa8\x03\xaf\xa9\x73\xeb" + "\xde\x0f\xf2\x44\x87\x7e\xa6\x0a\x4c\xb0\x43\x2c\xe5\x77\xc3\x1b\xeb\x00\x9c\x5c\x2c\x49\xaa\x2e\x4e\xad\xb2\x17\xad\x8c\xc0\x9b" + } + }; + + char message1[] = "abc"; + char message2a[] = "abcdbcdecdefdefgefghfghighijhi" + "jkijkljklmklmnlmnomnopnopq"; + char message2b[] = "abcdefghbcdefghicdefghijdefghijkefghij" + "klfghijklmghijklmnhijklmnoijklmnopjklm" + "nopqklmnopqrlmnopqrsmnopqrstnopqrstu"; + unsigned char *message3; + unsigned int message3_len = 1000000; + unsigned char digest[SHA512_DIGEST_SIZE]; + int rc; + + message3 = malloc(message3_len); + if (message3 == NULL) { + fprintf(stderr, "Can't allocate memory\n"); + return; + } + memset(message3, 'a', message3_len); + + /* SHA-2 FIPS 180-2 Validation tests. + * SHA-224 Test vector */ + + sha224((c_uint8_t *)message1, strlen((char *) message1), digest); + rc = memcmp(vectors[0][0], digest, SHA224_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + sha224((c_uint8_t *)message2a, strlen((char *) message2a), digest); + rc = memcmp(vectors[0][1], digest, SHA224_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + sha224((c_uint8_t *)message3, message3_len, digest); + rc = memcmp(vectors[0][2], digest, SHA224_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + + /* SHA-256 Test vector */ + + sha256((c_uint8_t *)message1, strlen((char *) message1), digest); + rc = memcmp(vectors[1][0], digest, SHA256_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + sha256((c_uint8_t *)message2a, strlen((char *) message2a), digest); + rc = memcmp(vectors[1][1], digest, SHA256_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + sha256((c_uint8_t *)message3, message3_len, digest); + rc = memcmp(vectors[1][2], digest, SHA256_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + + /* SHA-384 Test vector */ + + sha384((c_uint8_t *)message1, strlen((char *) message1), digest); + rc = memcmp(vectors[2][0], digest, SHA384_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + sha384((c_uint8_t *)message2b, strlen((char *) message2b), digest); + rc = memcmp(vectors[2][1], digest, SHA384_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + sha384((c_uint8_t *)message3, message3_len, digest); + rc = memcmp(vectors[2][2], digest, SHA384_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + + /* SHA-512 Test vector */ + sha512((c_uint8_t *)message1, strlen((char *) message1), digest); + rc = memcmp(vectors[3][0], digest, SHA512_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + sha512((c_uint8_t *)message2b, strlen((char *) message2b), digest); + rc = memcmp(vectors[3][1], digest, SHA512_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + sha512((c_uint8_t *)message3, message3_len, digest); + rc = memcmp(vectors[3][2], digest, SHA512_DIGEST_SIZE); + ABTS_INT_EQUAL(tc, 0, rc); + + free(message3); +} + +abts_suite *testsha2(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, sha1_test1, NULL); + abts_run_test(suite, sha2_test1, NULL); + + return suite; +} diff --git a/lib/core/test/testsleep.c b/lib/core/test/testsleep.c new file mode 100644 index 0000000000..acab57e485 --- /dev/null +++ b/lib/core/test/testsleep.c @@ -0,0 +1,47 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core_time.h" +#include "testutil.h" + +#define SLEEP_INTERVAL 3 + +static void sleep_one(abts_case *tc, void *data) +{ + time_t pretime = time(NULL); + time_t posttime; + time_t timediff; + + core_sleep(time_from_sec(SLEEP_INTERVAL)); + posttime = time(NULL); + + /* normalize the timediff. We should have slept for SLEEP_INTERVAL, so + * we should just subtract that out. + */ + timediff = posttime - pretime - SLEEP_INTERVAL; + ABTS_TRUE(tc, timediff >= 0); + ABTS_TRUE(tc, timediff <= 1); +} + +abts_suite *testsleep(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, sleep_one, NULL); + + return suite; +} + diff --git a/lib/core/test/testthread.c b/lib/core/test/testthread.c new file mode 100644 index 0000000000..9a022a040a --- /dev/null +++ b/lib/core/test/testthread.c @@ -0,0 +1,78 @@ +#include "core_mutex.h" +#include "core_thread.h" +#include "testutil.h" + +static mutex_id lock; +static int x = 0; + +static thread_id t1; +static thread_id t2; +static thread_id t3; +static thread_id t4; + +static void *THREAD_FUNC thread_func1(void *data) +{ + int i; + + for (i = 0; i < 10000; i++) + { + mutex_lock(lock); + x++; + mutex_unlock(lock); + } + return NULL; +} + +static void init_thread(abts_case *tc, void *data) +{ + status_t rv; + + rv = mutex_create(&lock, MUTEX_DEFAULT); + ABTS_INT_EQUAL(tc, CORE_OK, rv); +} + +static void create_threads(abts_case *tc, void *data) +{ + status_t rv; + + rv = thread_create(&t1, NULL, thread_func1, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + rv = thread_create(&t2, NULL, thread_func1, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + rv = thread_create(&t3, NULL, thread_func1, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, rv); + rv = thread_create(&t4, NULL, thread_func1, NULL); + ABTS_INT_EQUAL(tc, CORE_OK, rv); +} + +static void delete_threads(abts_case *tc, void *data) +{ + status_t s; + + s = thread_delete(t1); + ABTS_INT_EQUAL(tc, CORE_OK, s); + s = thread_delete(t2); + ABTS_INT_EQUAL(tc, CORE_OK, s); + s = thread_delete(t3); + ABTS_INT_EQUAL(tc, CORE_OK, s); + s = thread_delete(t4); + ABTS_INT_EQUAL(tc, CORE_OK, s); +} + +static void check_locks(abts_case *tc, void *data) +{ + ABTS_INT_EQUAL(tc, 40000, x); +} + +abts_suite *testthread(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, init_thread, NULL); + abts_run_test(suite, create_threads, NULL); + abts_run_test(suite, delete_threads, NULL); + abts_run_test(suite, check_locks, NULL); + + return suite; +} + diff --git a/lib/core/test/testtime.c b/lib/core/test/testtime.c new file mode 100644 index 0000000000..46bbf490e7 --- /dev/null +++ b/lib/core/test/testtime.c @@ -0,0 +1,289 @@ +#include "core_time.h" +#include "testutil.h" + +#define STR_SIZE 45 + +/* The time value is used throughout the tests, so just make this a global. + * Also, we need a single value that we can test for the positive tests, so + * I chose the number below, it corresponds to: + * 2002-08-14 12:05:36.186711 -25200 [257 Sat]. + * Which happens to be when I wrote the new tests. + */ +static c_time_t now = C_INT64_C(1032030336186711); + +static void test_now(abts_case *tc, void *data) +{ + c_time_t timediff; + c_time_t current; + time_t os_now; + + current = time_now(); + time(&os_now); + + timediff = os_now - (current / USEC_PER_SEC); + /* Even though these are called so close together, there is the chance + * that the time will be slightly off, so accept anything between -1 and + * 1 second. + */ + ABTS_ASSERT(tc, "core_time and OS time do not agree", + (timediff > -2) && (timediff < 2)); +} + +static void test_gmtstr(abts_case *tc, void *data) +{ + status_t rv; + time_exp_t xt; + char str[STR_SIZE+1]; + + rv = time_exp_gmt(&xt, now); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "time_exp_gmt"); + } + ABTS_TRUE(tc, rv == CORE_OK); + sprintf(str, "%04d-%02d-%02d %02d:%02d:%02d.%06d %+05d [%d %s]%s", + xt.tm_year + 1900, + xt.tm_mon, + xt.tm_mday, + xt.tm_hour, + xt.tm_min, + xt.tm_sec, + xt.tm_usec, + xt.tm_gmtoff, + xt.tm_yday + 1, + day_snames[xt.tm_wday], + (xt.tm_isdst ? " DST" : "")); + ABTS_STR_EQUAL(tc, "2002-08-14 19:05:36.186711 +0000 [257 Sat]", str); +} + +static void test_exp_lt(abts_case *tc, void *data) +{ + status_t rv; + time_exp_t xt; + time_t posix_secs = (time_t)time_sec(now); + struct tm *posix_exp = localtime(&posix_secs); + + rv = time_exp_lt(&xt, now); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "time_exp_lt"); + } + ABTS_TRUE(tc, rv == CORE_OK); + +#define CHK_FIELD(f) \ + ABTS_ASSERT(tc, "Mismatch in " #f, posix_exp->f == xt.f) + + CHK_FIELD(tm_sec); + CHK_FIELD(tm_min); + CHK_FIELD(tm_hour); + CHK_FIELD(tm_mday); + CHK_FIELD(tm_mon); + CHK_FIELD(tm_year); + CHK_FIELD(tm_wday); + CHK_FIELD(tm_yday); + CHK_FIELD(tm_isdst); +#undef CHK_FIELD +} + +static void test_exp_get_gmt(abts_case *tc, void *data) +{ + status_t rv; + time_exp_t xt; + c_time_t imp; + c_int64_t hr_off_64; + + rv = time_exp_gmt(&xt, now); + ABTS_TRUE(tc, rv == CORE_OK); + rv = time_exp_get(&imp, &xt); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "time_exp_get"); + } + ABTS_TRUE(tc, rv == CORE_OK); + hr_off_64 = (c_int64_t) xt.tm_gmtoff * USEC_PER_SEC; + ABTS_TRUE(tc, now + hr_off_64 == imp); +} + +static void test_exp_get_lt(abts_case *tc, void *data) +{ + status_t rv; + time_exp_t xt; + c_time_t imp; + c_int64_t hr_off_64; + + rv = time_exp_lt(&xt, now); + ABTS_TRUE(tc, rv == CORE_OK); + rv = time_exp_get(&imp, &xt); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "time_exp_get"); + } + ABTS_TRUE(tc, rv == CORE_OK); + hr_off_64 = (c_int64_t) xt.tm_gmtoff * USEC_PER_SEC; + ABTS_TRUE(tc, now + hr_off_64 == imp); +} + +static void test_imp_gmt(abts_case *tc, void *data) +{ + status_t rv; + time_exp_t xt; + c_time_t imp; + + rv = time_exp_gmt(&xt, now); + ABTS_TRUE(tc, rv == CORE_OK); + rv = time_exp_gmt_get(&imp, &xt); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "time_exp_gmt_get"); + } + ABTS_TRUE(tc, rv == CORE_OK); + ABTS_TRUE(tc, now == imp); +} + +static void test_rfcstr(abts_case *tc, void *data) +{ + status_t rv; + char str[STR_SIZE]; + + rv = rfc822_date(str, now); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "rfc822_date"); + } + ABTS_TRUE(tc, rv == CORE_OK); + ABTS_STR_EQUAL(tc, "Sat, 14 Sep 2002 19:05:36 GMT", str); +} + +static void test_ctime(abts_case *tc, void *data) +{ + status_t rv; + char core_str[STR_SIZE]; + char libc_str[STR_SIZE]; + c_time_t now_sec = time_sec(now); + time_t posix_sec = (time_t) now_sec; + + rv = core_ctime(core_str, now); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "core_ctime"); + } + ABTS_TRUE(tc, rv == CORE_OK); + strcpy(libc_str, ctime(&posix_sec)); + *strchr(libc_str, '\n') = '\0'; + + ABTS_STR_EQUAL(tc, libc_str, core_str); +} + +static void test_strftime(abts_case *tc, void *data) +{ + status_t rv; + time_exp_t xt; + char str[STR_SIZE+1]; + size_t sz; + + rv = time_exp_gmt(&xt, now); + rv = core_strftime(str, &sz, STR_SIZE, "%R %A %d %B %Y", &xt); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "core_strftime"); + } + ABTS_TRUE(tc, rv == CORE_OK); + ABTS_STR_EQUAL(tc, "19:05 Saturday 14 September 2002", str); +} + +static void test_strftimesmall(abts_case *tc, void *data) +{ + status_t rv; + time_exp_t xt; + char str[STR_SIZE]; + size_t sz; + + rv = time_exp_gmt(&xt, now); + rv = core_strftime(str, &sz, STR_SIZE, "%T", &xt); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "core_strftime"); + } + ABTS_TRUE(tc, rv == CORE_OK); + ABTS_STR_EQUAL(tc, "19:05:36", str); +} + +static void test_exp_tz(abts_case *tc, void *data) +{ + status_t rv; + time_exp_t xt; + c_int32_t hr_off = -5 * 3600; /* 5 hours in seconds */ + + rv = time_exp_tz(&xt, now, hr_off); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "time_exp_tz"); + } + ABTS_TRUE(tc, rv == CORE_OK); + ABTS_TRUE(tc, (xt.tm_usec == 186711) && + (xt.tm_sec == 36) && + (xt.tm_min == 5) && + (xt.tm_hour == 14) && + (xt.tm_mday == 14) && + (xt.tm_mon == 8) && + (xt.tm_year == 102) && + (xt.tm_wday == 6) && + (xt.tm_yday == 256)); +} + +static void test_strftimeoffset(abts_case *tc, void *data) +{ + status_t rv; + time_exp_t xt; + char str[STR_SIZE]; + size_t sz; + c_int32_t hr_off = -5 * 3600; /* 5 hours in seconds */ + + time_exp_tz(&xt, now, hr_off); + rv = core_strftime(str, &sz, STR_SIZE, "%T", &xt); + if (rv == CORE_ENOTIMPL) + { + ABTS_NOT_IMPL(tc, "core_strftime"); + } + ABTS_TRUE(tc, rv == CORE_OK); +} + +/* 0.9.4 and earlier rejected valid dates in 2038 */ +static void test_2038(abts_case *tc, void *data) +{ + time_exp_t xt; + c_time_t t; + + /* 2038-01-19T03:14:07.000000Z */ + xt.tm_year = 138; + xt.tm_mon = 0; + xt.tm_mday = 19; + xt.tm_hour = 3; + xt.tm_min = 14; + xt.tm_sec = 7; + + CORE_ASSERT_OK(tc, "explode January 19th, 2038", + time_exp_get(&t, &xt)); +} + +abts_suite *testtime(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_now, NULL); + abts_run_test(suite, test_gmtstr, NULL); + abts_run_test(suite, test_exp_lt, NULL); + abts_run_test(suite, test_exp_get_gmt, NULL); + abts_run_test(suite, test_exp_get_lt, NULL); + abts_run_test(suite, test_imp_gmt, NULL); + abts_run_test(suite, test_rfcstr, NULL); + abts_run_test(suite, test_ctime, NULL); + abts_run_test(suite, test_strftime, NULL); + abts_run_test(suite, test_strftimesmall, NULL); + abts_run_test(suite, test_exp_tz, NULL); + abts_run_test(suite, test_strftimeoffset, NULL); + abts_run_test(suite, test_2038, NULL); + + return suite; +} + diff --git a/lib/core/test/testtimer.c b/lib/core/test/testtimer.c new file mode 100644 index 0000000000..17be8ed204 --- /dev/null +++ b/lib/core/test/testtimer.c @@ -0,0 +1,381 @@ +#include "core_time.h" +#include "core_timer.h" +#include "core_param.h" +#include "testutil.h" + +#define TEST_TIMER_NUM 200 +#define TEST_TIMER_PRECISION 20 /* 2ms precision */ +#define TEST_DURATION 400 + +c_uint8_t expire_check[TEST_DURATION/TEST_TIMER_PRECISION]; + +typedef struct _test_timer_eliment +{ + c_uint8_t type; + c_uint32_t duration; +} test_timer_eliment; + + +test_timer_eliment timer_eliment[] ={ + {TIMER_TYPE_ONE_SHOT, 500}, + {TIMER_TYPE_ONE_SHOT, 50}, + {TIMER_TYPE_ONE_SHOT, 200}, + {TIMER_TYPE_ONE_SHOT, 90}, + {TIMER_TYPE_ONE_SHOT, 800} +}; + + +void test_expire_func_1(c_uintptr_t arg1, c_uintptr_t arg2, c_uintptr_t arg3) +{ + c_uint32_t index = arg2; + + expire_check[index] = TRUE; +} + +void test_expire_func_2(c_uintptr_t arg1, c_uintptr_t arg2, c_uintptr_t arg3) +{ + c_uint32_t index = arg2; + + expire_check[index]++; +} + +static void test_now(abts_case *tc, void *data) +{ + c_time_t timediff; + c_time_t current; + time_t os_now; + + current = time_now(); + time(&os_now); + + timediff = os_now - (current / USEC_PER_SEC); + /* Even though these are called so close together, there is the chance + * that the time will be slightly off, so accept anything between -1 and + * 1 second. + */ + ABTS_ASSERT(tc, "core_time and OS time do not agree", + (timediff > -2) && (timediff < 2)); +} + + +/* basic timer Test */ +static void timer_test_1(abts_case *tc, void *data) +{ + + int n = 0; + tm_block_id id_array[100]; + tm_block_id id; + tm_service_t tm_service; + + memset((char*)id_array, 0x00, sizeof(tm_service)); + memset(expire_check, 0x00, sizeof(expire_check)); + + /* init tm_service */ + tm_service_init(&tm_service); + + for(n = 0; n < sizeof(timer_eliment) / sizeof(test_timer_eliment); n++) + { + id_array[n] = tm_create(&tm_service); + tm_set(id_array[n], TIMER_TYPE_ONE_SHOT, timer_eliment[n].duration, + test_expire_func_1, (c_uintptr_t)id_array[n], n, 0); + } + + + for(n = 0; n < sizeof(timer_eliment) / sizeof(test_timer_eliment); n++) + { + tm_start(id_array[n]); + } + + id = (tm_block_id)list_first(&tm_service.idle_list); + ABTS_INT_EQUAL(tc, id, 0); + + id = (tm_block_id)list_first(&tm_service.active_list); + ABTS_INT_NEQUAL(tc, id, 0); + ABTS_INT_EQUAL(tc, id, id_array[1]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[3]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[2]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[0]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[4]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, 0); + + core_sleep(70000); + tm_execute_tm_service(&tm_service); + + id = (tm_block_id)list_first(&tm_service.idle_list); + ABTS_INT_EQUAL(tc, id, id_array[1]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, 0); + + id = (tm_block_id)list_first(&tm_service.active_list); + ABTS_INT_NEQUAL(tc, id, 0); + ABTS_INT_EQUAL(tc, id, id_array[3]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[2]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[0]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[4]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, 0); + + ABTS_INT_EQUAL(tc, expire_check[0], 0); + ABTS_INT_EQUAL(tc, expire_check[1], 1); + ABTS_INT_EQUAL(tc, expire_check[2], 0); + ABTS_INT_EQUAL(tc, expire_check[3], 0); + ABTS_INT_EQUAL(tc, expire_check[4], 0); + + + core_sleep(40000); + tm_execute_tm_service(&tm_service); + + id = (tm_block_id)list_first(&tm_service.idle_list); + ABTS_INT_EQUAL(tc, id, id_array[1]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[3]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, 0); + + id = (tm_block_id)list_first(&tm_service.active_list); + ABTS_INT_NEQUAL(tc, id, 0); + ABTS_INT_EQUAL(tc, id, id_array[2]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[0]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[4]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, 0); + + ABTS_INT_EQUAL(tc, expire_check[0], 0); + ABTS_INT_EQUAL(tc, expire_check[1], 1); + ABTS_INT_EQUAL(tc, expire_check[2], 0); + ABTS_INT_EQUAL(tc, expire_check[3], 1); + ABTS_INT_EQUAL(tc, expire_check[4], 0); + + + core_sleep(140000); + tm_execute_tm_service(&tm_service); + + id = (tm_block_id)list_first(&tm_service.idle_list); + ABTS_INT_EQUAL(tc, id, id_array[1]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[3]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[2]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, 0); + + id = (tm_block_id)list_first(&tm_service.active_list); + ABTS_INT_NEQUAL(tc, id, 0); + ABTS_INT_EQUAL(tc, id, id_array[0]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[4]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, 0); + + ABTS_INT_EQUAL(tc, expire_check[0], 0); + ABTS_INT_EQUAL(tc, expire_check[1], 1); + ABTS_INT_EQUAL(tc, expire_check[2], 1); + ABTS_INT_EQUAL(tc, expire_check[3], 1); + ABTS_INT_EQUAL(tc, expire_check[4], 0); + + + core_sleep(300000); + tm_execute_tm_service(&tm_service); + + id = (tm_block_id)list_first(&tm_service.idle_list); + ABTS_INT_EQUAL(tc, id, id_array[1]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[3]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[2]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[0]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, 0); + + id = (tm_block_id)list_first(&tm_service.active_list); + ABTS_INT_NEQUAL(tc, id, 0); + ABTS_INT_EQUAL(tc, id, id_array[4]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, 0); + + ABTS_INT_EQUAL(tc, expire_check[0], 1); + ABTS_INT_EQUAL(tc, expire_check[1], 1); + ABTS_INT_EQUAL(tc, expire_check[2], 1); + ABTS_INT_EQUAL(tc, expire_check[3], 1); + ABTS_INT_EQUAL(tc, expire_check[4], 0); + + + core_sleep(300000); + tm_execute_tm_service(&tm_service); + + id = (tm_block_id)list_first(&tm_service.idle_list); + ABTS_INT_EQUAL(tc, id, id_array[1]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[3]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[2]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[0]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, id_array[4]); if(tc->failed) return; + id = (tm_block_id)list_next(id); + ABTS_INT_EQUAL(tc, id, 0); + + id = (tm_block_id)list_first(&tm_service.active_list); + ABTS_INT_EQUAL(tc, id, 0); + + ABTS_INT_EQUAL(tc, expire_check[0], 1); + ABTS_INT_EQUAL(tc, expire_check[1], 1); + ABTS_INT_EQUAL(tc, expire_check[2], 1); + ABTS_INT_EQUAL(tc, expire_check[3], 1); + ABTS_INT_EQUAL(tc, expire_check[4], 1); + + for( n = 0; n < sizeof(timer_eliment) / sizeof(test_timer_eliment); n++) + { + tm_delete(id_array[n]); + } + + ABTS_INT_EQUAL(tc, tm_pool_avail(), MAX_NUM_OF_TIMER); + + return; +} + + +static void timer_test_2(abts_case *tc, void *data) +{ + + int n = 0; + tm_block_id id_array[TEST_TIMER_NUM]; + tm_service_t tm_service; + int duration; + int tm_num[TEST_DURATION/TEST_TIMER_PRECISION]; + int tm_idx; + + memset((char*)id_array, 0x00, sizeof(tm_service)); + memset(expire_check, 0x00, sizeof(expire_check)); + memset(tm_num, 0x00, sizeof(tm_num)); + + /* init tm_service */ + tm_service_init(&tm_service); + + for(n = 0; n < TEST_TIMER_NUM; n++) + { + duration = (rand() % (TEST_DURATION/TEST_TIMER_PRECISION)) + * TEST_TIMER_PRECISION; + + tm_idx = duration/TEST_TIMER_PRECISION; + tm_num[tm_idx]++; + duration += (TEST_TIMER_PRECISION >> 1); + + id_array[n] = tm_create(&tm_service); + tm_set(id_array[n], TIMER_TYPE_ONE_SHOT, duration, + test_expire_func_2, (c_uintptr_t)id_array[n], tm_idx, 0); + } + + for(n = 0; n < TEST_TIMER_NUM; n++) + { + tm_start(id_array[n]); + } + + for(n = 0; n < TEST_DURATION/TEST_TIMER_PRECISION; n++) + { + core_sleep(TEST_TIMER_PRECISION * 1000); + tm_execute_tm_service(&tm_service); + ABTS_INT_EQUAL(tc, tm_num[n], expire_check[n]); + } + + for(n = 0; n < TEST_TIMER_NUM; n++) + { + tm_delete(id_array[n]); + } + + ABTS_INT_EQUAL(tc, tm_pool_avail(), MAX_NUM_OF_TIMER); + + return; +} + + +static void timer_test_3(abts_case *tc, void *data) +{ + c_uint32_t n = 0; + tm_block_id id_array[TEST_TIMER_NUM]; + tm_service_t tm_service; + int id_duration[TEST_TIMER_NUM]; + int duration; + int tm_num[TEST_DURATION/TEST_TIMER_PRECISION]; + int tm_idx, tm_check_id; + + memset((char*)id_array, 0x00, sizeof(tm_service)); + memset(expire_check, 0x00, sizeof(expire_check)); + memset(tm_num, 0x00, sizeof(tm_num)); + + /* init tm_service */ + tm_service_init(&tm_service); + + for(n = 0; n < TEST_TIMER_NUM; n++) + { + duration = (rand() % (TEST_DURATION/TEST_TIMER_PRECISION)) + * TEST_TIMER_PRECISION; + tm_idx = duration/TEST_TIMER_PRECISION; + tm_num[tm_idx]++; + id_duration[n] = duration; + duration += (TEST_TIMER_PRECISION >> 1); + + + id_array[n] = tm_create(&tm_service); + tm_set(id_array[n], TIMER_TYPE_ONE_SHOT, duration, + test_expire_func_2, (c_uint32_t)id_array[n], tm_idx, 0); + } + + for(n = 0; n < TEST_TIMER_NUM; n++) + { + tm_start(id_array[n]); + } + + for(n = 0; n < TEST_TIMER_NUM / 10; n++) + { + tm_idx = n*10 + rand()%10; + tm_check_id = id_duration[tm_idx]/TEST_TIMER_PRECISION; + tm_num[tm_check_id]--; + tm_delete(id_array[tm_idx]); + id_array[tm_idx] = 0; + } + + for(n = 0; n < TEST_DURATION/TEST_TIMER_PRECISION; n++) + { + core_sleep(TEST_TIMER_PRECISION * 1000); + tm_execute_tm_service(&tm_service); + ABTS_INT_EQUAL(tc, tm_num[n], expire_check[n]); + } + + for(n = 0; n < TEST_TIMER_NUM; n++) + { + if(id_array[n] != 0) + { + tm_delete(id_array[n]); + } + } + + ABTS_INT_EQUAL(tc, tm_pool_avail(), MAX_NUM_OF_TIMER); + + return; +} + +abts_suite *testtimer(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_now, NULL); + abts_run_test(suite, timer_test_1, NULL); + abts_run_test(suite, timer_test_2, NULL); + abts_run_test(suite, timer_test_3, NULL); + + return suite; +} + diff --git a/lib/core/test/testtlv.c b/lib/core/test/testtlv.c new file mode 100644 index 0000000000..0fc4eda55c --- /dev/null +++ b/lib/core/test/testtlv.c @@ -0,0 +1,446 @@ +#include "core_tlv.h" +#include "core_net.h" +#include "testutil.h" + +#define TLV_0_LEN 10 +#define TLV_1_LEN 20 +#define TLV_2_LEN 100 +#define TLV_3_LEN 200 +#define TLV_4_LEN 2 +#define TLV_5_LEN 2000 +#define TLV_VALUE_ARRAY_SIZE 3000 + +#define EMBED_TLV_TYPE 20 + +typedef struct _test_tlv_eliment +{ + c_uint8_t type; + c_uint32_t length; + c_uint8_t *value; + c_uint8_t val_char; +} test_tlv_eliment; + +c_uint8_t test_tlv_value[TLV_VALUE_ARRAY_SIZE]; + +test_tlv_eliment tlv_eliment[] ={ + {1, TLV_0_LEN, 0, 0x0a}, + {100, TLV_1_LEN, 0, 0x0b}, + {255, TLV_2_LEN, 0, 0x0c}, + {254, TLV_3_LEN, 0, 0x0d}, + {5, TLV_4_LEN, 0, 0x0e}, + {30, TLV_5_LEN, 0, 0x0f} +}; + +void tlv_test_set_tlv_value(void) +{ + c_uint32_t inc = 0; + + /* set test tlv value */ + tlv_eliment[0].value = test_tlv_value; + memset(tlv_eliment[0].value, tlv_eliment[0].val_char, tlv_eliment[0].length); + inc += tlv_eliment[0].length; + + tlv_eliment[1].value = test_tlv_value + inc; + memset(tlv_eliment[1].value, tlv_eliment[1].val_char, tlv_eliment[1].length); + inc += tlv_eliment[1].length; + + tlv_eliment[2].value = test_tlv_value + inc; + memset(tlv_eliment[2].value, tlv_eliment[2].val_char, tlv_eliment[2].length); + inc += tlv_eliment[2].length; + + tlv_eliment[3].value = test_tlv_value + inc; + memset(tlv_eliment[3].value, tlv_eliment[3].val_char, tlv_eliment[3].length); + inc += tlv_eliment[3].length; + + tlv_eliment[4].value = test_tlv_value + inc; + memset(tlv_eliment[4].value, tlv_eliment[4].val_char, tlv_eliment[4].length); + inc += tlv_eliment[4].length; + + return; +} + +void tlv_test_check_embed_tlv_test(abts_case *tc, tlv_t *root_tlv) +{ + c_uint32_t m; + c_uint32_t parent_block_len; + tlv_t *pTlv; + tlv_t *embed_tlv = NULL, *parent_tlv = NULL, *parsed_tlv = NULL; + c_uint8_t parent_block[4000]; + c_uint8_t *pos = NULL; + int result; + + memset(parent_block, 0x00, sizeof(parent_block)); + + parent_block_len = tlv_render(root_tlv, parent_block, + sizeof(parent_block), TLV_MODE_WMX_R4_R6); + + ABTS_INT_EQUAL(tc, parent_block_len, 332); + + tlv_free_all(root_tlv); + ABTS_INT_EQUAL(tc, tlv_pool_avail(), NUM_OF_TLV_NODE); + + + + pos = parent_block; + + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[0].type >> 8); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[0].type & 0xFF); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[0].length >> 8); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[0].length & 0xFF); + + for(m = 0; m < tlv_eliment[0].length; m++) + { + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[0].val_char); + } + + ABTS_INT_EQUAL(tc, *(pos++), EMBED_TLV_TYPE >> 8); + ABTS_INT_EQUAL(tc, *(pos++), EMBED_TLV_TYPE & 0xFF); + ABTS_INT_EQUAL(tc, *(pos++), (308 >> 8)); + ABTS_INT_EQUAL(tc, *(pos++), 308 & 0xFF); + + /* embedded tlv_t */ + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[2].type >> 8); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[2].type & 0xFF); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[2].length >> 8); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[2].length & 0xFF); + for(m = 0; m < tlv_eliment[2].length; m++) + { + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[2].val_char); + } + + + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[3].type >> 8); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[3].type & 0xFF); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[3].length >> 8); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[3].length & 0xFF); + for(m = 0; m < tlv_eliment[3].length; m++) + { + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[3].val_char); + } + + + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[4].type >> 8); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[4].type & 0xFF); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[4].length >> 8); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[4].length & 0xFF); + + for(m = 0; m < tlv_eliment[4].length; m++) + { + ABTS_INT_EQUAL(tc, *(pos++), 0x0e); + } + + + + parsed_tlv = tlv_parse_tlv_block(parent_block_len, + parent_block, TLV_MODE_WMX_R4_R6); + ABTS_PTR_NOTNULL(tc, parsed_tlv); + + + pTlv = parsed_tlv; + + ABTS_INT_EQUAL(tc, pTlv->type, tlv_eliment[0].type); + + ABTS_INT_EQUAL(tc, pTlv->length, tlv_eliment[0].length); + result = memcmp(pTlv->value, tlv_eliment[0].value, tlv_eliment[0].length); + ABTS_INT_EQUAL(tc, result, 0); + pTlv = pTlv->next; + + ABTS_INT_EQUAL(tc, pTlv->type, 20); + ABTS_INT_EQUAL(tc, pTlv->length, 308); + pTlv = pTlv->next; + + ABTS_INT_EQUAL(tc, pTlv->type, tlv_eliment[4].type); + ABTS_INT_EQUAL(tc, pTlv->length, tlv_eliment[4].length); + result = memcmp(pTlv->value, tlv_eliment[4].value, tlv_eliment[4].length); + ABTS_INT_EQUAL(tc, result, 0); + pTlv = pTlv->next; + + + ABTS_PTR_NULL(tc, pTlv); + + parent_tlv = tlv_find(parsed_tlv,20); + ABTS_PTR_NOTNULL(tc, parent_tlv); + + tlv_parse_embedded_tlv_block(parent_tlv, TLV_MODE_WMX_R4_R6); + embed_tlv = parent_tlv->embedded; + ABTS_PTR_NOTNULL(tc, embed_tlv); + + + ABTS_INT_EQUAL(tc, embed_tlv->type, tlv_eliment[2].type); + ABTS_INT_EQUAL(tc, embed_tlv->length, tlv_eliment[2].length); + for(m = 0; m < tlv_eliment[2].length; m++) + { + ABTS_INT_EQUAL(tc, *((c_uint8_t*)(embed_tlv->value+m)), + tlv_eliment[2].val_char); + } + embed_tlv = embed_tlv->next; + + ABTS_INT_EQUAL(tc, embed_tlv->type, tlv_eliment[3].type); + ABTS_INT_EQUAL(tc, embed_tlv->length, tlv_eliment[3].length); + for(m = 0; m < tlv_eliment[3].length; m++) + { + ABTS_INT_EQUAL(tc, *((c_uint8_t*)(embed_tlv->value+m)), + tlv_eliment[3].val_char); + } + embed_tlv = embed_tlv->next; + + ABTS_PTR_NULL(tc, embed_tlv); + + embed_tlv = tlv_find(parsed_tlv,254); + ABTS_PTR_NOTNULL(tc, embed_tlv); + + embed_tlv = tlv_find(parsed_tlv,253); + ABTS_PTR_NULL(tc, embed_tlv); + + tlv_free_all(parsed_tlv); + ABTS_INT_EQUAL(tc, tlv_pool_avail(), NUM_OF_TLV_NODE); + + return; +} + + + +/* basic encoding/decoding/finding Test */ +static void tlv_test_1(abts_case *tc, void *data) +{ + c_uint32_t idx, m, parent_block_len; + tlv_t *root_tlv = NULL, *parsed_tlv = NULL, *pTlv; + c_uint8_t parent_block[4000]; + c_uint8_t *pos = NULL; + + tlv_test_set_tlv_value(); + + /* tlv encoding for test */ + root_tlv = tlv_add(NULL,tlv_eliment[0].type, + tlv_eliment[0].length, tlv_eliment[0].value); + + for(idx = 1; idx < 4; idx++) + { + tlv_add(root_tlv,tlv_eliment[idx].type, + tlv_eliment[idx].length, tlv_eliment[idx].value); + } + + memset(parent_block, 0x00, sizeof(parent_block)); + parent_block_len = tlv_render(root_tlv, parent_block, + sizeof(parent_block), TLV_MODE_WMX_R4_R6); + + ABTS_INT_EQUAL(tc, parent_block_len, 346); + + tlv_free_all(root_tlv); + ABTS_INT_EQUAL(tc, tlv_pool_avail(), NUM_OF_TLV_NODE); + + pos = parent_block; + + for(idx = 0; idx < 4; idx++) + { + + ABTS_INT_EQUAL(tc, *(pos++), (tlv_eliment[idx].type >> 8)); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[idx].type & 0xFF); + + + ABTS_INT_EQUAL(tc, *(pos++), (tlv_eliment[idx].length >> 8)); + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[idx].length & 0xFF); + + for(m = 0; m < tlv_eliment[idx].length; m++) + { + ABTS_INT_EQUAL(tc, *(pos++), tlv_eliment[idx].val_char); + } + } + + + parsed_tlv = tlv_parse_tlv_block(parent_block_len,parent_block, + TLV_MODE_WMX_R4_R6); + ABTS_PTR_NOTNULL(tc, parsed_tlv); + + pTlv = parsed_tlv; + + idx = 0; + while(pTlv) + { + int result; + ABTS_INT_EQUAL(tc, pTlv->type, tlv_eliment[idx].type); + ABTS_INT_EQUAL(tc, pTlv->length, tlv_eliment[idx].length); + + result = memcmp(pTlv->value, tlv_eliment[idx].value, tlv_eliment[idx].length); + ABTS_INT_EQUAL(tc, result, 0); + + pTlv = pTlv->next; + idx++; + } + + ABTS_INT_EQUAL(tc, idx, 4); + + pTlv = tlv_find(parsed_tlv, 255); + ABTS_PTR_NOTNULL(tc, pTlv); + + pTlv = tlv_find(parsed_tlv, 253); + ABTS_PTR_NULL(tc, pTlv); + + tlv_free_all(parsed_tlv); + ABTS_INT_EQUAL(tc, tlv_pool_avail(), NUM_OF_TLV_NODE); + + return; +} + + +/* embedded tlv_t test : first, make embedded tlv block for embeded tlv + and then make whole tlv block using embedded tlv block previously made*/ +static void tlv_test_2(abts_case *tc, void *data) +{ + c_uint32_t embed_block_len; + tlv_t *root_tlv = NULL; + tlv_t *embed_tlv = NULL; + c_uint8_t embed_block[1000];; + + tlv_test_set_tlv_value(); + + /* Tlv Encoding for embeded tlv_t */ + embed_tlv = tlv_add(NULL, tlv_eliment[2].type, + tlv_eliment[2].length, tlv_eliment[2].value); + tlv_add(embed_tlv,tlv_eliment[3].type, + tlv_eliment[3].length, tlv_eliment[3].value); + + embed_block_len = tlv_render(embed_tlv, embed_block, + sizeof(embed_block), TLV_MODE_WMX_R4_R6); + ABTS_INT_EQUAL(tc, embed_block_len, 308); + + tlv_free_all(embed_tlv); + ABTS_INT_EQUAL(tc, tlv_pool_avail(), NUM_OF_TLV_NODE); + + root_tlv = tlv_add(NULL,tlv_eliment[0].type, + tlv_eliment[0].length, tlv_eliment[0].value); + + tlv_add(root_tlv, EMBED_TLV_TYPE, embed_block_len, embed_block); + tlv_add(root_tlv,tlv_eliment[4].type, + tlv_eliment[4].length, tlv_eliment[4].value); + + tlv_test_check_embed_tlv_test(tc, root_tlv); + + return; +} + + +/* embedded tlv_t test : make parent and embedded tlv and then tlv_render + functions makes whole tlv block. the value member of each tlv must + point to vaild address at the time using tlv_rendering function */ +static void tlv_test_3(abts_case *tc, void *data) +{ + tlv_t *root_tlv = NULL, *parent_tlv = NULL; + + tlv_test_set_tlv_value(); + + /* Tlv Encoding for embeded tlv_t */ + root_tlv = tlv_add(NULL,tlv_eliment[0].type, + tlv_eliment[0].length, tlv_eliment[0].value); + parent_tlv= tlv_add(root_tlv, EMBED_TLV_TYPE, 0, NULL); + tlv_add(root_tlv,tlv_eliment[4].type, + tlv_eliment[4].length, tlv_eliment[4].value); + + tlv_embed(parent_tlv,tlv_eliment[2].type, + tlv_eliment[2].length, tlv_eliment[2].value); + tlv_embed(parent_tlv,tlv_eliment[3].type, + tlv_eliment[3].length, tlv_eliment[3].value); + + tlv_test_check_embed_tlv_test(tc, root_tlv); + + return; +} + + +/* embedded tlv_t test : make parent and embedded tlv and then tlv_render + functions makes whole tlv block. The value member of each tlv is copied + to the buff of the root tlv_t, so the allocated resource for the value + member of each tlv can be deallocated after executing tlv_add or tlv embed + function*/ +static void tlv_test_4(abts_case *tc, void *data) +{ + tlv_t *root_tlv = NULL, *parent_tlv = NULL; + c_uint8_t tlv_buff[2000]; + + tlv_test_set_tlv_value(); + + root_tlv = tlv_create_buff_enabled_tlv(tlv_buff, sizeof(tlv_buff), + tlv_eliment[0].type,tlv_eliment[0].length, tlv_eliment[0].value); + parent_tlv = tlv_add(root_tlv, 20, 0, NULL); + tlv_add(root_tlv,tlv_eliment[4].type, + tlv_eliment[4].length, tlv_eliment[4].value); + + tlv_embed(parent_tlv,tlv_eliment[2].type, + tlv_eliment[2].length, tlv_eliment[2].value); + tlv_embed(parent_tlv,tlv_eliment[3].type, + tlv_eliment[3].length, tlv_eliment[3].value); + + memset(tlv_eliment[2].value, 0x00, tlv_eliment[2].length); + memset(tlv_eliment[3].value, 0xf0, tlv_eliment[3].length); + + tlv_test_check_embed_tlv_test(tc, root_tlv); + + return; +} + +/* endian check test */ +static void tlv_test_5(abts_case *tc, void *data) +{ + c_uint32_t parent_block_len; + tlv_t *root_tlv = NULL, *parsed_tlv = NULL, *p_tlv; + c_uint8_t parent_block[4000]; + c_uint8_t *pos = NULL; + c_uint16_t c_16 = 0x1122; + c_uint32_t c_32 = 0x11223344; + + /* tlv encoding for test */ + c_16 = htons(c_16); + root_tlv = tlv_add(NULL,10, 2, (c_uint8_t*)&c_16); + c_32 = htonl(c_32); + tlv_add(root_tlv, 20, 4, (c_uint8_t*)&c_32); + + memset(parent_block, 0x00, sizeof(parent_block)); + parent_block_len = tlv_render(root_tlv, parent_block, + sizeof(parent_block), TLV_MODE_WMX_R4_R6); + + tlv_free_all(root_tlv); + ABTS_INT_EQUAL(tc, tlv_pool_avail(), NUM_OF_TLV_NODE); + + pos = parent_block; + ABTS_INT_EQUAL(tc, *(pos++), 0); + + ABTS_INT_EQUAL(tc, *(pos++), 10); + ABTS_INT_EQUAL(tc, *(pos++), 0); + ABTS_INT_EQUAL(tc, *(pos++), 2); + ABTS_INT_EQUAL(tc, *(pos++), 0x11); + ABTS_INT_EQUAL(tc, *(pos++), 0x22); + ABTS_INT_EQUAL(tc, *(pos++), 0); + ABTS_INT_EQUAL(tc, *(pos++), 20); + ABTS_INT_EQUAL(tc, *(pos++), 0); + ABTS_INT_EQUAL(tc, *(pos++), 4); + ABTS_INT_EQUAL(tc, *(pos++), 0x11); + ABTS_INT_EQUAL(tc, *(pos++), 0x22); + ABTS_INT_EQUAL(tc, *(pos++), 0x33); + ABTS_INT_EQUAL(tc, *(pos++), 0x44); + + p_tlv = parsed_tlv = tlv_parse_tlv_block(parent_block_len,parent_block, + TLV_MODE_WMX_R4_R6); + ABTS_INT_EQUAL(tc, tlv_value_16(p_tlv), 0x1122); + p_tlv = parsed_tlv->next; + ABTS_INT_EQUAL(tc, tlv_value_32(p_tlv), 0x11223344); + + tlv_free_all(parsed_tlv); + ABTS_INT_EQUAL(tc, tlv_pool_avail(), NUM_OF_TLV_NODE); + + return; +} + + +abts_suite *testtlv(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, tlv_test_1, NULL); + abts_run_test(suite, tlv_test_2, NULL); + abts_run_test(suite, tlv_test_3, NULL); + abts_run_test(suite, tlv_test_4, NULL); + abts_run_test(suite, tlv_test_5, NULL); + + return suite; +} + diff --git a/lib/core/test/testutil.c b/lib/core/test/testutil.c new file mode 100644 index 0000000000..c34b0655df --- /dev/null +++ b/lib/core/test/testutil.c @@ -0,0 +1,41 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core.h" +#include "abts.h" +#include "testutil.h" + +void core_assert_ok(abts_case* tc, const char* context, status_t rv, + int lineno) +{ + if (rv == CORE_ENOTIMPL) + { + abts_not_impl(tc, context, lineno); + } else if (rv != CORE_OK) + { + char buf[STRING_MAX], ebuf[128]; + sprintf(buf, "%s (%d): %s\n", context, rv, + core_strerror(rv, ebuf, sizeof ebuf)); + abts_fail(tc, buf, lineno); + } +} + +void test_initialize(void) +{ + core_initialize(); + atexit(core_terminate); +} + diff --git a/lib/core/test/testutil.h b/lib/core/test/testutil.h new file mode 100644 index 0000000000..87db132caf --- /dev/null +++ b/lib/core/test/testutil.h @@ -0,0 +1,76 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core_general.h" +#include "abts.h" + +#ifndef __APR_TEST_UTIL__ +#define __APR_TEST_UTIL__ + +/* XXX: FIXME - these all should become much more utilitarian + * and part of core, itself + */ + +#ifdef WIN32 +#ifdef BINPATH +#define TESTBINPATH APR_STRINGIFY(BINPATH) "/" +#else +#define TESTBINPATH "" +#endif +#else +#define TESTBINPATH "./" +#endif + +#ifdef WIN32 +#define EXTENSION ".exe" +#elif NETWARE +#define EXTENSION ".nlm" +#else +#define EXTENSION +#endif + +#define STRING_MAX 8096 + +/* Some simple functions to make the test apps easier to write and + * a bit more consistent... + */ + +/* Assert that RV is an CORE_OK value; else fail giving strerror + * for RV and CONTEXT message. */ +void core_assert_ok(abts_case* tc, const char *context, + status_t rv, int lineno); +#define CORE_ASSERT_OK(tc, ctxt, rv) \ + core_assert_ok(tc, ctxt, rv, __LINE__) + +void test_initialize(void); + +abts_suite *testds(abts_suite *suite); +abts_suite *testfsm(abts_suite *suite); +abts_suite *testtlv(abts_suite *suite); +abts_suite *testaes(abts_suite *suite); +abts_suite *testsha2(abts_suite *suite); +abts_suite *testnetlib(abts_suite *suite); +abts_suite *testtime(abts_suite *suite); +abts_suite *testtimer(abts_suite *suite); +abts_suite *testthread(abts_suite *suite); +abts_suite *testlock(abts_suite *suite); +abts_suite *testfile(abts_suite *suite); +abts_suite *testfilecopy(abts_suite *suite); +abts_suite *testdir(abts_suite *suite); +abts_suite *testmsgq(abts_suite *suite); +abts_suite *testsleep(abts_suite *suite); + +#endif /* CORE_TEST_INCLUDES */ diff --git a/lib/logger/Makefile.am b/lib/logger/Makefile.am new file mode 100644 index 0000000000..573c4b1ef9 --- /dev/null +++ b/lib/logger/Makefile.am @@ -0,0 +1,18 @@ +## Process this file with automake to produce Makefile.in. + +noinst_LTLIBRARIES = liblogger.la + +liblogger_la_SOURCES = logger.h + +nodist_liblogger_la_SOURCES = logger.c + +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib/core/include + +AM_CFLAGS = \ + -Wall -Werror + +MAINTAINERCLEANFILES = Makefile.in +MOSTLYCLEANFILES = core *.stackdump + +EXTRA_DIST = .libs $(noinst_LTLIBRARIES) diff --git a/lib/logger/logger.c b/lib/logger/logger.c new file mode 100644 index 0000000000..be91fd8607 --- /dev/null +++ b/lib/logger/logger.c @@ -0,0 +1,223 @@ +#include "logger.h" + +#include "core_general.h" +#include "core_debug.h" +#include "core_param.h" +#include "core_file.h" + +#include +#include +#include +#include +#include + +#define MAX_LOG_FILE_SIZE (6*16*1024) /* 96 KB */ +#define MAX_BACKUP_LOG_FILE_NUM 19 /* 96 KB x 19 */ +#define FILE_CHECK_CYCLE 15 + +static char g_buffer[1024]; +static char g_path[MAX_FILENAME_SIZE] = "wemania.log"; +static file_t *g_file = NULL; + +static int request_stop = 0; + +status_t log_file_backup() +{ + status_t rv; + char fn[MAX_FILENAME_SIZE], nfn[MAX_FILENAME_SIZE]; + file_t *tmpf = NULL; + int i, j; + + file_close(g_file); + + for (i = 0; ; i++) + { + sprintf(fn, "%s.%d", g_path, i); + + rv = file_open(&tmpf, fn, FILE_READ, 0); + if (rv != CORE_OK) + break; + + file_close(tmpf); + } + + for (j = i - 1; j >= 0; j--) + { + sprintf(fn, "%s.%d", g_path, j); + sprintf(nfn, "%s.%d", g_path, j + 1); + + if (j + 1 > MAX_BACKUP_LOG_FILE_NUM) + { + rv = file_remove(fn); + if (rv != CORE_OK) + { + fprintf(stderr, "Can't remove '%s'\n", fn); + return CORE_ERROR; + } + } + else + { + rv = file_rename(fn, nfn); + if (rv != CORE_OK) + { + fprintf(stderr, "Can't rename '%s' to '%s'\n", fn, nfn); + return CORE_ERROR; + } + } + } + + sprintf(fn, "%s", g_path); + sprintf(nfn, "%s.0", g_path); + + rv = file_rename(fn, nfn); + if (rv != CORE_OK) + { + fprintf(stderr, "Can't rename '%s' to '%s'\n", fn, nfn); + return CORE_ERROR; + } + + rv = file_open(&g_file, g_path, + FILE_CREATE | FILE_WRITE| FILE_APPEND, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + if (rv != CORE_OK) + { + fprintf(stderr, "Cannot open log file '%s'", g_path); + return CORE_ERROR; + } + + return CORE_OK; +} + +int logger_start(const char *path) +{ + status_t rv; + int ret, count = 0; + size_t nbytes; + ssize_t r; + file_info_t finfo; + int us; + fd_set readfd; + struct timeval timer_val; + struct sockaddr_un svaddr; + + /* If path is given, use it */ + if (path) + strcpy(g_path, path); + + us = socket(AF_UNIX, SOCK_DGRAM, 0); + if (us < 0) + { + fprintf(stderr, "socket() failed. (%d:%s)\n", + errno, strerror(errno)); + return -1; + } + + svaddr.sun_family = AF_UNIX; + strcpy(svaddr.sun_path, D_LOGD_IPC_PATH); + + ret = bind(us, (struct sockaddr *)&svaddr, sizeof(svaddr)); + if (ret != 0) + { + if (errno == EADDRINUSE) + { + ret = unlink(D_LOGD_IPC_PATH); + if (ret != 0) + { + fprintf(stderr, "unlink() failed. (%d:%s)\n", + errno, strerror(errno)); + return -1; + } + ret = bind(us, (struct sockaddr *)&svaddr, sizeof(svaddr)); + if (ret != 0) + { + fprintf(stderr, "bind() failed 2. (%d:%s)\n", + errno, strerror(errno)); + return -1; + } + } + else + { + fprintf(stderr, "bind() failed. (%d:%s)\n", + errno, strerror(errno)); + return -1; + } + } + + rv = file_open(&g_file, g_path, + FILE_CREATE | FILE_WRITE| FILE_APPEND, + FILE_UREAD | FILE_UWRITE | FILE_GREAD); + if (rv != CORE_OK) + { + fprintf(stderr, "Cannot open log file '%s'\n", g_path); + close(us); + return -1; + } + + + while (!request_stop) + { + timer_val.tv_sec = 0; + timer_val.tv_usec = 50000; + FD_ZERO(&readfd); + FD_SET(us, &readfd); + + r = select (us+1, &readfd, NULL, NULL, &timer_val); + if (r == -1) + { + if (errno == EINTR) + break; + fprintf(stderr, "select() error(%d: %s)", + errno, strerror(errno)); + } + + if (r == 0) + continue; + + if (FD_ISSET(us, &readfd)) + { + r = read(us, g_buffer, sizeof(g_buffer)); + + if (r < 0) + { + if (errno == EINTR) + break; + fprintf(stderr, "read() failed. (%d:%s)\n", + errno, strerror(errno)); + continue; + } + + if (r == 0) + continue; + + nbytes = r; + rv = file_write(g_file, g_buffer, &nbytes); + if (rv != CORE_OK || r != nbytes) + { + fprintf(stderr, "Cannot write %ld bytes to log file (%ld written)\n", + (long)r, (long)nbytes); + } + + if (count % FILE_CHECK_CYCLE == 0) + { + file_info_get(&finfo, FILE_INFO_SIZE, g_file); + if (finfo.size > MAX_LOG_FILE_SIZE) + { + log_file_backup(); + } + } + + count++; + } + } + + file_close(g_file); + + close(us); + + return 0; +} + +void logger_stop() +{ + request_stop = 1; +} diff --git a/lib/logger/logger.h b/lib/logger/logger.h new file mode 100644 index 0000000000..163959220a --- /dev/null +++ b/lib/logger/logger.h @@ -0,0 +1,17 @@ +#ifndef __LOGGER_H__ +#define __LOGGER_H__ + +#include "core.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +CORE_DECLARE(int) logger_start(const char *path); +CORE_DECLARE(void) logger_stop(); + +#ifdef __cplusplus +} +#endif /* !__cplusplus */ + +#endif /* !__LOGGER_H__ */ diff --git a/main.c b/main.c new file mode 100644 index 0000000000..c063260a9c --- /dev/null +++ b/main.c @@ -0,0 +1,250 @@ +/** + * @file main.c + */ + +/* Core library */ +#include "core.h" +#include "core_general.h" +#define TRACE_MODULE _main_ +#include "core_debug.h" +#include "core_cond.h" +#include "core_thread.h" +#include "core_signal.h" +#include "core_net.h" + +#include "logger.h" +#include "symtbl.h" + +/* Server */ +#include "cellwire.h" + +thread_id thr_sm; +#define THREAD_SM_STACK_SIZE +#define THREAD_SM_PRIORITY +extern void *THREAD_FUNC sm_main(void *data); + +thread_id thr_dp; +#define THREAD_DP_STACK_SIZE +#define THREAD_DP_PRIORITY +extern void *THREAD_FUNC dp_main(void *data); + +thread_id thr_test; + +char *config_path = NULL; +extern char g_compile_time[]; + +static void show_version() +{ + printf("CellWire daemon v%s - %s\n", + PACKAGE_VERSION, g_compile_time); +} + +static void show_help() +{ + show_version(); + + printf("\n" + "Usage: cellwired [arguments]\n" + "\n" + "Arguments:\n" + " -v Show version\n" + " -h Show help\n" + " -d Start as daemon\n" + " -f Set configuration file name\n" + " -l log_path Fork log daemon with file path to be logged to\n" + "\n" + ); +} + +static void threads_start() +{ + status_t rv; + +#if 0 + rv = thread_create(&thr_sm, NULL, sm_main, NULL); + d_assert(rv == CORE_OK, return, + "State machine thread creation failed"); + + rv = thread_create(&thr_dp, NULL, dp_main, NULL); + d_assert(rv == CORE_OK, return, + "Control path thread creation failed"); +#endif +} + +static void threads_stop() +{ +#if 0 + thread_delete(thr_sm); + thread_delete(thr_dp); +#endif +} + +static int check_signal(int signum) +{ + switch (signum) + { + case SIGTERM: + case SIGINT: + { + d_info("%s received", + signum == SIGTERM ? "SIGTERM" : "SIGINT"); + + threads_stop(); + + return 1; + } + case SIGHUP: + { + + d_info("SIGHUP received"); + + threads_stop(); + + cellwire_terminate(); + + core_terminate(); + + core_initialize(); + + cellwire_initialize(); + + threads_start(); + + break; + } + default: + { + d_error("Unknown Signal Number = %d\n", signum); + break; + } + + } + return 0; +} + +void logger_signal(int signum) +{ + switch (signum) + { + case SIGTERM: + case SIGINT: + logger_stop(); + break; + case SIGHUP: + break; + default: + break; + } +} + +int main(int argc, char *argv[]) +{ + int opt; + int opt_daemon = 0; + int opt_logger = 0; + + char *log_path = NULL; + + /************************************************************************** + * Starting up process. + * + * Keep the order of starting-up + */ + + while (1) + { + opt = getopt (argc, argv, "vhdf:l:"); + if (opt == -1) + break; + + switch (opt) + { + case 'v': + show_version(); + return EXIT_SUCCESS; + case 'h': + show_help(); + return EXIT_SUCCESS; + case 'd': + opt_daemon = 1; + break; + case 'f': + config_path = optarg; + break; + case 'l': + opt_logger = 1; + log_path = optarg; + break; + default: + show_help(); + return EXIT_FAILURE; + } + } + + if (opt_daemon) + { + pid_t pid; + pid = fork(); + + d_assert(pid != -1, return EXIT_FAILURE, "fork() failed"); + + if (pid != 0) + { + /* Parent */ + return EXIT_SUCCESS; + } + /* Child */ + + setsid(); + umask(027); + } + + core_initialize(); + + if (opt_logger) + { + pid_t pid; + pid = fork(); + + d_assert(pid != -1, return EXIT_FAILURE, "fork() failed"); + + if (pid == 0) + { + /* Child */ + setsid(); + umask(027); + + core_signal(SIGINT, logger_signal); + core_signal(SIGTERM, logger_signal); + core_signal(SIGHUP, logger_signal); + + logger_start(log_path); + + return EXIT_SUCCESS; + } + /* Parent */ + } + + signal_init(); + + if (cellwire_initialize() != CORE_OK) + { + d_fatal("CellWire initialization failed. Aborted"); + return EXIT_FAILURE; + } + + + d_info("CellWire daemon start"); + + threads_start(); + + signal_thread(check_signal); + + d_info("CellWire daemon terminating..."); + + cellwire_terminate(); + + core_terminate(); + + return EXIT_SUCCESS; +} diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000000..0674b3e7c5 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,24 @@ +## Process this file with automake to produce Makefile.in. + +noinst_LTLIBRARIES = libcellwire.la + +libcellwire_la_SOURCES = \ + ../include/cellwire.h + +nodist_libcellwire_la_SOURCES = \ + init.c + +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/lib/core \ + -I$(top_srcdir)/lib/core/include + +AM_CFLAGS = \ + -Wall -Werror + +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" + +MAINTAINERCLEANFILES = Makefile.in +MOSTLYCLEANFILES = core *.stackdump + +EXTRA_DIST = .libs $(noinst_LTLIBRARIES) diff --git a/src/cellwire.h b/src/cellwire.h new file mode 100644 index 0000000000..3dacb6229d --- /dev/null +++ b/src/cellwire.h @@ -0,0 +1,23 @@ +#ifndef __CELLWIRE_H__ +#define __CELLWIRE_H__ + +#include "core.h" +#include "core_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define S1_SCTP_PORT 36412 +#define GTP_C_UDP_PORT 2123 +#define GTP_U_UDP_PORT 2152 + +CORE_DECLARE(status_t) cellwire_initialize(void); + +CORE_DECLARE_NONSTD(void) cellwire_terminate(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !__CELLWIRE_H__ */ diff --git a/src/init.c b/src/init.c new file mode 100644 index 0000000000..738cff3cda --- /dev/null +++ b/src/init.c @@ -0,0 +1,23 @@ +/** + * @file init.c + */ + +/* Core library */ +#include "core.h" +#define TRACE_MODULE _init +#include "core_debug.h" + +#include + +status_t cellwire_initialize(char *config_path) +{ + openlog("cellwire", 0, LOG_DAEMON); + + srand(time(NULL)*getpid()); + + return CORE_OK; +} + +void cellwire_terminate(void) +{ +} diff --git a/symtbl.h b/symtbl.h new file mode 100644 index 0000000000..609a6d7274 --- /dev/null +++ b/symtbl.h @@ -0,0 +1,14 @@ +#include "core.h" + +#define ST_BSS 1 +#define ST_COMMON 2 +#define ST_DATA 3 +#define ST_TEXT 4 + +typedef struct { + int sym_type; + void *sym_addr; + char *sym_name; +} symbol_tbl_t; + +extern symbol_tbl_t st[]; diff --git a/symtbl.sh b/symtbl.sh new file mode 100755 index 0000000000..e5ec03ab6c --- /dev/null +++ b/symtbl.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +SYMTBL_TMP="symtbl.tmp" + +grep -e " B " -e " C " -e " D " -e " T " $1 | grep -v "\." > $SYMTBL_TMP + +echo '/* Symbol table generated automatically by symtbl.sh */' > $2 +echo '#include "symtbl.h"' >> $2 +awk '/ [BCD] / { print "extern int "$3";"}' $SYMTBL_TMP >> $2 +awk '/ T / { print "extern int "$3"();"}' $SYMTBL_TMP >> $2 +echo "symbol_tbl_t st[] = {" >> $2 +awk '/ B / { print "{ST_BSS,(void*)&"$3",\""$3"\"}," }' $SYMTBL_TMP >> $2 +awk '/ C / { print "{ST_COMMON,(void*)&"$3",\""$3"\"}," }' $SYMTBL_TMP >> $2 +awk '/ D / { print "{ST_DATA,(void*)&"$3",\""$3"\"}," }' $SYMTBL_TMP >> $2 +awk '/ T / { print "{ST_TEXT,(void*)&"$3",\""$3"\"}," }' $SYMTBL_TMP >> $2 +echo "{0,NULL,NULL}};" >> $2 +echo "char g_compile_time[] = __DATE__ \" \" __TIME__;" >> $2 + +rm -f $SYMTBL_TMP