From fdf97f47bbfcce08492da12ac346b222cd4f0efa Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Thu, 2 Feb 2017 20:34:37 +0900 Subject: [PATCH] add build system using Core Library --- AUTHORS | 0 COPYING | 0 ChangeLog | 0 INSTALL | 370 ++++ Makefile.am | 46 + NEWS | 0 README | 64 + acinclude.m4 | 74 + configure.ac | 272 +++ lib/Makefile.am | 6 + lib/core/Makefile.am | 6 + lib/core/include/arch/core_private_common.h | 4 + lib/core/include/arch/unix/core_arch_file.h | 29 + lib/core/include/arch/unix/core_arch_mutex.h | 12 + .../include/arch/unix/core_arch_semaphore.h | 12 + lib/core/include/core.h.in | 366 ++++ lib/core/include/core_aes.h | 42 + lib/core/include/core_aes_cmac.h | 46 + lib/core/include/core_cond.h | 118 ++ lib/core/include/core_debug.h | 226 +++ lib/core/include/core_errno.h | 1309 ++++++++++++++ lib/core/include/core_file.h | 652 +++++++ lib/core/include/core_fsm.h | 48 + lib/core/include/core_general.h | 122 ++ lib/core/include/core_index.h | 67 + lib/core/include/core_lib.h | 87 + lib/core/include/core_list.h | 112 ++ lib/core/include/core_msgq.h | 86 + lib/core/include/core_mutex.h | 89 + lib/core/include/core_net.h | 266 +++ lib/core/include/core_param.h | 19 + lib/core/include/core_pkbuf.h | 192 ++ lib/core/include/core_pool.h | 65 + lib/core/include/core_queue.h | 40 + lib/core/include/core_ringbuf.h | 57 + lib/core/include/core_rwlock.h | 110 ++ lib/core/include/core_semaphore.h | 81 + lib/core/include/core_sha1.h | 61 + lib/core/include/core_sha1_hmac.h | 71 + lib/core/include/core_sha2.h | 102 ++ lib/core/include/core_sha2_hmac.h | 140 ++ lib/core/include/core_signal.h | 90 + lib/core/include/core_thread.h | 79 + lib/core/include/core_time.h | 196 ++ lib/core/include/core_timer.h | 59 + lib/core/include/core_tlv.h | 108 ++ lib/core/include/core_version.h | 141 ++ lib/core/src/Makefile.am | 41 + lib/core/src/aes.c | 1344 ++++++++++++++ lib/core/src/aes_cmac.c | 272 +++ lib/core/src/debug.c | 405 +++++ lib/core/src/fsm.c | 50 + lib/core/src/msgq.c | 310 ++++ lib/core/src/ringbuf.c | 170 ++ lib/core/src/sha1.c | 404 +++++ lib/core/src/sha1_hmac.c | 120 ++ lib/core/src/sha2.c | 822 +++++++++ lib/core/src/sha2_hmac.c | 380 ++++ lib/core/src/timer.c | 244 +++ lib/core/src/tlv.c | 729 ++++++++ lib/core/src/unix/Makefile.am | 26 + lib/core/src/unix/cond.c | 103 ++ lib/core/src/unix/errorcodes.c | 420 +++++ lib/core/src/unix/file.c | 1012 +++++++++++ lib/core/src/unix/mutex.c | 108 ++ lib/core/src/unix/net_lib.c | 1571 +++++++++++++++++ lib/core/src/unix/pkbuf.c | 498 ++++++ lib/core/src/unix/rwlock.c | 102 ++ lib/core/src/unix/semaphore.c | 96 + lib/core/src/unix/signal.c | 239 +++ lib/core/src/unix/start.c | 84 + lib/core/src/unix/thread.c | 178 ++ lib/core/src/unix/time.c | 255 +++ lib/core/src/version.c | 19 + lib/core/test/Makefile.am | 27 + lib/core/test/abts.c | 458 +++++ lib/core/test/abts.h | 112 ++ lib/core/test/abts_tests.h | 43 + lib/core/test/testaes.c | 391 ++++ lib/core/test/testdir.c | 124 ++ lib/core/test/testds.c | 814 +++++++++ lib/core/test/testfile.c | 684 +++++++ lib/core/test/testfilecopy.c | 163 ++ lib/core/test/testfsm.c | 298 ++++ lib/core/test/testlock.c | 393 +++++ lib/core/test/testmsgq.c | 188 ++ lib/core/test/testnetlib.c | 835 +++++++++ lib/core/test/testsha.c | 163 ++ lib/core/test/testsleep.c | 47 + lib/core/test/testthread.c | 78 + lib/core/test/testtime.c | 289 +++ lib/core/test/testtimer.c | 381 ++++ lib/core/test/testtlv.c | 446 +++++ lib/core/test/testutil.c | 41 + lib/core/test/testutil.h | 76 + lib/logger/Makefile.am | 18 + lib/logger/logger.c | 223 +++ lib/logger/logger.h | 17 + main.c | 250 +++ src/Makefile.am | 24 + src/cellwire.h | 23 + src/init.c | 23 + symtbl.h | 14 + symtbl.sh | 19 + 104 files changed, 22806 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 acinclude.m4 create mode 100644 configure.ac create mode 100644 lib/Makefile.am create mode 100644 lib/core/Makefile.am create mode 100644 lib/core/include/arch/core_private_common.h create mode 100644 lib/core/include/arch/unix/core_arch_file.h create mode 100644 lib/core/include/arch/unix/core_arch_mutex.h create mode 100644 lib/core/include/arch/unix/core_arch_semaphore.h create mode 100644 lib/core/include/core.h.in create mode 100644 lib/core/include/core_aes.h create mode 100644 lib/core/include/core_aes_cmac.h create mode 100644 lib/core/include/core_cond.h create mode 100644 lib/core/include/core_debug.h create mode 100644 lib/core/include/core_errno.h create mode 100644 lib/core/include/core_file.h create mode 100644 lib/core/include/core_fsm.h create mode 100644 lib/core/include/core_general.h create mode 100644 lib/core/include/core_index.h create mode 100644 lib/core/include/core_lib.h create mode 100644 lib/core/include/core_list.h create mode 100644 lib/core/include/core_msgq.h create mode 100644 lib/core/include/core_mutex.h create mode 100644 lib/core/include/core_net.h create mode 100644 lib/core/include/core_param.h create mode 100644 lib/core/include/core_pkbuf.h create mode 100644 lib/core/include/core_pool.h create mode 100644 lib/core/include/core_queue.h create mode 100644 lib/core/include/core_ringbuf.h create mode 100644 lib/core/include/core_rwlock.h create mode 100644 lib/core/include/core_semaphore.h create mode 100644 lib/core/include/core_sha1.h create mode 100644 lib/core/include/core_sha1_hmac.h create mode 100644 lib/core/include/core_sha2.h create mode 100644 lib/core/include/core_sha2_hmac.h create mode 100644 lib/core/include/core_signal.h create mode 100644 lib/core/include/core_thread.h create mode 100644 lib/core/include/core_time.h create mode 100644 lib/core/include/core_timer.h create mode 100644 lib/core/include/core_tlv.h create mode 100644 lib/core/include/core_version.h create mode 100644 lib/core/src/Makefile.am create mode 100644 lib/core/src/aes.c create mode 100644 lib/core/src/aes_cmac.c create mode 100644 lib/core/src/debug.c create mode 100644 lib/core/src/fsm.c create mode 100644 lib/core/src/msgq.c create mode 100644 lib/core/src/ringbuf.c create mode 100644 lib/core/src/sha1.c create mode 100644 lib/core/src/sha1_hmac.c create mode 100644 lib/core/src/sha2.c create mode 100644 lib/core/src/sha2_hmac.c create mode 100644 lib/core/src/timer.c create mode 100644 lib/core/src/tlv.c create mode 100644 lib/core/src/unix/Makefile.am create mode 100644 lib/core/src/unix/cond.c create mode 100644 lib/core/src/unix/errorcodes.c create mode 100644 lib/core/src/unix/file.c create mode 100644 lib/core/src/unix/mutex.c create mode 100644 lib/core/src/unix/net_lib.c create mode 100644 lib/core/src/unix/pkbuf.c create mode 100644 lib/core/src/unix/rwlock.c create mode 100644 lib/core/src/unix/semaphore.c create mode 100644 lib/core/src/unix/signal.c create mode 100644 lib/core/src/unix/start.c create mode 100644 lib/core/src/unix/thread.c create mode 100644 lib/core/src/unix/time.c create mode 100644 lib/core/src/version.c create mode 100644 lib/core/test/Makefile.am create mode 100644 lib/core/test/abts.c create mode 100644 lib/core/test/abts.h create mode 100644 lib/core/test/abts_tests.h create mode 100644 lib/core/test/testaes.c create mode 100644 lib/core/test/testdir.c create mode 100644 lib/core/test/testds.c create mode 100644 lib/core/test/testfile.c create mode 100644 lib/core/test/testfilecopy.c create mode 100644 lib/core/test/testfsm.c create mode 100644 lib/core/test/testlock.c create mode 100644 lib/core/test/testmsgq.c create mode 100644 lib/core/test/testnetlib.c create mode 100644 lib/core/test/testsha.c create mode 100644 lib/core/test/testsleep.c create mode 100644 lib/core/test/testthread.c create mode 100644 lib/core/test/testtime.c create mode 100644 lib/core/test/testtimer.c create mode 100644 lib/core/test/testtlv.c create mode 100644 lib/core/test/testutil.c create mode 100644 lib/core/test/testutil.h create mode 100644 lib/logger/Makefile.am create mode 100644 lib/logger/logger.c create mode 100644 lib/logger/logger.h create mode 100644 main.c create mode 100644 src/Makefile.am create mode 100644 src/cellwire.h create mode 100644 src/init.c create mode 100644 symtbl.h create mode 100755 symtbl.sh diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..e69de29bb diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..e69de29bb diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..209984075 --- /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 000000000..ff8790fbe --- /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 000000000..e69de29bb diff --git a/README b/README new file mode 100644 index 000000000..a1ecdd75d --- /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 000000000..b16858d4c --- /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 000000000..22c123657 --- /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 000000000..daf681464 --- /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 000000000..101a51422 --- /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 000000000..141c04789 --- /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 000000000..76cc8b1dc --- /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 000000000..38d67803a --- /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 000000000..fcbae58b9 --- /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 000000000..e458c164a --- /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 000000000..afec811b1 --- /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 000000000..d2dd36abb --- /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 000000000..e5486e3f5 --- /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 000000000..e778dc447 --- /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 000000000..593d6fab7 --- /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 000000000..88ccf13a9 --- /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 000000000..2bbc0674e --- /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 000000000..47559ce08 --- /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 000000000..c4b453fd8 --- /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 000000000..e00510a48 --- /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 000000000..693225679 --- /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 000000000..9701ac07b --- /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 000000000..a4cdf53aa --- /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 000000000..2622acbd6 --- /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 000000000..5c7a9c049 --- /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 000000000..d397983c5 --- /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 000000000..a7ab286b1 --- /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 000000000..901e6b331 --- /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 000000000..c1a5bee89 --- /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 000000000..831e081e6 --- /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 000000000..48df39279 --- /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 000000000..17c5674e0 --- /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 000000000..50d41ae95 --- /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 000000000..df095c315 --- /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 000000000..7907d3be3 --- /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 000000000..2073a1731 --- /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 000000000..c9df0afb3 --- /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 000000000..fab242688 --- /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 000000000..ecd04bc26 --- /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 000000000..6bf202825 --- /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 000000000..bf5a8505f --- /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 000000000..0af823ef5 --- /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 000000000..c732b0e98 --- /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 000000000..6860ca19e --- /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 000000000..6d6fb3ac1 --- /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 000000000..c2b7acd39 --- /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 000000000..15cdb790d --- /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 000000000..f26b52925 --- /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 000000000..edd3b4fb4 --- /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 000000000..47908473b --- /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 000000000..25ad5abee --- /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 000000000..0eacd2447 --- /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 000000000..3b8b6db03 --- /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 000000000..df0c8d59a --- /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 000000000..058b53ffe --- /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 000000000..be0f110cf --- /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 000000000..0e7b7e44c --- /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 000000000..497fbc5d9 --- /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 000000000..9b49073a4 --- /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 000000000..937056fea --- /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 000000000..28be862bd --- /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 000000000..0416234da --- /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 000000000..7a4f95b6f --- /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 000000000..26a7d20d5 --- /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 000000000..afcf85f09 --- /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 000000000..e0c1c043d --- /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 000000000..e0dd4dd31 --- /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 000000000..582d139e2 --- /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 000000000..2c92a31ca --- /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 000000000..f2d01bb98 --- /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 000000000..211805077 --- /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 000000000..9c074c46e --- /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 000000000..ff6ea6230 --- /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 000000000..72206d5d5 --- /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 000000000..b52ff453d --- /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 000000000..0ef96fb29 --- /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 000000000..2750bf7ed --- /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 000000000..b93d5b60b --- /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 000000000..5df5dd2c9 --- /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 000000000..474fead62 --- /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 000000000..bc41ccd33 --- /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 000000000..17d1643d8 --- /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 000000000..acab57e48 --- /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 000000000..9a022a040 --- /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 000000000..46bbf490e --- /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 000000000..17be8ed20 --- /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 000000000..0fc4eda55 --- /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 000000000..c34b0655d --- /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 000000000..87db132ca --- /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 000000000..573c4b1ef --- /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 000000000..be91fd860 --- /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 000000000..163959220 --- /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 000000000..c063260a9 --- /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 000000000..0674b3e7c --- /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 000000000..3dacb6229 --- /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 000000000..738cff3cd --- /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 000000000..609a6d727 --- /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 000000000..e5ec03ab6 --- /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