Merge branch 'rhizomedirect' into 'master'

This commit is contained in:
Andrew Bettison 2012-10-05 17:45:30 +09:30
commit 89343c69cd
54 changed files with 25519 additions and 637 deletions

View File

@ -39,6 +39,8 @@ SERVALD_SRC_FILES = \
serval-dna/rhizome_fetch.c \
serval-dna/rhizome_http.c \
serval-dna/rhizome_packetformats.c \
serval-dna/rhizome_direct.c \
serval-dna/rhizome_direct_http.c \
serval-dna/responses.c \
serval-dna/serval_packetvisualise.c \
serval-dna/server.c \

View File

@ -1,7 +1,5 @@
SRCS= \
audiodevices.c \
audio_alsa.c \
audio_msm_g1.c \
audio_reflector.c \
batman.c \
ciphers.c \
@ -47,6 +45,8 @@ SRCS= \
rhizome_bundle.c \
rhizome_crypto.c \
rhizome_database.c \
rhizome_direct.c \
rhizome_direct_http.c \
rhizome_fetch.c \
rhizome_http.c \
rhizome_packetformats.c \
@ -65,6 +65,11 @@ SRCS= \
vomp_console.c \
xprintf.c
HAVE_ALSA= @HAVE_ALSA@
ifeq (HAVE_ALSA,1)
SRCS+= audio_alsa.c
endif
MONITORCLIENTSRCS=conf.c \
log.c \
mkdir.c \
@ -114,11 +119,15 @@ HDRS= fifo.h \
mdp_client.h \
sqlite-amalgamation-3070900/sqlite3.h
LDFLAGS=@LDFLAGS@ @PORTAUDIO_LIBS@ @SRC_LIBS@ @SPANDSP_LIBS@ @CODEC2_LIBS@ @PTHREAD_LIBS@
LDFLAGS=@LDFLAGS@ @LIBS@ @PORTAUDIO_LIBS@ @SRC_LIBS@ @SPANDSP_LIBS@ @CODEC2_LIBS@ @PTHREAD_LIBS@
CFLAGS= -Isqlite-amalgamation-3070900 @CPPFLAGS@ @CFLAGS@ @PORTAUDIO_CFLAGS@ @SRC_CFLAGS@ @SPANDSP_CFLAGS@ @PTHREAD_CFLAGS@ $(VOIPTEST_CFLAGS)
CFLAGS+=-fPIC
CFLAGS+=-Wall -Wno-unused-value
# Solaris magic
CFLAGS+=-DSHA2_USE_INTTYPES_H -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D__EXTENSIONS__=1
# OSX magic to compensate for the Solaris magic
CFLAGS+=-D_DARWIN_C_SOURCE
-include Makefile.dbg
DEFS= @DEFS@

View File

@ -30,8 +30,12 @@ int recordBufferSize=0;
int detectAudioDevice()
{
#ifdef ANDROID
if (!audev) audev=audio_msm_g1_detect();
#endif
#ifdef HAVE_SYS_ALSA_ASOUNDLIB_H
if (!audev) audev=audio_alsa_detect();
#endif
if (audev) {
WHYF("Detected audio device '%s'",audev->name);
return 0;

View File

@ -17,6 +17,11 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <time.h>
#include "serval.h"
@ -206,9 +211,9 @@ int getBatmanPeerList(char *socket_path,struct in_addr peers[],int *peer_count,i
askagain:
/* Make socket */
sock=socket(AF_LOCAL,SOCK_STREAM,0);
sock=socket(PF_UNIX,SOCK_STREAM,0);
memset(&socket_address,0,sizeof(struct sockaddr_un));
socket_address.sun_family=AF_LOCAL;
socket_address.sun_family=PF_UNIX;
if (strlen(socket_path)>256) return WHY("BATMAN socket path too long");
strcpy(socket_address.sun_path,socket_path);

View File

@ -17,6 +17,10 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "serval.h"
int sock = -1;

View File

@ -587,7 +587,9 @@ int app_server_start(int argc, const char *const *argv, struct command_line_opti
creates a new server daemon process with the correct argv[0]. Otherwise, the servald
process appears as a process with argv[0] = "org.servalproject". */
if (execpath) {
execl(execpath, execpath, "start", "foreground", NULL);
/* XXX: Need the cast on Solaris because it defins NULL as 0L and gcc doesn't
* see it as a sentinal */
execl(execpath, execpath, "start", "foreground", (void *)NULL);
_exit(-1);
}
_exit(server(NULL));
@ -597,10 +599,7 @@ int app_server_start(int argc, const char *const *argv, struct command_line_opti
/* Main process. Allow a few seconds for the child process to report for duty. */
time_ms_t timeout = gettime_ms() + 5000;
do {
struct timespec delay;
delay.tv_sec = 0;
delay.tv_nsec = 200000000; // 200 ms = 5 Hz
nanosleep(&delay, NULL);
sleep_ms(200); // 5 Hz
} while ((pid = server_pid()) == 0 && gettime_ms() < timeout);
if (pid == -1)
return -1;
@ -1038,8 +1037,11 @@ int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_
rhizome_manifest_free(m);
return WHYF("Could not bind manifest to file '%s'",filepath);
}
/* Add the manifest and its associated file to the Rhizome database, generating an "id" in the
* process */
/* Add the manifest and its associated file to the Rhizome database,
generating an "id" in the process.
PGS @20121003 - Hang on, didn't we create the ID above? Presumably the
following does NOT in fact generate a bundle ID.
*/
rhizome_manifest *mout = NULL;
if (debug & DEBUG_RHIZOME) DEBUGF("rhizome_add_manifest(author='%s')", authorSidHex);
@ -1121,66 +1123,7 @@ int app_rhizome_import_bundle(int argc, const char *const *argv, struct command_
cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, "");
if (rhizome_opendb() == -1)
return -1;
rhizome_manifest *m = rhizome_new_manifest();
if (!m)
return WHY("Out of manifests.");
int status = -1;
if (rhizome_read_manifest_file(m, manifestpath, 0) == -1) {
status = WHY("could not read manifest file");
} else if (rhizome_manifest_verify(m) == -1) {
status = WHY("Could not verify manifest file.");
} else {
/* Add the manifest and its associated file to the Rhizome database. */
m->dataFileName = strdup(filepath);
if (rhizome_manifest_check_file(m))
status = WHY("file does not belong to manifest");
else {
int ret = rhizome_manifest_check_duplicate(m, NULL);
if (ret == -1)
status = WHY("rhizome_manifest_check_duplicate() failed");
else if (ret) {
INFO("Duplicate found in store");
status = 1;
} else if (rhizome_add_manifest(m, 1) == -1) { // ttl = 1
status = WHY("rhizome_add_manifest() failed");
} else {
status = 0;
}
if (status != -1) {
const char *service = rhizome_manifest_get(m, "service", NULL, 0);
if (service) {
cli_puts("service");
cli_delim(":");
cli_puts(service);
cli_delim("\n");
}
{
cli_puts("manifestid");
cli_delim(":");
cli_puts(alloca_tohex(m->cryptoSignPublic, RHIZOME_MANIFEST_ID_BYTES));
cli_delim("\n");
}
cli_puts("filesize");
cli_delim(":");
cli_printf("%lld", m->fileLength);
cli_delim("\n");
if (m->fileLength != 0) {
cli_puts("filehash");
cli_delim(":");
cli_puts(m->fileHexHash);
cli_delim("\n");
}
const char *name = rhizome_manifest_get(m, "name", NULL, 0);
if (name) {
cli_puts("name");
cli_delim(":");
cli_puts(name);
cli_delim("\n");
}
}
}
}
rhizome_manifest_free(m);
int status=rhizome_import_from_files(manifestpath,filepath);
return status;
}
@ -1687,6 +1630,15 @@ struct command_line_option command_line_options[]={
"Extract a manifest from Rhizome and write it to the given path"},
{app_rhizome_extract_file,{"rhizome","extract","file","<fileid>","[<filepath>]","[<key>]",NULL},CLIFLAG_STANDALONE,
"Extract a file from Rhizome and write it to the given path"},
{app_rhizome_direct_sync,{"rhizome","direct","sync","[peer url]",NULL},
CLIFLAG_STANDALONE,
"Synchronise with the specified Rhizome Direct server. Return when done."},
{app_rhizome_direct_sync,{"rhizome","direct","push","[peer url]",NULL},
CLIFLAG_STANDALONE,
"Deliver all new content to the specified Rhizome Direct server. Return when done."},
{app_rhizome_direct_sync,{"rhizome","direct","pull","[peer url]",NULL},
CLIFLAG_STANDALONE,
"Fetch all new content from the specified Rhizome Direct server. Return when done."},
{app_keyring_create,{"keyring","create",NULL},0,
"Create a new keyring file."},
{app_keyring_list,{"keyring","list","[<pin,pin...>]",NULL},CLIFLAG_STANDALONE,

1
config.guess vendored
View File

@ -1 +0,0 @@
/usr/share/libtool/config/config.guess

1530
config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1
config.sub vendored
View File

@ -1 +0,0 @@
/usr/share/libtool/config/config.sub

1782
config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(servald, 0.9)
AC_CONFIG_MACRO_DIR([m4])
CPPFLAGS=-D_GNU_SOURCE
@ -59,8 +60,15 @@ if test -n "$JAVAC"; then
popdef([AC_MSG_ERROR])
fi
dnl XXX Isn't this pointless? we are always linked against libc
AC_CHECK_LIB(c,srandomdev)
dnl Solaris hides nanosleep here
AC_CHECK_LIB(rt,nanosleep)
dnl BSD way of getting socket creds
AC_CHECK_FUNCS(getpeereid)
AC_CHECK_HEADERS(
stdio.h \
errno.h \
@ -85,9 +93,17 @@ AC_CHECK_HEADERS(
net/route.h \
signal.h \
jni.h \
alsa/asoundlib.h \
ucred.h \
sys/filio.h \
sys/endian.h \
sys/byteorder.h \
)
dnl Check for ALSA
AC_CHECK_HEADER([alsa/asoundlib.h], [have_alsa=1], [have_alsa=0])
AS_IF([test x"$have_alsa" = "x1"], [AC_DEFINE([HAVE_ALSA_ASOUNDLIB_H])])
AS_IF([test x"$have_alsa" = "x1"], [AC_SUBST(HAVE_ALSA,1)], [AC_SUBST(HAVE_ALSA,0)])
echo "Fetching and building NaCl if required."
echo "(this can take HOURS to build depending on your architecture,"
echo " but fortunately it only needs to happen once.)"

View File

@ -196,7 +196,9 @@ dna_helper_start()
fflush(stderr);
_exit(-1);
}
execl(command, command, arg, NULL);
/* XXX: Need the cast on Solaris because it defins NULL as 0L and gcc doesn't
* see it as a sentinal */
execl(command, command, arg, (void *)NULL);
LOGF_perror(LOG_LEVEL_FATAL, "execl(%s, %s, %s, NULL)", command, command, arg ? arg : "NULL");
fflush(stderr);
do { _exit(-1); } while (1);

View File

@ -74,7 +74,9 @@ static int safeSystem(char *cmd_file)
if(pid == -1)
return WHY_perror("fork");
if (pid == 0) {
execlp(shell, shell, "-c", cmd_file,NULL);
/* XXX: Need the cast on Solaris because it defins NULL as 0L and gcc doesn't
* see it as a sentinal */
execlp(shell, shell, "-c", cmd_file,(void*)NULL);
_exit(1);
}
// Wait for child to finish

View File

@ -1 +0,0 @@
/usr/share/libtool/config/install-sh

527
install-sh Executable file
View File

@ -0,0 +1,527 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-01-19.21; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
nl='
'
IFS=" "" $nl"
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for `test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writeable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set fnord $dstdir
shift
$posix_glob set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
$posix_glob set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -1116,7 +1116,7 @@ unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid,
int cn=0,in=0,kp=0;
if (!keyring_find_sid(k,&cn,&in,&kp,sid)) {
RETURN(WHYNULL("Could not find SID in keyring, so can't find SAS"));
RETURNNULL(WHYNULL("Could not find SID in keyring, so can't find SAS"));
}
for(kp=0;kp<k->contexts[cn]->identities[in]->keypair_count;kp++)
@ -1130,7 +1130,7 @@ unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid,
RETURN(k->contexts[cn]->identities[in]->keypairs[kp]->private_key);
}
RETURN(WHYNULL("Identity lacks SAS"));
RETURNNULL(WHYNULL("Identity lacks SAS"));
}
static int keyring_store_sas(overlay_mdp_frame *req){
@ -1404,9 +1404,9 @@ struct nm_record nm_cache[NM_CACHE_SLOTS];
unsigned char *keyring_get_nm_bytes(unsigned char *known_sid, unsigned char *unknown_sid)
{
IN();
if (!known_sid) { RETURN(WHYNULL("known pub key is null")); }
if (!unknown_sid) { RETURN(WHYNULL("unknown pub key is null")); }
if (!keyring) { RETURN(WHYNULL("keyring is null")); }
if (!known_sid) { RETURNNULL(WHYNULL("known pub key is null")); }
if (!unknown_sid) { RETURNNULL(WHYNULL("unknown pub key is null")); }
if (!keyring) { RETURNNULL(WHYNULL("keyring is null")); }
int i;
@ -1421,8 +1421,8 @@ unsigned char *keyring_get_nm_bytes(unsigned char *known_sid, unsigned char *unk
/* Not in the cache, so prepare to cache it (or return failure if known is not
in fact a known key */
int cn=0,in=0,kp=0;
if (!keyring_find_sid(keyring,&cn,&in,&kp,known->sid))
{ RETURN(WHYNULL("known key is not in fact known.")); }
if (!keyring_find_sid(keyring,&cn,&in,&kp,known_sid))
{ RETURNNULL(WHYNULL("known key is not in fact known.")); }
/* work out where to store it */
if (nm_slots_used<NM_CACHE_SLOTS) {
@ -1433,7 +1433,7 @@ unsigned char *keyring_get_nm_bytes(unsigned char *known_sid, unsigned char *unk
/* calculate and store */
bcopy(known_sid,nm_cache[i].known_key,SID_SIZE);
bcopy(unknown->sid,nm_cache[i].unknown_key,SID_SIZE);
bcopy(unknown_sid,nm_cache[i].unknown_key,SID_SIZE);
crypto_box_curve25519xsalsa20poly1305_beforenm(nm_cache[i].nm_bytes,
unknown_sid,
keyring

63
log.c
View File

@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <time.h>
#ifdef __APPLE__
#include <mach-o/dyld.h>
@ -30,6 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include "log.h"
#include "net.h"
@ -223,7 +225,7 @@ void logArgv(int level, struct __sourceloc where, const char *label, int argc, c
if (i)
strbuf_putc(&logbuf, ' ');
if (argv[i])
strbuf_toprint_quoted(&logbuf, '"', argv[i]);
strbuf_toprint_quoted(&logbuf, "\"\"", argv[i]);
else
strbuf_puts(&logbuf, "NULL");
}
@ -266,7 +268,7 @@ void vlogMessage(int level, struct __sourceloc where, const char *fmt, va_list a
}
}
int logDump(int level, struct __sourceloc where, char *name, unsigned char *addr, size_t len)
int logDump(int level, struct __sourceloc where, char *name, const unsigned char *addr, size_t len)
{
char buf[100];
size_t i;
@ -324,10 +326,10 @@ unsigned int debugFlagMask(const char *flagname) {
in log messages.
@author Andrew Bettison <andrew@servalproject.com>
*/
char *toprint(char *dstStr, ssize_t dstBufSiz, const char *srcBuf, size_t srcBytes)
char *toprint(char *dstStr, ssize_t dstBufSiz, const char *srcBuf, size_t srcBytes, const char quotes[2])
{
strbuf b = strbuf_local(dstStr, dstBufSiz);
strbuf_toprint_quoted_len(b, '"', srcBuf, srcBytes);
strbuf_toprint_quoted_len(b, quotes, srcBuf, srcBytes);
return dstStr;
}
@ -336,9 +338,30 @@ char *toprint(char *dstStr, ssize_t dstBufSiz, const char *srcBuf, size_t srcByt
otherwise returns dstStrLen.
@author Andrew Bettison <andrew@servalproject.com>
*/
size_t toprint_strlen(const char *srcBuf, size_t srcBytes)
size_t toprint_len(const char *srcBuf, size_t srcBytes, const char quotes[2])
{
return strbuf_count(strbuf_toprint_quoted_len(strbuf_local(NULL, 0), '"', srcBuf, srcBytes));
return strbuf_count(strbuf_toprint_quoted_len(strbuf_local(NULL, 0), quotes, srcBuf, srcBytes));
}
/* Format a null-terminated string as a printable representation, eg: "Abc\x0b\n", for display
in log messages.
@author Andrew Bettison <andrew@servalproject.com>
*/
char *toprint_str(char *dstStr, ssize_t dstBufSiz, const char *srcStr, const char quotes[2])
{
strbuf b = strbuf_local(dstStr, dstBufSiz);
strbuf_toprint_quoted(b, quotes, srcStr);
return dstStr;
}
/* Compute the length of the string produced by toprint_str(). If dstStrLen == -1 then returns the
exact number of characters in the printable representation (excluding the terminating nul),
otherwise returns dstStrLen.
@author Andrew Bettison <andrew@servalproject.com>
*/
size_t toprint_str_len(const char *srcStr, const char quotes[2])
{
return strbuf_count(strbuf_toprint_quoted(strbuf_local(NULL, 0), quotes, srcStr));
}
/* Read the symbolic link into the supplied buffer and add a terminating nul. Return -1 if the
@ -385,30 +408,30 @@ ssize_t read_symlink(const char *path, char *buf, size_t len)
ssize_t get_self_executable_path(char *buf, size_t len)
{
#ifdef linux
#if defined(linux)
return read_symlink("/proc/self/exe", buf, len);
#endif
#ifdef __APPLE__
// Mac OS X
// TODO: Not tested
#elif defined (__sun__)
return read_symlink("/proc/self/path/a.out", buf, len);
#elif defined (__APPLE__)
uint32_t bufsize = len;
return _NSGetExecutablePath(buf, &bufsize) == -1 && len ? -1 : bufsize;
#else
#error Unable to find executable path
#endif
return WHYF("Not implemented");
}
int log_backtrace(struct __sourceloc where)
{
open_logging();
char execpath[160];
char execpath[MAXPATHLEN];
if (get_self_executable_path(execpath, sizeof execpath) == -1)
return WHY("cannot log backtrace: own executable path unknown");
char tempfile[512];
if (!FORM_SERVAL_INSTANCE_PATH(tempfile, "servalXXXXXX.gdb"))
char tempfile[MAXPATHLEN];
if (!FORM_SERVAL_INSTANCE_PATH(tempfile, "servalgdb.XXXXX"))
return -1;
int tmpfd = mkstemps(tempfile, 4);
int tmpfd = mkstemp(tempfile);
if (tmpfd == -1)
return WHY_perror("mkstemps");
return WHY_perror("mkstemp");
if (write_str(tmpfd, "backtrace\n") == -1) {
close(tmpfd);
unlink(tempfile);
@ -420,7 +443,7 @@ int log_backtrace(struct __sourceloc where)
return -1;
}
char pidstr[12];
snprintf(pidstr, sizeof pidstr, "%u", getpid());
snprintf(pidstr, sizeof pidstr, "%jd", (intmax_t)getpid());
int stdout_fds[2];
if (pipe(stdout_fds) == -1)
return WHY_perror("pipe");
@ -442,7 +465,9 @@ int log_backtrace(struct __sourceloc where)
_exit(-2);
}
close(stdout_fds[0]);
execlp("gdb", "gdb", "-n", "-batch", "-x", tempfile, execpath, pidstr, NULL);
/* XXX: Need the cast on Solaris because it defins NULL as 0L and gcc doesn't
* see it as a sentinal */
execlp("gdb", "gdb", "-n", "-batch", "-x", tempfile, execpath, pidstr, (void*)NULL);
perror("execlp(\"gdb\")");
do { _exit(-3); } while (1);
break;

25
log.h
View File

@ -77,19 +77,22 @@ void logString(int level, struct __sourceloc where, const char *str);
void logMessage(int level, struct __sourceloc where, const char *fmt, ...);
void vlogMessage(int level, struct __sourceloc where, const char *fmt, va_list);
unsigned int debugFlagMask(const char *flagname);
int logDump(int level, struct __sourceloc where, char *name, unsigned char *addr, size_t len);
char *toprint(char *dstStr, ssize_t dstBufSiz, const char *srcBuf, size_t srcBytes);
size_t toprint_strlen(const char *srcBuf, size_t srcBytes);
int logDump(int level, struct __sourceloc where, char *name, const unsigned char *addr, size_t len);
char *toprint(char *dstStr, ssize_t dstBufSiz, const char *srcBuf, size_t srcBytes, const char quotes[2]);
char *toprint_str(char *dstStr, ssize_t dstBufSiz, const char *srcStr, const char quotes[2]);
size_t toprint_len(const char *srcBuf, size_t srcBytes, const char quotes[2]);
size_t toprint_str_len(const char *srcStr, const char quotes[2]);
ssize_t get_self_executable_path(char *buf, size_t len);
int log_backtrace(struct __sourceloc where);
void set_log_implementation(void (*log_function)(int level, struct strbuf *buf));
#define alloca_toprint(dstlen,buf,len) toprint((char *)alloca((dstlen) == -1 ? toprint_strlen((buf),(len)) + 1 : (dstlen)), (dstlen), (buf), (len))
#define alloca_toprint(dstlen,buf,len) toprint((char *)alloca((dstlen) == -1 ? toprint_len((buf),(len), "``") + 1 : (dstlen)), (dstlen), (buf), (len), "``")
#define alloca_str_toprint(str) toprint_str((char *)alloca(toprint_str_len(str, "``") + 1), -1, (str), "``")
#define __HERE__ ((struct __sourceloc){ .file = __FILE__, .line = __LINE__, .function = __FUNCTION__ })
#define __NOWHERE__ ((struct __sourceloc){ .file = NULL, .line = 0, .function = NULL })
#define LOGF(L,F,...) (logMessage(L, __HERE__, F, ##__VA_ARGS__))
#define LOGF(L,F,...) logMessage(L, __HERE__, F, ##__VA_ARGS__)
#define LOGF_perror(L,F,...) logMessage_perror(L, __HERE__, F, ##__VA_ARGS__)
#define LOG_perror(L,X) LOGF_perror(L, "%s", (X))
@ -104,12 +107,12 @@ void set_log_implementation(void (*log_function)(int level, struct strbuf *buf))
#define WHY(X) WHYF("%s", (X))
#define WHYFNULL(F,...) (LOGF(LOG_LEVEL_ERROR, F, ##__VA_ARGS__), NULL)
#define WHYNULL(X) (WHYFNULL("%s", (X)))
#define WHYF_perror(F,...) WHYF(F ": %s [errno=%d]", ##__VA_ARGS__, strerror(errno), errno)
#define WHYF_perror(F,...) (LOGF_perror(LOG_LEVEL_ERROR, F, ##__VA_ARGS__), -1)
#define WHY_perror(X) WHYF_perror("%s", (X))
#define WARNF(F,...) LOGF(LOG_LEVEL_WARN, F, ##__VA_ARGS__)
#define WARN(X) WARNF("%s", (X))
#define WARNF_perror(F,...) WARNF(F ": %s [errno=%d]", ##__VA_ARGS__, strerror(errno), errno)
#define WARNF_perror(F,...) LOGF_perror(LOG_LEVEL_WARN, F, ##__VA_ARGS__)
#define WARN_perror(X) WARNF_perror("%s", (X))
#define WHY_argv(X,ARGC,ARGV) logArgv(LOG_LEVEL_ERROR, __HERE__, (X), (ARGC), (ARGV))
@ -118,12 +121,12 @@ void set_log_implementation(void (*log_function)(int level, struct strbuf *buf))
#define DEBUGF(F,...) LOGF(LOG_LEVEL_DEBUG, F, ##__VA_ARGS__)
#define DEBUG(X) DEBUGF("%s", (X))
#define DEBUGF_perror(F,...) DEBUGF(F ": %s [errno=%d]", ##__VA_ARGS__, strerror(errno), errno)
#define DEBUG_perror(X) DEBUGF("%s: %s [errno=%d]", (X), strerror(errno), errno)
#define D DEBUG("D")
#define DEBUGF_perror(F,...) LOGF_perror(LOG_LEVEL_DEBUG, F, ##__VA_ARGS__)
#define DEBUG_perror(X) DEBUGF_perror("%s", (X))
#define D DEBUG("D")
#define DEBUG_argv(X,ARGC,ARGV) logArgv(LOG_LEVEL_DEBUG, __HERE__, (X), (ARGC), (ARGV))
#define dump(X,A,N) logDump(LOG_LEVEL_DEBUG, __HERE__, (X), (A), (N))
#define dump(X,A,N) logDump(LOG_LEVEL_DEBUG, __HERE__, (X), (const unsigned char *)(A), (size_t)(N))
#define BACKTRACE log_backtrace(__HERE__)

View File

@ -1 +0,0 @@
/usr/share/libtool/config/ltmain.sh

9661
ltmain.sh Normal file

File diff suppressed because it is too large Load Diff

7983
m4/libtool.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

384
m4/ltoptions.m4 vendored Normal file
View File

@ -0,0 +1,384 @@
# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 7 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option `$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl `shared' nor `disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [1], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the `shared' and
# `disable-shared' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the `static' and
# `disable-static' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the `fast-install'
# and `disable-fast-install' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the `pic-only' and `no-pic'
# LT_INIT options.
# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[lt_p=${PACKAGE-default}
case $withval in
yes|no) pic_mode=$withval ;;
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for lt_pkg in $withval; do
IFS="$lt_save_ifs"
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[pic_mode=default])
test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])

123
m4/ltsugar.m4 vendored Normal file
View File

@ -0,0 +1,123 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59 which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])

23
m4/ltversion.m4 vendored Normal file
View File

@ -0,0 +1,23 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# @configure_input@
# serial 3337 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.4.2])
m4_define([LT_PACKAGE_REVISION], [1.3337])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.4.2'
macro_revision='1.3337'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])

98
m4/lt~obsolete.m4 vendored Normal file
View File

@ -0,0 +1,98 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 5 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])

View File

@ -31,9 +31,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "overlay_address.h"
#include "monitor-client.h"
#ifdef HAVE_UCRED_H
#include <ucred.h>
#endif
#ifdef linux
#if defined(LOCAL_PEERCRED) && !defined(SO_PEERCRED)
#define SO_PEERCRED LOCAL_PEERCRED
#endif
#endif
#define MONITOR_LINE_LENGTH 160
#define MONITOR_DATA_SIZE MAX_AUDIO_BYTES
@ -286,12 +292,14 @@ void monitor_client_poll(struct sched_ent *alarm)
}
static void monitor_new_client(int s) {
#ifdef linux
#ifdef SO_PEERCRED
struct ucred ucred;
socklen_t len;
int res;
#else
#elif defined(HAVE_GETPEEREID)
gid_t othergid;
#elif defined(HAVE_UCRED_H)
ucred_t *ucred;
#endif
uid_t otheruid;
struct monitor_context *c;
@ -299,7 +307,8 @@ static void monitor_new_client(int s) {
if (set_nonblock(s) == -1)
goto error;
#ifdef linux
#ifdef SO_PEERCRED
/* Linux way */
len = sizeof(ucred);
res = getsockopt(s, SOL_SOCKET, SO_PEERCRED, &ucred, &len);
if (res) {
@ -311,11 +320,22 @@ static void monitor_new_client(int s) {
goto error;
}
otheruid = ucred.uid;
#else
#elif defined(HAVE_UCRED_H)
/* Solaris way */
if (getpeerucred(s, &ucred) != 0) {
WHY_perror("getpeerucred()");
goto error;
}
otheruid = ucred_geteuid(ucred);
ucred_free(ucred);
#elif defined(HAVE_GETPEEREID)
/* BSD way */
if (getpeereid(s, &otheruid, &othergid) != 0) {
WHY_perror("getpeereid()");
goto error;
}
#else
#error No way to get socket peer credentials
#endif
if (otheruid != getuid()) {
@ -542,8 +562,8 @@ int monitor_announce_bundle(rhizome_manifest *m)
service ? service : "",
m->version,
m->fileLength,
sender,
recipient,
sender ? sender : "",
recipient ? recipient : "",
m->dataFileName?m->dataFileName:"");
for(i=monitor_socket_count -1;i>=0;i--) {
if (monitor_sockets[i].flags & MONITOR_RHIZOME) {

View File

@ -1,6 +1,6 @@
#!/bin/sh
if [ ! -e nacl-version ]; then
if [ ! -r nacl-version ]; then
echo "Can't find nacl-version file"
exit 1
fi
@ -67,20 +67,27 @@ printf("The compilation worked.\n");
}
EOF
worked=0
for ar in $arlist; do
arch=`basename \`dirname $ar\``
incpath=`dirname $ar`/../../include/$arch
rm -f test
gcc -o test test.c $ar -I$incpath >/dev/null 2>&1
if [ -e test ]; then
if [ -r test ]; then
naclbuilddir=`echo $ar | sed -e s,/libnacl.a,,`
echo "${incpath}" >naclinc.txt
echo "${ar}" >nacllib.txt
worked=1
break
fi
done
rm -f test test.c
# Create nacl.h for lazy programmers
(cd ${incpath} ; find . -name \*.h -a \! -name mphlr.h -a \! -name nacl.h | sed -Ee 's,\./(.*),#include <\1>,') >${incpath}/nacl.h
if [ $worked -eq 0 ]; then
echo "Library present but couldn't build the test program"
exit 1
fi
# Create nacl.h for lazy programmers
(cd ${incpath} ; find . -name \*.h -a \! -name mphlr.h -a \! -name nacl.h | sed -e 's,\./\(.*\),#include <\1>,') >${incpath}/nacl.h

View File

@ -148,7 +148,13 @@ schedule(&_sched_##X); }
/* Get rhizome server started BEFORE populating fd list so that
the server's listen socket is in the list for poll() */
if (rhizome_enabled()) rhizome_http_server_start();
if (rhizome_enabled())
/* Rhizome http server needs to know which callback to attach
to client sockets, so provide it here, along with the name to
appear in time accounting statistics. */
rhizome_http_server_start(rhizome_server_parse_http_request,
"rhizome_server_parse_http_request",
RHIZOME_HTTP_PORT,RHIZOME_HTTP_PORT_MAX);
// start the dna helper if configured
dna_helper_start();

View File

@ -17,6 +17,10 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <time.h>
#include "serval.h"
@ -228,7 +232,13 @@ overlay_bind_socket(const struct sockaddr *addr, size_t addr_size, char *interfa
/* Automatically close socket on calls to exec().
This makes life easier when we restart with an exec after receiving
a bad signal. */
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, NULL) | O_CLOEXEC);
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, NULL) |
#ifdef FD_CLOEXEC
FD_CLOEXEC
#else
O_CLOEXEC
#endif
);
#ifdef SO_BINDTODEVICE
/*

View File

@ -250,7 +250,7 @@ int overlay_mdp_process_bind_request(int sock, struct subscriber *subscriber, in
free=random()%MDP_MAX_BINDINGS;
}
if (debug & DEBUG_MDPREQUESTS)
DEBUGF("Binding %s:%d",alloca_tohex_sid(subscriber->sid),port);
DEBUGF("Binding %s:%d", subscriber ? alloca_tohex_sid(subscriber->sid) : "NULL", port);
/* Okay, record binding and report success */
mdp_bindings[free].port=port;
mdp_bindings[free].subscriber=subscriber;
@ -281,18 +281,15 @@ int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp)
break;
case OF_CRYPTO_CIPHERED:
RETURN(WHY("decryption not implemented"));
case OF_CRYPTO_SIGNED:
{
/* This call below will dispatch the request for the SAS if we don't
already have it. In the meantime, we just drop the frame if the SAS
is not available. */
if (!f->source->sas_valid){
keyring_send_sas_request(f->source);
RETURN(WHY("SAS key not currently on record, cannot verify"));
}
/* get payload and following compacted signature */
b=&f->payload->bytes[f->payload->position];
len=f->payload->sizeLimit - f->payload->position - crypto_sign_edwards25519sha512batch_BYTES;
@ -327,7 +324,7 @@ int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp)
{
if (0) DEBUGF("crypted MDP frame for %s", alloca_tohex_sid(mdp->out.dst.sid));
unsigned char *k=keyring_get_nm_bytes(&mdp->out.dst.sid,&mdp->out.src.sid);
unsigned char *k=keyring_get_nm_bytes(mdp->out.dst.sid, mdp->out.src.sid);
unsigned char *nonce=&f->payload->bytes[f->payload->position];
int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES;
int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
@ -789,7 +786,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
/* get pre-computed PKxSK bytes (the slow part of auth-cryption that can be
retained and reused, and use that to do the encryption quickly. */
unsigned char *k=keyring_get_nm_bytes(&mdp->out.src.sid,&mdp->out.dst.sid);
unsigned char *k=keyring_get_nm_bytes(mdp->out.src.sid, mdp->out.dst.sid);
if (!k) {
op_free(frame);
RETURN(WHY("could not compute Curve25519(NxM)"));

View File

@ -22,11 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "overlay_buffer.h"
#include "overlay_packet.h"
struct sockaddr_in loopback = {
.sin_family=0,
.sin_port=0,
.sin_addr.s_addr=0x0100007f
};
struct sockaddr_in loopback;
// a frame destined for one of our local addresses, or broadcast, has arrived. Process it.
int process_incoming_frame(time_ms_t now, struct overlay_interface *interface, struct overlay_frame *f){
@ -185,10 +181,12 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
f.recvaddr=recvaddr;
if (debug&DEBUG_OVERLAYFRAMES)
DEBUG("Received overlay packet");
} else {
if (interface->fileP) {
/* dummy interface, so tell to use 0.0.0.0 */
/* dummy interface, so tell to use localhost */
loopback.sin_family = AF_INET;
loopback.sin_port = 0;
loopback.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
f.recvaddr=(struct sockaddr *)&loopback;
} else
/* some other sort of interface, so we can't offer any help here */

View File

@ -282,7 +282,7 @@ struct overlay_frame *op_dup(struct overlay_frame *in)
/* copy main data structure */
bcopy(in,out,sizeof(struct overlay_frame));
if (in->payload)
out->payload=ob_dup(in->payload);
return out;

View File

@ -17,6 +17,10 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "serval.h"
char *batman_socket=NULL;

121
rhizome.c
View File

@ -41,71 +41,66 @@ int rhizome_enabled()
return rhizome_enabled_flag;
}
/* Import a bundle from the inbox folder. The bundle is contained a pair of files, one containing
the manifest and the optional other containing the payload.
The logic is all in rhizome_add_manifest(). This function just wraps that function and manages
file and object buffers and lifetimes.
/* Import a bundle from a pair of files, one containing the manifest and the optional other
containing the payload. The logic is all in rhizome_bundle_import(). This function just wraps
that function and manages file and object buffers and lifetimes.
*/
int rhizome_bundle_import(rhizome_manifest *m_in, rhizome_manifest **m_out,
const char *bundle, int ttl)
int rhizome_bundle_import_files(const char *manifest_path, const char *payload_path, int ttl)
{
if (debug & DEBUG_RHIZOME)
DEBUGF("rhizome_bundle_import(m_in=%p, m_out=%p, bundle=%s, ttl=%d)",
m_in, m_out, bundle ? bundle : "(null)", ttl);
if (m_out) *m_out = NULL;
char filename[1024];
char manifestname[1024];
/* make sure import path exists */
if (create_rhizome_import_dir() == -1)
return -1;
if (!FORM_RHIZOME_IMPORT_PATH(filename, "file.%s", bundle)
|| !FORM_RHIZOME_IMPORT_PATH(manifestname, "manifest.%s", bundle))
return WHY("Manifest bundle name too long");
DEBUGF("(manifest_path=%s, payload_path=%s, ttl=%d)",
manifest_path ? alloca_str_toprint(manifest_path) : "NULL",
payload_path ? alloca_str_toprint(payload_path) : "NULL",
ttl
);
/* Read manifest file if no manifest was given */
rhizome_manifest *m = m_in;
if (!m_in) {
m = rhizome_new_manifest();
if (!m)
return WHY("Out of manifests.");
if (rhizome_read_manifest_file(m, manifestname, 0 /* file not buffer */) == -1) {
rhizome_manifest_free(m);
return WHY("Could not read manifest file.");
} else if (rhizome_manifest_verify(m)) {
rhizome_manifest_free(m);
return WHY("Could not verify manifest file.");
}
}
if (!manifest_path)
return WHY("No manifest supplied");
int ret = 0;
rhizome_manifest *m = rhizome_new_manifest();
if (!m)
ret = WHY("Out of manifests");
else if (rhizome_read_manifest_file(m, manifest_path, 0 /* file not buffer */) == -1)
ret = WHY("Could not read manifest file");
else if (rhizome_manifest_verify(m))
ret = WHY("Verification of manifest file failed");
else {
/* Make sure we store signatures */
m->manifest_bytes=m->manifest_all_bytes;
/* Add the manifest and its associated file to the Rhizome database. */
m->dataFileName = strdup(filename);
m->dataFileName = strdup(payload_path);
if (rhizome_manifest_check_file(m))
ret = WHY("Payload does not belong to manifest");
else
ret = rhizome_bundle_import(m, ttl);
}
if (m)
rhizome_manifest_free(m);
return ret;
}
/* Import a bundle from a finalised manifest struct. The dataFileName element must give the path
of a readable file containing the payload unless the payload is null (zero length). The logic is
all in rhizome_add_manifest(). This function just wraps that function and manages object buffers
and lifetimes.
*/
int rhizome_bundle_import(rhizome_manifest *m, int ttl)
{
if (debug & DEBUG_RHIZOME)
DEBUGF("(m=%p, ttl=%d)", m, ttl);
/* Add the manifest and its payload to the Rhizome database. */
if (m->fileLength > 0 && !(m->dataFileName && m->dataFileName[0]))
return WHY("Missing data file name");
if (rhizome_manifest_check_file(m))
return WHY("File does not belong to manifest");
int ret=rhizome_manifest_check_duplicate(m,NULL);
if (!ret) rhizome_add_manifest(m, ttl);
unlink(filename);
if (ret == -1) {
WHY("rhizome_add_manifest() failed");
unlink(manifestname);
} else {
/* >>> For testing, write manifest file back to disk and leave it there */
// unlink(manifestname);
if (rhizome_write_manifest_file(m, manifestname))
ret = WHY("Could not write manifest file.");
int ret = rhizome_manifest_check_duplicate(m, NULL);
if (ret == 0) {
ret = rhizome_add_manifest(m, ttl);
if (ret == -1)
WHY("rhizome_add_manifest() failed");
}
/* If the manifest structure was allocated in this function, and it is not being returned to the
caller, then this function is responsible for freeing it */
if (m_out)
*m_out = m;
else if (!m_in)
rhizome_manifest_free(m);
return ret;
}
@ -232,18 +227,18 @@ int rhizome_manifest_check_file(rhizome_manifest *m_in)
return 0;
}
if (gotfile) {
DEBUGF("Skipping file checks for bundle, as file is already in the database");
/* Skipping file checks for bundle, as file is already in the database */
return 0;
}
/* Find out whether the payload is expected to be encrypted or not */
m_in->payloadEncryption=rhizome_manifest_get_ll(m_in, "crypt");
/* Check payload file is accessible and discover its length, then check that it matches
the file size stored in the manifest */
/* Check payload file is accessible and discover its length, then check that it
matches the file size stored in the manifest */
long long mfilesize = rhizome_manifest_get_ll(m_in, "filesize");
m_in->fileLength = 0;
if (m_in->dataFileName[0]) {
if (m_in->dataFileName && m_in->dataFileName[0]) {
struct stat stat;
if (lstat(m_in->dataFileName,&stat) == -1) {
if (errno != ENOENT || mfilesize != 0)
@ -253,7 +248,7 @@ int rhizome_manifest_check_file(rhizome_manifest *m_in)
}
}
if (debug & DEBUG_RHIZOME)
DEBUGF("filename=%s, fileLength=%lld", m_in->dataFileName, m_in->fileLength);
DEBUGF("filename=%s, fileLength=%lld", m_in->dataFileName ? alloca_str_toprint(m_in->dataFileName) : "NULL", m_in->fileLength);
if (mfilesize != -1 && mfilesize != m_in->fileLength) {
WHYF("Manifest.filesize (%lld) != actual file size (%lld)", mfilesize, m_in->fileLength);
return -1;
@ -326,7 +321,7 @@ int rhizome_add_manifest(rhizome_manifest *m_in,int ttl)
/* Get manifest version number. */
m_in->version = rhizome_manifest_get_ll(m_in, "version");
if (m_in->version==-1)
if (m_in->version==-1)
return WHY("Manifest must have a version number");
/* Supply manifest version number if missing, so we can do the version check below */
@ -372,7 +367,7 @@ int rhizome_add_manifest(rhizome_manifest *m_in,int ttl)
service ? service : "NULL",
alloca_tohex_sid(m_in->cryptoSignPublic),
m_in->version
);
);
monitor_announce_bundle(m_in);
return 0;
}

240
rhizome.h
View File

@ -63,6 +63,13 @@ typedef struct rhizome_signature {
} rhizome_signature;
#define RHIZOME_BAR_BYTES 32
#define RHIZOME_BAR_COMPARE_BYTES 31
#define RHIZOME_BAR_PREFIX_BYTES 15
#define RHIZOME_BAR_PREFIX_OFFSET 0
#define RHIZOME_BAR_FILESIZE_OFFSET 15
#define RHIZOME_BAR_VERSION_OFFSET 16
#define RHIZOME_BAR_GEOBOX_OFFSET 23
#define RHIZOME_BAR_TTL_OFFSET 31
#define MAX_MANIFEST_VARS 256
#define MAX_MANIFEST_BYTES 8192
@ -171,7 +178,7 @@ int rhizome_str_is_file_hash(const char *text);
#define alloca_tohex_bid(bid) alloca_tohex((bid), RHIZOME_MANIFEST_ID_BYTES)
int http_header_complete(const char *buf, size_t len, size_t tail);
int http_header_complete(const char *buf, size_t len, size_t read_since_last_call);
typedef struct sqlite_retry_state {
unsigned int limit; // do not retry once elapsed >= limit
@ -207,7 +214,8 @@ int rhizome_store_bundle(rhizome_manifest *m);
int rhizome_manifest_add_group(rhizome_manifest *m,char *groupid);
int rhizome_clean_payload(const char *fileidhex);
int rhizome_store_file(rhizome_manifest *m,const unsigned char *key);
int rhizome_bundle_import(rhizome_manifest *m_in, rhizome_manifest **m_out, const char *bundle, int ttl);
int rhizome_bundle_import_files(const char *manifest_path, const char *payload_path, int ttl);
int rhizome_bundle_import(rhizome_manifest *m, int ttl);
int rhizome_manifest_verify(rhizome_manifest *m);
int rhizome_manifest_check_sanity(rhizome_manifest *m_in);
@ -233,8 +241,8 @@ __RHIZOME_INLINE int sqlite_code_busy(int code)
return code == SQLITE_BUSY || code == SQLITE_LOCKED;
}
sqlite3_stmt *_sqlite_prepare(struct __sourceloc, const char *sqlformat, ...);
sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc, int log_level, strbuf stmt);
sqlite3_stmt *_sqlite_prepare(struct __sourceloc where, sqlite_retry_state *retry, const char *sqlformat, ...);
sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc where, int log_level, sqlite_retry_state *retry, strbuf stmt);
int _sqlite_retry(struct __sourceloc where, sqlite_retry_state *retry, const char *action);
void _sqlite_retry_done(struct __sourceloc where, sqlite_retry_state *retry, const char *action);
int _sqlite_step_retry(struct __sourceloc where, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement);
@ -245,8 +253,8 @@ int _sqlite_exec_int64(struct __sourceloc, long long *result, const char *sqlfor
int _sqlite_exec_int64_retry(struct __sourceloc, sqlite_retry_state *retry, long long *result, const char *sqlformat,...);
int _sqlite_exec_strbuf(struct __sourceloc, strbuf sb, const char *sqlformat,...);
#define sqlite_prepare(fmt,...) _sqlite_prepare(__HERE__, (fmt), ##__VA_ARGS__)
#define sqlite_prepare_loglevel(ll,sb) _sqlite_prepare_loglevel(__HERE__, (ll), (sb))
#define sqlite_prepare(rs,fmt,...) _sqlite_prepare(__HERE__, (rs), (fmt), ##__VA_ARGS__)
#define sqlite_prepare_loglevel(ll,rs,sb) _sqlite_prepare_loglevel(__HERE__, (ll), (rs), (sb))
#define sqlite_retry(rs,action) _sqlite_retry(__HERE__, (rs), (action))
#define sqlite_retry_done(rs,action) _sqlite_retry_done(__HERE__, (rs), (action))
#define sqlite_step(stmt) _sqlite_step_retry(__HERE__, LOG_LEVEL_ERROR, NULL, (stmt))
@ -264,6 +272,8 @@ int rhizome_update_file_priority(const char *fileid);
int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found,
int checkVersionP);
int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar);
long long rhizome_bar_version(unsigned char *bar);
unsigned long long rhizome_bar_bidprefix_ll(unsigned char *bar);
int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peerip, int *manifest_kept);
int rhizome_list_manifests(const char *service, const char *sender_sid, const char *recipient_sid, int limit, int offset);
int rhizome_retrieve_manifest(const char *manifestid, rhizome_manifest **mp);
@ -298,3 +308,221 @@ int rhizome_ignore_manifest_check(rhizome_manifest *m,
int rhizome_suggest_queue_manifest_import(rhizome_manifest *m,
struct sockaddr_in *peerip);
typedef struct rhizome_http_request {
struct sched_ent alarm;
long long initiate_time; /* time connection was initiated */
struct sockaddr_in requestor;
/* identify request from others being run.
Monotonic counter feeds it. Only used for debugging when we write
post-<uuid>.log files for multi-part form requests. */
unsigned int uuid;
/* The HTTP request as currently received */
int request_length;
char request[1024];
/* Nature of the request */
int request_type;
/* All of the below are receiving data */
#define RHIZOME_HTTP_REQUEST_RECEIVING -1
#define RHIZOME_HTTP_REQUEST_RECEIVING_MULTIPART -2
/* All of the below are sending data */
#define RHIZOME_HTTP_REQUEST_FROMBUFFER 1
#define RHIZOME_HTTP_REQUEST_FILE 2
#define RHIZOME_HTTP_REQUEST_SUBSCRIBEDGROUPLIST 4
#define RHIZOME_HTTP_REQUEST_ALLGROUPLIST 8
#define RHIZOME_HTTP_REQUEST_BUNDLESINGROUP 16
// manifests are small enough to send from a buffer
// #define RHIZOME_HTTP_REQUEST_BUNDLEMANIFEST 32
// for anything too big, we can just use a blob
#define RHIZOME_HTTP_REQUEST_BLOB 64
#define RHIZOME_HTTP_REQUEST_FAVICON 128
/* Local buffer of data to be sent.
If a RHIZOME_HTTP_REQUEST_FROMBUFFER, then the buffer is sent, and when empty
the request is closed.
Else emptying the buffer triggers a request to fetch more data. Only if no
more data is provided do we then close the request. */
unsigned char *buffer;
int buffer_size; // size
int buffer_length; // number of bytes loaded into buffer
int buffer_offset; // where we are between [0,buffer_length)
/* Path of request (used by POST multipart form requests where
the actual processing of the request does not occur while the
request headers are still available. */
char path[1024];
/* Boundary string for POST multipart form requests */
char boundary_string[1024];
int boundary_string_length;
/* File currently being written to while decoding POST multipart form */
FILE *field_file;
/* Name of data file supplied */
char data_file_name[1024];
/* Which fields have been seen in POST multipart form */
int fields_seen;
/* The seen fields bitmap above shares values with the actual Rhizome Direct
state machine. The state numbers (and thus bitmap values for the various
fields) are listed here.
To avoid confusion, we should not use single bit values for states that do
not correspond directly to a particular field.
Doesn't really matter what they are apart from not having exactly one bit set.
In fact, the only reason to not have exactly one bit set is so that we keep as
many bits available for field types as possible.
*/
#define RD_MIME_STATE_MANIFESTHEADERS (1<<0)
#define RD_MIME_STATE_DATAHEADERS (1<<1)
#define RD_MIME_STATE_INITIAL 0
#define RD_MIME_STATE_PARTHEADERS 0xffff0000
#define RD_MIME_STATE_BODY 0xffff0001
/* The source specification data which are used in different ways by different
request types */
char source[1024];
long long source_index;
long long source_count;
int source_record_size;
unsigned int source_flags;
sqlite3_blob *blob;
/* source_index used for offset in blob */
long long blob_end;
} rhizome_http_request;
struct http_response {
unsigned int result_code;
const char * content_type;
unsigned long long content_length;
const char * body;
};
int rhizome_server_set_response(rhizome_http_request *r, const struct http_response *h);
int rhizome_server_free_http_request(rhizome_http_request *r);
int rhizome_server_http_send_bytes(rhizome_http_request *r);
int rhizome_server_parse_http_request(rhizome_http_request *r);
int rhizome_server_simple_http_response(rhizome_http_request *r, int result, const char *response);
int rhizome_server_http_response_header(rhizome_http_request *r, int result, const char *mime_type, unsigned long long bytes);
int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, char *column);
int rhizome_http_server_start(int (*http_parse_func)(rhizome_http_request *),
const char *http_parse_func_description,
int port_low,int port_high);
typedef struct rhizome_direct_bundle_cursor {
/* Where the current fill started */
long long start_size_high;
unsigned char start_bid_low[RHIZOME_MANIFEST_ID_BYTES];
/* Limit of where this cursor may traverse */
long long limit_size_high;
unsigned char limit_bid_high[RHIZOME_MANIFEST_ID_BYTES];
long long size_low;
long long size_high;
unsigned char bid_low[RHIZOME_MANIFEST_ID_BYTES];
unsigned char bid_high[RHIZOME_MANIFEST_ID_BYTES];
unsigned char *buffer;
int buffer_size;
int buffer_used;
int buffer_offset_bytes;
} rhizome_direct_bundle_cursor;
rhizome_direct_bundle_cursor *rhizome_direct_bundle_iterator(int buffer_size);
void rhizome_direct_bundle_iterator_unlimit(rhizome_direct_bundle_cursor *r);
int rhizome_direct_bundle_iterator_pickle_range(rhizome_direct_bundle_cursor *r,
unsigned char *pickled,
int pickle_buffer_size);
rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix,int prefix_length);
int rhizome_direct_bundle_iterator_unpickle_range(rhizome_direct_bundle_cursor *r,
const unsigned char *pickled,
int pickle_buffer_size);
int rhizome_direct_bundle_iterator_fill(rhizome_direct_bundle_cursor *c,
int max_bars);
void rhizome_direct_bundle_iterator_free(rhizome_direct_bundle_cursor **c);
int rhizome_direct_get_bars(const unsigned char bid_low[RHIZOME_MANIFEST_ID_BYTES],
unsigned char bid_high[RHIZOME_MANIFEST_ID_BYTES],
long long size_low,long long size_high,
const unsigned char bid_max[RHIZOME_MANIFEST_ID_BYTES],
unsigned char *bars_out,
int bars_requested);
int rhizome_direct_process_post_multipart_bytes
(rhizome_http_request *r,const char *bytes,int count);
typedef struct rhizome_direct_sync_request {
struct sched_ent alarm;
rhizome_direct_bundle_cursor *cursor;
int pushP;
int pullP;
/* Sync interval in seconds. zero = sync only once */
int interval;
/* The dispatch function will be called each time a sync request can
be sent off, i.e., one cursor->buffer full of data.
Will differ based on underlying transport. HTTP is the initial
supported transport, but deLorme inReach will likely follow soon after.
*/
void (*dispatch_function)(struct rhizome_direct_sync_request *);
/* General purpose pointer for transport-dependent state */
void *transport_specific_state;
/* Statistics.
Each sync will consist of one or more "fills" of the cursor buffer, which
will then be dispatched by the transport-specific dispatch function.
Each of those dispatches may then result in zero or
*/
int syncs_started;
int syncs_completed;
int fills_sent;
int fill_responses_processed;
int bundles_pushed;
int bundles_pulled;
int bundle_transfers_in_progress;
} rhizome_direct_sync_request;
#define RHIZOME_DIRECT_MAX_SYNC_HANDLES 16
extern rhizome_direct_sync_request *rd_sync_handles[RHIZOME_DIRECT_MAX_SYNC_HANDLES];
extern int rd_sync_handle_count;
rhizome_direct_sync_request
*rhizome_direct_new_sync_request(
void (*transport_specific_dispatch_function)
(struct rhizome_direct_sync_request *),
int buffer_size,int interval, int mode,
void *transport_specific_state);
int rhizome_direct_continue_sync_request(rhizome_direct_sync_request *r);
int rhizome_direct_conclude_sync_request(rhizome_direct_sync_request *r);
rhizome_direct_bundle_cursor *rhizome_direct_get_fill_response
(unsigned char *buffer,int size,int max_response_bytes);
typedef struct rhizome_direct_transport_state_http {
int port;
char host[1024];
} rhizome_direct_transport_state_http;
void rhizome_direct_http_dispatch(rhizome_direct_sync_request *);
extern unsigned char favicon_bytes[];
extern int favicon_len;
int rhizome_import_from_files(const char *manifestpath,const char *filepath);
int rhizome_fetch_request_manifest_by_prefix(struct sockaddr_in *peerip,
unsigned char *prefix,
int prefix_length,
int importP);
extern int rhizome_file_fetch_queue_count;
struct http_response_parts {
int code;
char *reason;
long long content_length;
char *content_start;
};
int unpack_http_response(char *response, struct http_response_parts *parts);

View File

@ -353,7 +353,7 @@ long long rhizome_manifest_get_ll(rhizome_manifest *m, const char *var)
if (!m)
return -1;
int i;
for (i = 0;i != m->var_count; ++i)
for (i = 0; i < m->var_count; ++i)
if (!strcmp(m->vars[i], var)) {
char *vp = m->values[i];
char *ep = vp;

View File

@ -296,7 +296,10 @@ int rhizome_manifest_lookup_signature_validity(unsigned char *hash,unsigned char
int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs)
{
IN();
if (!m) { RETURN(WHY("NULL pointer passed in as manifest")); }
if (!m)
RETURN(WHY("NULL pointer passed in as manifest"));
if (debug&DEBUG_RHIZOME)
DEBUGF("m->manifest_all_bytes=%d m->manifest_bytes=%d *ofs=%d", m->manifest_all_bytes, m->manifest_bytes, *ofs);
if ((*ofs)>=m->manifest_all_bytes) { RETURN(0); }

View File

@ -149,21 +149,20 @@ int rhizome_opendb()
/* Create tables as required */
sqlite_exec_void_loglevel(loglevel, "PRAGMA auto_vacuum=2;");
if ( sqlite_exec_void("CREATE TABLE IF NOT EXISTS GROUPLIST(id text not null primary key, closed integer,ciphered integer,priority integer);") == -1
|| sqlite_exec_void("CREATE TABLE IF NOT EXISTS MANIFESTS(id text not null primary key, manifest blob, version integer,inserttime integer, bar blob);") == -1
|| sqlite_exec_void("CREATE TABLE IF NOT EXISTS FILES(id text not null primary key, data blob, length integer, highestpriority integer, datavalid integer);") == -1
|| sqlite_exec_void("CREATE TABLE IF NOT EXISTS MANIFESTS(id text not null primary key, manifest blob, version integer,inserttime integer, bar blob, filesize integer, filehash text);") == -1
|| sqlite_exec_void("CREATE TABLE IF NOT EXISTS FILES(id text not null primary key, data blob, length integer, highestpriority integer, datavalid integer, inserttime integer);") == -1
|| sqlite_exec_void("DROP TABLE IF EXISTS FILEMANIFESTS;") == -1
|| sqlite_exec_void("CREATE TABLE IF NOT EXISTS GROUPMEMBERSHIPS(manifestid text not null, groupid text not null);") == -1
|| sqlite_exec_void("CREATE TABLE IF NOT EXISTS VERIFICATIONS(sid text not null, did text, name text, starttime integer, endtime integer, signature blob);") == -1
) {
RETURN(WHY("Failed to create schema"));
}
// No easy way to tell if these columns already exist, should probably create some kind of schema
// version table. Running these a second time will fail.
sqlite_exec_void_loglevel(loglevel, "ALTER TABLE MANIFESTS ADD COLUMN filesize text;");
sqlite_exec_void_loglevel(loglevel, "ALTER TABLE MANIFESTS ADD COLUMN filehash text;");
sqlite_exec_void_loglevel(loglevel, "ALTER TABLE FILES ADD inserttime integer;");
/* Clean out database, but if this fails keep going (database may be read-only). */
/* Create indexes if they don't already exist */
sqlite_exec_void_loglevel(LOG_LEVEL_WARN,"CREATE INDEX IF NOT EXISTS bundlesizeindex ON manifests (filesize);");
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE INDEX IF NOT EXISTS IDX_MANIFESTS_HASH ON MANIFESTS(filehash);");
/* Clean out half-finished entries from the database */
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "DELETE FROM MANIFESTS WHERE filehash IS NULL;");
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "DELETE FROM FILES WHERE NOT EXISTS( SELECT 1 FROM MANIFESTS WHERE MANIFESTS.filehash = FILES.id);");
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "DELETE FROM MANIFESTS WHERE filehash != '' AND NOT EXISTS( SELECT 1 FROM FILES WHERE MANIFESTS.filehash = FILES.id);");
@ -272,14 +271,14 @@ void _sqlite_retry_done(struct __sourceloc where, sqlite_retry_state *retry, con
Returns -1 if an error occurs (logged as an error), otherwise zero with the prepared
statement in *statement.
*/
sqlite3_stmt *_sqlite_prepare(struct __sourceloc where, const char *sqlformat, ...)
sqlite3_stmt *_sqlite_prepare(struct __sourceloc where, sqlite_retry_state *retry, const char *sqlformat, ...)
{
strbuf sql = strbuf_alloca(8192);
strbuf_va_printf(sql, sqlformat);
return _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, sql);
return _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, retry, sql);
}
sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc where, int log_level, strbuf stmt)
sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc where, int log_level, sqlite_retry_state *retry, strbuf stmt)
{
sqlite3_stmt *statement = NULL;
if (strbuf_overrun(stmt)) {
@ -288,16 +287,23 @@ sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc where, int log_level,
}
if (!rhizome_db && rhizome_opendb() == -1)
return NULL;
switch (sqlite3_prepare_v2(rhizome_db, strbuf_str(stmt), -1, &statement, NULL)) {
case SQLITE_OK:
case SQLITE_DONE:
break;
default:
logMessage(log_level, where, "query invalid, %s: %s", sqlite3_errmsg(rhizome_db), strbuf_str(stmt));
sqlite3_finalize(statement);
return NULL;
while (1) {
switch (sqlite3_prepare_v2(rhizome_db, strbuf_str(stmt), -1, &statement, NULL)) {
case SQLITE_OK:
case SQLITE_DONE:
return statement;
case SQLITE_BUSY:
case SQLITE_LOCKED:
if (retry && _sqlite_retry(where, retry, strbuf_str(stmt))) {
break; // back to sqlite3_prepare_v2()
}
// fall through...
default:
logMessage(log_level, where, "query invalid, %s: %s", sqlite3_errmsg(rhizome_db), strbuf_str(stmt));
sqlite3_finalize(statement);
return NULL;
}
}
return statement;
}
int _sqlite_step_retry(struct __sourceloc where, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement)
@ -352,7 +358,7 @@ static int _sqlite_vexec_void(struct __sourceloc where, int log_level, sqlite_re
{
strbuf stmt = strbuf_alloca(8192);
strbuf_vsprintf(stmt, sqlformat, ap);
return _sqlite_exec_void_prepared(where, log_level, retry, sqlite_prepare_loglevel(log_level, stmt));
return _sqlite_exec_void_prepared(where, log_level, retry, _sqlite_prepare_loglevel(where, log_level, retry, stmt));
}
/* Convenience wrapper for executing an SQL command that returns no value.
@ -401,7 +407,7 @@ static int _sqlite_vexec_int64(struct __sourceloc where, sqlite_retry_state *ret
{
strbuf stmt = strbuf_alloca(8192);
strbuf_vsprintf(stmt, sqlformat, ap);
sqlite3_stmt *statement = _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, stmt);
sqlite3_stmt *statement = _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, retry, stmt);
if (!statement)
return -1;
int ret = 0;
@ -467,13 +473,13 @@ int _sqlite_exec_strbuf(struct __sourceloc where, strbuf sb, const char *sqlform
{
strbuf stmt = strbuf_alloca(8192);
strbuf_va_printf(stmt, sqlformat);
sqlite3_stmt *statement = _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, stmt);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = _sqlite_prepare_loglevel(where, LOG_LEVEL_ERROR, &retry, stmt);
if (!statement)
return -1;
int ret = 0;
int rowcount = 0;
int stepcode;
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
while ((stepcode = _sqlite_step_retry(where, LOG_LEVEL_ERROR, &retry, statement)) == SQLITE_ROW) {
int columncount = sqlite3_column_count(statement);
if (columncount != 1) {
@ -517,11 +523,10 @@ int rhizome_make_space(int group_priority, long long bytes)
return 0;
/* Okay, not enough space, so free up some. */
sqlite3_stmt *statement = sqlite_prepare("select id,length from files where highestpriority < %d order by descending length", group_priority);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "select id,length from files where highestpriority < %d order by descending length", group_priority);
if (!statement)
return -1;
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
while (bytes > (rhizome_space - 65536 - rhizome_database_used_bytes())
&& sqlite_step_retry(&retry, statement) == SQLITE_ROW
) {
@ -564,10 +569,10 @@ int rhizome_drop_stored_file(const char *id,int maximum_priority)
{
if (!rhizome_str_is_file_hash(id))
return WHYF("invalid file hash id=%s", alloca_toprint(-1, id, strlen(id)));
sqlite3_stmt *statement = sqlite_prepare("select id from manifests where filehash='%s'", id);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "select id from manifests where filehash='%s'", id);
if (!statement)
return WHYF("Could not drop stored file id=%s", id);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
int can_drop = 1;
while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) {
/* Find manifests for this file */
@ -644,15 +649,20 @@ int rhizome_store_bundle(rhizome_manifest *m)
unsigned char bar[RHIZOME_BAR_BYTES];
rhizome_manifest_to_bar(m,bar);
/* Store the file */
/* Store the file (but not if it is already in the database) */
// TODO encrypted payloads - pass encryption key here. Filehash should be of
// encrypted data.
// We should add the file in the same transaction, but closing the blob seems
// to cause some issues.
char filehash[RHIZOME_FILEHASH_STRLEN + 1];
if (m->fileLength > 0) {
if (!m->fileHashedP)
return WHY("Manifest payload hash unknown");
strncpy(filehash, m->fileHexHash, sizeof filehash);
str_toupper_inplace(filehash);
// TODO encrypted payloads - pass encryption key here
// We should add the file in the same transaction, but closing the blob seems to cause some issues.
/* rhizome_store_file() checks if it is already in the database, so we just
call it normally. */
if (rhizome_store_file(m, NULL))
return WHY("Could not store file");
} else {
@ -664,7 +674,7 @@ int rhizome_store_bundle(rhizome_manifest *m)
return -1;
sqlite3_stmt *stmt;
if ((stmt = sqlite_prepare("INSERT OR REPLACE INTO MANIFESTS(id,manifest,version,inserttime,bar,filesize,filehash) VALUES(?,?,?,?,?,?,?);")) == NULL)
if ((stmt = sqlite_prepare(&retry, "INSERT OR REPLACE INTO MANIFESTS(id,manifest,version,inserttime,bar,filesize,filehash) VALUES(?,?,?,?,?,?,?);")) == NULL)
goto rollback;
if (!( sqlite_code_ok(sqlite3_bind_text(stmt, 1, manifestid, -1, SQLITE_TRANSIENT))
&& sqlite_code_ok(sqlite3_bind_blob(stmt, 2, m->manifestdata, m->manifest_bytes, SQLITE_TRANSIENT))
@ -684,7 +694,7 @@ int rhizome_store_bundle(rhizome_manifest *m)
// we might need to leave the old file around for a bit
// clean out unreferenced files first
if ((stmt = sqlite_prepare("DELETE FROM FILES WHERE inserttime < ? AND NOT EXISTS( SELECT 1 FROM MANIFESTS WHERE MANIFESTS.filehash = FILES.id);")) == NULL)
if ((stmt = sqlite_prepare(&retry, "DELETE FROM FILES WHERE inserttime < ? AND NOT EXISTS( SELECT 1 FROM MANIFESTS WHERE MANIFESTS.filehash = FILES.id);")) == NULL)
goto rollback;
if (!sqlite_code_ok(sqlite3_bind_int64(stmt, 1, (long long)(gettime_ms() - 60000)))) {
WHYF("query failed, %s: %s", sqlite3_errmsg(rhizome_db), sqlite3_sql(stmt));
@ -700,7 +710,7 @@ int rhizome_store_bundle(rhizome_manifest *m)
if (closed<1) closed=0;
int ciphered=rhizome_manifest_get_ll(m,"cipheredgroup");
if (ciphered<1) ciphered=0;
if ((stmt = sqlite_prepare("INSERT OR REPLACE INTO GROUPLIST(id,closed,ciphered,priority) VALUES (?,?,?,?);")) == NULL)
if ((stmt = sqlite_prepare(&retry, "INSERT OR REPLACE INTO GROUPLIST(id,closed,ciphered,priority) VALUES (?,?,?,?);")) == NULL)
goto rollback;
if (!( sqlite_code_ok(sqlite3_bind_text(stmt, 1, manifestid, -1, SQLITE_TRANSIENT))
&& sqlite_code_ok(sqlite3_bind_int(stmt, 2, closed))
@ -717,7 +727,7 @@ int rhizome_store_bundle(rhizome_manifest *m)
}
if (m->group_count > 0) {
if ((stmt = sqlite_prepare("INSERT OR REPLACE INTO GROUPMEMBERSHIPS(manifestid,groupid) VALUES(?, ?);")) == NULL)
if ((stmt = sqlite_prepare(&retry, "INSERT OR REPLACE INTO GROUPMEMBERSHIPS(manifestid,groupid) VALUES(?, ?);")) == NULL)
goto rollback;
int i;
for (i=0;i<m->group_count;i++){
@ -755,7 +765,8 @@ int rhizome_list_manifests(const char *service, const char *sender_sid, const ch
strbuf_sprintf(b, " OFFSET %u", offset);
if (strbuf_overrun(b))
RETURN(WHYF("SQL command too long: ", strbuf_str(b)));
sqlite3_stmt *statement = sqlite_prepare("%s", strbuf_str(b));
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "%s", strbuf_str(b));
if (!statement)
return -1;
int ret = 0;
@ -772,7 +783,6 @@ int rhizome_list_manifests(const char *service, const char *sender_sid, const ch
cli_puts("sender"); cli_delim(":");
cli_puts("recipient"); cli_delim(":");
cli_puts("name"); cli_delim("\n"); // should be last, because name may contain ':'
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) {
++rows;
if (!( sqlite3_column_count(statement) == 4
@ -853,34 +863,12 @@ int rhizome_store_file(rhizome_manifest *m,const unsigned char *key)
if (!m->fileHashedP)
return WHY("Cannot store bundle file until it has been hashed");
int fd=open(file,O_RDONLY);
if (fd == -1) {
WHY_perror("open");
WHY("Could not open associated file");
goto error;
}
struct stat stat;
if (fstat(fd, &stat)) {
WHY_perror("fstat");
WHY("Could not stat() associated file");
goto error;
}
if (stat.st_size<m->fileLength) {
WHYF("File has shrunk, so cannot be stored.");
goto error;
} else if (stat.st_size>m->fileLength) {
WARNF("File has grown by %lld bytes. I will just store the original number of bytes so that the hash (hopefully) matches",stat.st_size-m->fileLength);
}
int fd = -1;
unsigned char *addr = mmap(NULL, m->fileLength, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0);
if (addr==MAP_FAILED) {
WHY_perror("mmap");
WHY("mmap() of associated file failed.");
goto error;
}
/* See if the file is already stored, and if so, don't bother storing it again */
/* See if the file is already stored, and if so, don't bother storing it again.
Do this check BEFORE trying to open the associated file, because if the caller
has received a manifest and checked that it exists in the database, it may
(sensibly) elect not supply the file. Rhizome Direct does this. */
long long count = 0;
if (sqlite_exec_int64(&count, "SELECT COUNT(*) FROM FILES WHERE id='%s' AND datavalid<>0;", hash) < 1) {
WHY("Failed to count stored files");
@ -899,10 +887,41 @@ int rhizome_store_file(rhizome_manifest *m,const unsigned char *key)
goto error;
}
}
close(fd);
return 0;
}
fd = open(file, O_RDONLY);
if (fd == -1) {
WHYF_perror("open(%s)", alloca_str_toprint(file));
WHY("Could not open associated file");
goto error;
}
struct stat stat;
if (fstat(fd, &stat)) {
WHYF_perror("fstat(%d)", fd);
WHY("Could not stat() associated file");
goto error;
}
if (stat.st_size < m->fileLength) {
WHYF("File has shrunk by %lld bytes from %lld to %lld, not stored",
(long long)(m->fileLength - stat.st_size), (long long) m->fileLength, (long long) stat.st_size
);
goto error;
} else if (stat.st_size > m->fileLength) {
// If the file has grown, store the original , in the hope that it will match the hash.
WARNF("File has grown by +%lld bytes to %lld, only storing %lld",
(long long)(stat.st_size - m->fileLength), (long long) stat.st_size, (long long) m->fileLength
);
}
unsigned char *addr = mmap(NULL, m->fileLength, PROT_READ, MAP_SHARED, fd, 0);
if (addr==MAP_FAILED) {
WHYF_perror("mmap(NULL, %lld, PROT_READ, MAP_SHARED, %d, 0)", (long long) m->fileLength, fd);
WHY("mmap() of associated file failed.");
goto error;
}
/* Okay, so there are no records that match, but we should delete any half-baked record (with datavalid=0) so that the insert below doesn't fail.
Don't worry about the return result, since it might not delete any records. */
sqlite_exec_void("DELETE FROM FILES WHERE datavalid=0;");
@ -916,7 +935,8 @@ int rhizome_store_file(rhizome_manifest *m,const unsigned char *key)
int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
*/
sqlite3_stmt *statement = sqlite_prepare("INSERT OR REPLACE INTO FILES(id,data,length,highestpriority,datavalid,inserttime) VALUES('%s',?,%lld,%d,0,%lld);",
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "INSERT OR REPLACE INTO FILES(id,data,length,highestpriority,datavalid,inserttime) VALUES('%s',?,%lld,%d,0,%lld);",
hash, (long long)m->fileLength, priority, (long long)gettime_ms()
);
if (!statement)
@ -928,7 +948,6 @@ int rhizome_store_file(rhizome_manifest *m,const unsigned char *key)
goto insert_row_fail;
}
/* Do actual insert, and abort if it fails */
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
if (_sqlite_exec_void_prepared(__HERE__, LOG_LEVEL_ERROR, &retry, statement) == -1) {
insert_row_fail:
WHYF("Failed to insert row for fileid=%s", hash);
@ -1099,7 +1118,8 @@ int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found,
if (debug & DEBUG_RHIZOME)
DEBUGF("sql query: %s", sqlcmd);
int ret = 0;
sqlite3_stmt *statement = sqlite_prepare("%s", strbuf_str(b));
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "%s", strbuf_str(b));
if (!statement)
return -1;
int field = 1;
@ -1114,7 +1134,6 @@ int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found,
if (checkVersionP)
sqlite3_bind_int64(statement, field++, m->version);
size_t rows = 0;
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) {
++rows;
if (debug & DEBUG_RHIZOME) DEBUGF("Row %d", rows);
@ -1243,13 +1262,13 @@ int rhizome_retrieve_manifest(const char *manifestid, rhizome_manifest **mp)
unsigned char manifest_id[RHIZOME_MANIFEST_ID_BYTES];
if (fromhexstr(manifest_id, manifestid, RHIZOME_MANIFEST_ID_BYTES) == -1)
return WHY("Invalid manifest ID");
sqlite3_stmt *statement = sqlite_prepare("SELECT id, manifest, version, inserttime FROM manifests WHERE id = ?");
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "SELECT id, manifest, version, inserttime FROM manifests WHERE id = ?");
if (!statement)
return -1;
char manifestIdUpper[RHIZOME_MANIFEST_ID_STRLEN + 1];
tohex(manifestIdUpper, manifest_id, RHIZOME_MANIFEST_ID_BYTES);
sqlite3_bind_text(statement, 1, manifestIdUpper, -1, SQLITE_STATIC);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
int ret = 0;
rhizome_manifest *m = NULL;
while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) {
@ -1343,7 +1362,8 @@ int rhizome_retrieve_file(const char *fileid, const char *filepath, const unsign
WHY("Failed to update file priority");
return 0;
}
sqlite3_stmt *statement = sqlite_prepare("SELECT id, rowid, length FROM files WHERE id = ? AND datavalid != 0");
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "SELECT id, rowid, length FROM files WHERE id = ? AND datavalid != 0");
if (!statement)
return -1;
int ret = 0;
@ -1352,7 +1372,6 @@ int rhizome_retrieve_file(const char *fileid, const char *filepath, const unsign
fileIdUpper[RHIZOME_FILEHASH_STRLEN] = '\0';
str_toupper_inplace(fileIdUpper);
sqlite3_bind_text(statement, 1, fileIdUpper, -1, SQLITE_STATIC);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
int stepcode = sqlite_step_retry(&retry, statement);
if (stepcode != SQLITE_ROW) {
ret = 0; // no files found
@ -1433,3 +1452,71 @@ int rhizome_retrieve_file(const char *fileid, const char *filepath, const unsign
sqlite3_finalize(statement);
return ret;
}
int rhizome_import_from_files(const char *manifestpath,const char *filepath)
{
rhizome_manifest *m = rhizome_new_manifest();
if (!m)
return WHY("Out of manifests.");
int status = -1;
if (rhizome_read_manifest_file(m, manifestpath, 0) == -1) {
status = WHY("could not read manifest file");
} else if (rhizome_manifest_verify(m) == -1) {
status = WHY("Could not verify manifest file.");
} else {
/* Make sure we store signatures */
m->manifest_bytes=m->manifest_all_bytes;
/* Add the manifest and its associated file to the Rhizome database. */
m->dataFileName = strdup(filepath);
if (rhizome_manifest_check_file(m))
status = WHY("file does not belong to manifest");
else {
int ret = rhizome_manifest_check_duplicate(m, NULL);
if (ret == -1)
status = WHY("rhizome_manifest_check_duplicate() failed");
else if (ret) {
INFO("Duplicate found in store");
status = 1;
} else if (rhizome_add_manifest(m, 1) == -1) { // ttl = 1
status = WHY("rhizome_add_manifest() failed");
} else {
status = 0;
}
if (status != -1) {
const char *service = rhizome_manifest_get(m, "service", NULL, 0);
if (service) {
cli_puts("service");
cli_delim(":");
cli_puts(service);
cli_delim("\n");
}
{
cli_puts("manifestid");
cli_delim(":");
cli_puts(alloca_tohex(m->cryptoSignPublic, RHIZOME_MANIFEST_ID_BYTES));
cli_delim("\n");
}
cli_puts("filesize");
cli_delim(":");
cli_printf("%lld", m->fileLength);
cli_delim("\n");
if (m->fileLength != 0) {
cli_puts("filehash");
cli_delim(":");
cli_puts(m->fileHexHash);
cli_delim("\n");
}
const char *name = rhizome_manifest_get(m, "name", NULL, 0);
if (name) {
cli_puts("name");
cli_delim(":");
cli_puts(name);
cli_delim("\n");
}
}
}
}
rhizome_manifest_free(m);
return status;
}

855
rhizome_direct.c Normal file
View File

@ -0,0 +1,855 @@
/*
Serval Mesh Software
Copyright (C) 2010-2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Rhizome Direct (github issue #9)
@author Paul Gardner-Stephen <paul@servalproject.org>
The base rhizome protocol allows the automatic and progressive transfer of data
bundles (typically files and their associated meta-data) between devices sharing
a common network interface.
There are several use-cases where that is insufficient, e.g.:
1. User wishes to cause two near-by devices to completely synchronise, e.g., as
part of a regular data courier activity, or a field operation centre wishing to
extract all field-collected data from a device, and possibly provide the field
device with updated operational information and software.
2. Two remote devices wish to synchronise, e.g., redundant Serval Rhizome servers
forming part of a humanitarian or governmental emergency/disaster response
capability.
3. As (2), but with regular synchronisation.
In all cases what is required is a mechanism for one Serval daemon instance to
communicate via another Serval daemon instance, and determine the bundles that
need to be transfered in each direction, and effect those transfers.
Several challenges complicate this objective:
1. Network Address Translation (NAT) or some other barrier may make it impossible
for one of the devices to initiate a TCP connection to the other device. Thus
the protocol must be able to operate "one-sided", yet be able to synchronise
bundles in both directions.
2. The protocol must not impair the real-time requirements of the Serval daemon
at either end. Therefore the protocol must be implemented in a separate thread
or process. As the Serval design is for single-threaded processes to improve
portability and reliability, a separate process will be used. That separate
process will be another instance of the Serval daemon that will be run from the
command line, and terminate when the synchronisation has completed, or when it
receives an appropriate signal. This approach also ensures that the Rhizome
databases at each end will always be consistent (or more properly, not become
inconsistent due to the operation of this protocol).
The test suites to exercise this protocol are located in "tests/rhizomeprotocol".
The above functionality resolves down to several specific functions:
1. Ability to enquire running servald and generate a list of BARs that it has
stored, and present that list of "IHAVE"'s to the far end for examination.
2. Ability to respond to such a list of BAR's, compare the list to the local
servald instance's Rhizome database, and send back a list of "IHAVE"'s for any
bundles that are newer than those presented in the list, or that were not present
in the list.
3. Ability to parse such a list of "IHAVE"'s, and from that determine the set of
bundles to synchronise in each direction.
4. As each server may have very many bundles, the above transactions must be able
to operate on a limited range of bundle-IDs. Each request shall therefore include
the lowest and highest bundle-ID covered by the list.
Note that the above actions are between the two Rhizome Direct processes, and not
the Serval daemon processes (although each Rhizome Direct process will necessarily
need to communicate with their local Serval daemon instances).
5. Ability to present a BAR to the remote end Serval daemon instance and fetch the
associated data bundle, and then present it to the local Serval daemon instance
for adding to the local Rhizome database.
It is recognised that the Serval daemon's real-time behaviour is compromised by
the current mechanism for importing bundles into the Rhizome database. This will
be addressed as part of the on-going development of the main Rhizome protocol, and
its rectification is beyond the scope of Rhizome Direct.
6. Ability to present manifest and associated data for a bundle to the remote
Rhizome Direct process for that process to schedule its insertion into the Rhizome
database.
As with the existing Rhizome protocol, it seems reasonable to use HTTP as the
basis. The interactions will be M2M, so we do not need a fully-fledged HTTP
server at this stage, but can make use of our own spartan HTTP server already
integrated into servald.
In light of the above, all rhizome services and HTTP services are being
transitioned from running in the main servald process, into a separate process
started by servald calling fork() (but not exec, since the same starting image
will be fine).
*/
#include "serval.h"
#include "rhizome.h"
#include "str.h"
#include <assert.h>
rhizome_direct_sync_request *rd_sync_handles[RHIZOME_DIRECT_MAX_SYNC_HANDLES];
int rd_sync_handle_count=0;
/* Create (but don't start) a rhizome direct sync request.
This creates the record to say that we want to undertake this synchronisation,
either once or at intervals as specified.
The start process actually triggers the first filling of a cursor buffer, and
then calls the transport specific dispatch function. The transport specific
dispatch function is expected to be asynchronous, and to call the continue
process.
The transport specific dispatch function is also expected to tell rhizome
direct about which bundles to send or receive, or to fetch/push them itself.
For IP-based transports, the built-in http transport will be suitable in
many cases. For non-IP transports the transport will have to take care of
the bundle transport as well.
*/
rhizome_direct_sync_request
*rhizome_direct_new_sync_request(
void (*transport_specific_dispatch_function)
(struct rhizome_direct_sync_request *),
int buffer_size,int interval, int mode, void *state)
{
assert(mode&3);
if (rd_sync_handle_count>=RHIZOME_DIRECT_MAX_SYNC_HANDLES)
{
DEBUGF("Too many Rhizome Direct synchronisation policies.");
return NULL;
}
rhizome_direct_sync_request *r=calloc(sizeof(rhizome_direct_sync_request),1);
assert(r!=NULL);
r->dispatch_function=transport_specific_dispatch_function;
r->transport_specific_state=state;
r->pushP=mode&1;
r->pullP=mode&2;
r->interval=interval;
r->cursor=rhizome_direct_bundle_iterator(buffer_size);
assert(r->cursor);
rd_sync_handles[rd_sync_handle_count++]=r;
return r;
}
/*
Initiate a synchronisation episode.
*/
int rhizome_direct_start_sync_request(rhizome_direct_sync_request *r)
{
assert(r);
assert(r->syncs_started==r->syncs_completed);
r->syncs_started++;
return rhizome_direct_continue_sync_request(r);
}
int rhizome_direct_continue_sync_request(rhizome_direct_sync_request *r)
{
assert(r);
assert(r->syncs_started==r->syncs_completed+1);
/* We might not get any BARs in the final fill, but it doesn't mean that
this cursor fill didn't cover a part of the BAR address space, so we
still have to send it.
We detect completion solely by whether on entering the call we have no
more BAR address space or bundle data size bin space left to explore.
In short, if the cursor's current position is the limit position,
then we can stop.
*/
if (r->cursor->size_high>=r->cursor->limit_size_high)
{
DEBUG("Out of bins");
if (memcmp(r->cursor->bid_low,r->cursor->limit_bid_high,
RHIZOME_MANIFEST_ID_BYTES)>=0)
{
DEBUG("out of BIDs");
/* Sync has finished.
The transport may have initiated one or more transfers, so
we cannot declare the sync complete until we know the transport
has finished transferring. */
if (!r->bundle_transfers_in_progress)
{
/* seems that all is done */
DEBUG("All done");
return rhizome_direct_conclude_sync_request(r);
} else
DEBUG("Stuck on in-progress transfers");
} else
DEBUGF("bid_low<limit_bid_high");
}
int count=rhizome_direct_bundle_iterator_fill(r->cursor,-1);
DEBUGF("Got %d BARs",count);
dump("BARs",r->cursor->buffer,
r->cursor->buffer_used+r->cursor->buffer_offset_bytes);
r->dispatch_function(r);
r->fills_sent++;
return count;
}
int rhizome_direct_conclude_sync_request(rhizome_direct_sync_request *r)
{
assert(r);
r->syncs_completed++;
/* reschedule if interval driven?
if one-shot, should we remove from the list of active sync requests?
*/
if (r->interval==0) {
DEBUG("concluding one-shot");
int i;
for(i=0;i<rd_sync_handle_count;i++)
if (r==rd_sync_handles[i])
{
DEBUG("Found it");
rhizome_direct_bundle_iterator_free(&r->cursor);
free(r);
if (i!=rd_sync_handle_count-1)
rd_sync_handles[i]=rd_sync_handles[rd_sync_handle_count-1];
rd_sync_handle_count--;
DEBUGF("handle count=%d",rd_sync_handle_count);
return 0;
}
DEBUGF("Couldn't find sync request handle in list.");
return -1;
}
return 0;
}
/*
This function is called with the list of BARs for a specified cursor range
that the far-end possesses, i.e., what we are given is a list of the far end's
"I have"'s. To produce our reply, we need to work out corresponding list of
"I have"'s, and then compare them to produce the list of "you have and I want"
and "I have and you want" that if fulfilled, would result in both ends having the
same set of BARs for the specified cursor range. The potential presense of
multiple versions of a given bundle introduces only a slight complication.
*/
rhizome_direct_bundle_cursor *rhizome_direct_get_fill_response
(unsigned char *buffer,int size, int max_response_bytes)
{
if (size<10) return NULL;
if (size>65536) return NULL;
if (max_response_bytes<10) return NULL;
if (max_response_bytes>1048576) return NULL;
int them_count=(size-10)/RHIZOME_BAR_BYTES;
/* We need to get a list of BARs that will fit into max_response_bytes when we
have summarised them into (1+RHIZOME_BAR_PREFIX_BYTES)-byte PUSH/PULL hints.
So we need an intermediate buffer that is somewhat larger to allow the actual
maximum response buffer to be completely filled. */
int max_intermediate_bytes
=10+((max_response_bytes-10)/(1+RHIZOME_BAR_PREFIX_BYTES))*RHIZOME_BAR_BYTES;
unsigned char usbuffer[max_intermediate_bytes];
rhizome_direct_bundle_cursor
*c=rhizome_direct_bundle_iterator(max_intermediate_bytes);
assert(c!=NULL);
if (rhizome_direct_bundle_iterator_unpickle_range(c,buffer,10))
{
DEBUGF("Couldn't unpickle range");
rhizome_direct_bundle_iterator_free(&c);
return NULL;
}
DEBUGF("unpickled size_high=%lld, limit_size_high=%lld",
c->size_high,c->limit_size_high);
DEBUGF("c->buffer_size=%d",c->buffer_size);
/* Get our list of BARs for the same cursor range */
int us_count=rhizome_direct_bundle_iterator_fill(c,-1);
DEBUGF("Found %d manifests in that range",us_count);
/* Transfer to a temporary buffer, so that we can overwrite
the cursor's buffer with the response data. */
bcopy(c->buffer,usbuffer,10+us_count*RHIZOME_BAR_BYTES);
c->buffer_offset_bytes=10;
c->buffer_used=0;
/* Iterate until we are through both lists.
Note that the responses are (1+RHIZOME_BAR_PREFIX_BYTES)-bytes each, much
smaller than the 32 bytes used by BARs, therefore the response will never be
bigger than the request, and so we don't need to worry about overflows. */
int them=0,us=0;
DEBUGF("themcount=%d, uscount=%d",them_count,us_count);
while(them<them_count||us<us_count)
{
DEBUGF("them=%d, us=%d",them,us);
unsigned char *them_bar=&buffer[10+them*RHIZOME_BAR_BYTES];
unsigned char *us_bar=&usbuffer[10+us*RHIZOME_BAR_BYTES];
int relation=0;
if (them<them_count&&us<us_count) {
relation=memcmp(them_bar,us_bar,RHIZOME_BAR_COMPARE_BYTES);
DEBUGF("relation = %d",relation);
dump("them BAR",them_bar,RHIZOME_BAR_BYTES);
dump("us BAR",us_bar,RHIZOME_BAR_BYTES);
}
else if (us==us_count) relation=-1; /* they have a bundle we don't have */
else if (them==them_count) relation=+1; /* we have a bundle they don't have */
else {
DEBUGF("This should never happen.");
break;
}
int who=0;
if (relation<0) {
/* They have a bundle that we don't have any version of.
Append 16-byte "please send" record consisting of 0x01 followed
by the eight-byte BID prefix from the BAR. */
c->buffer[c->buffer_offset_bytes+c->buffer_used]=0x01; /* Please send */
bcopy(&buffer[10+them*RHIZOME_BAR_BYTES+RHIZOME_BAR_PREFIX_OFFSET],
&c->buffer[c->buffer_offset_bytes+c->buffer_used+1],
RHIZOME_BAR_PREFIX_BYTES);
c->buffer_used+=1+RHIZOME_BAR_PREFIX_BYTES;
who=-1;
DEBUGF("They have previously unseen bundle %016llx*",
rhizome_bar_bidprefix_ll(&buffer[10+them*RHIZOME_BAR_BYTES]));
} else if (relation>0) {
/* We have a bundle that they don't have any version of
Append 16-byte "I have [newer]" record consisting of 0x02 followed
by the eight-byte BID prefix from the BAR. */
c->buffer[c->buffer_offset_bytes+c->buffer_used]=0x02; /* I have [newer] */
bcopy(&usbuffer[10+us*RHIZOME_BAR_BYTES+RHIZOME_BAR_PREFIX_OFFSET],
&c->buffer[c->buffer_offset_bytes+c->buffer_used+1],
RHIZOME_BAR_PREFIX_BYTES);
c->buffer_used+=1+RHIZOME_BAR_PREFIX_BYTES;
who=+1;
DEBUGF("We have previously unseen bundle %016llx*",
rhizome_bar_bidprefix_ll(&usbuffer[10+us*RHIZOME_BAR_BYTES]));
} else {
/* We each have a version of this bundle, so see whose is newer */
long long them_version
=rhizome_bar_version(&buffer[10+them*RHIZOME_BAR_BYTES]);
long long us_version
=rhizome_bar_version(&usbuffer[10+us*RHIZOME_BAR_BYTES]);
if (them_version>us_version) {
/* They have the newer version of the bundle */
c->buffer[c->buffer_offset_bytes+c->buffer_used]=0x01; /* Please send */
bcopy(&buffer[10+them*RHIZOME_BAR_BYTES+RHIZOME_BAR_PREFIX_OFFSET],
&c->buffer[c->buffer_offset_bytes+c->buffer_used+1],
RHIZOME_BAR_PREFIX_BYTES);
c->buffer_used+=1+RHIZOME_BAR_PREFIX_BYTES;
DEBUGF("They have newer version of bundle %016llx* (%lld versus %lld)",
rhizome_bar_bidprefix_ll(&usbuffer[10+us*RHIZOME_BAR_BYTES]),
rhizome_bar_version(&usbuffer[10+us*RHIZOME_BAR_BYTES]),
rhizome_bar_version(&buffer[10+them*RHIZOME_BAR_BYTES]));
} else if (them_version<us_version) {
/* We have the newer version of the bundle */
c->buffer[c->buffer_offset_bytes+c->buffer_used]=0x02; /* I have [newer] */
bcopy(&usbuffer[10+us*RHIZOME_BAR_BYTES+RHIZOME_BAR_PREFIX_OFFSET],
&c->buffer[c->buffer_offset_bytes+c->buffer_used+1],
RHIZOME_BAR_PREFIX_BYTES);
c->buffer_used+=1+RHIZOME_BAR_PREFIX_BYTES;
DEBUGF("We have newer version of bundle %016llx* (%lld versus %lld)",
rhizome_bar_bidprefix_ll(&usbuffer[10+us*RHIZOME_BAR_BYTES]),
rhizome_bar_version(&usbuffer[10+us*RHIZOME_BAR_BYTES]),
rhizome_bar_version(&buffer[10+them*RHIZOME_BAR_BYTES]));
} else {
DEBUGF("We both have the same version of %016llx*",
rhizome_bar_bidprefix_ll(&buffer[10+them*RHIZOME_BAR_BYTES]));
}
}
/* Advance through lists accordingly */
switch(who) {
case -1: them++; break;
case +1: us++; break;
case 0: them++; us++; break;
}
}
return c;
}
rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix,int prefix_length)
{
/* Give a BID prefix, e.g., from a BAR, find the matching manifest and return it.
Of course, it is possible that more than one manifest matches. This should
occur only very rarely (with the possible exception of intentional attack, and
even then a 64-bit prefix creates a reasonable barrier. If we move to a new
BAR format with 120 or 128 bits of BID prefix, then we should be safe for some
time, thus this function taking the BID prefix as an input in preparation for
that change).
Of course, we need to be able to find the manifest.
Easiest way is to select with a BID range. We could instead have an extra
database column with the prefix.
*/
assert(prefix_length>=0);
assert(prefix_length<=RHIZOME_MANIFEST_ID_BYTES);
DEBUGF("here");
unsigned char low[RHIZOME_MANIFEST_ID_BYTES];
unsigned char high[RHIZOME_MANIFEST_ID_BYTES];
memset(low,0x00,RHIZOME_MANIFEST_ID_BYTES);
memset(high,0xff,RHIZOME_MANIFEST_ID_BYTES);
bcopy(bid_prefix,low,prefix_length);
bcopy(bid_prefix,high,prefix_length);
char query[1024];
snprintf(query,1024,"SELECT MANIFEST,ROWID FROM MANIFESTS WHERE ID>='%s' AND ID<='%s'",
alloca_tohex(low,RHIZOME_MANIFEST_ID_BYTES),
alloca_tohex(high,RHIZOME_MANIFEST_ID_BYTES));
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, query);
sqlite3_blob *blob=NULL;
if (sqlite_step_retry(&retry, statement) == SQLITE_ROW)
{
int ret;
int64_t rowid = sqlite3_column_int64(statement, 1);
do ret = sqlite3_blob_open(rhizome_db, "main", "manifests", "bar",
rowid, 0 /* read only */, &blob);
while (sqlite_code_busy(ret) && sqlite_retry(&retry, "sqlite3_blob_open"));
if (!sqlite_code_ok(ret)) {
WHYF("sqlite3_blob_open() failed, %s", sqlite3_errmsg(rhizome_db));
sqlite3_finalize(statement);
return NULL;
}
sqlite_retry_done(&retry, "sqlite3_blob_open");
/* Read manifest data from blob */
size_t manifestblobsize = sqlite3_column_bytes(statement, 0);
if (manifestblobsize<1||manifestblobsize>1024) goto error;
const char *manifestblob = (char *) sqlite3_column_blob(statement, 0);
if (!manifestblob) goto error;
rhizome_manifest *m=rhizome_new_manifest();
if (rhizome_read_manifest_file(m,manifestblob,manifestblobsize)==-1)
{
rhizome_manifest_free(m);
goto error;
}
DEBUGF("Read manifest");
sqlite3_blob_close(blob);
sqlite3_finalize(statement);
return m;
error:
sqlite3_blob_close(blob);
sqlite3_finalize(statement);
return NULL;
}
else
{
DEBUGF("no matching manifests");
sqlite3_finalize(statement);
return NULL;
}
}
int app_rhizome_direct_sync(int argc, const char *const *argv, struct command_line_option *o, void *context)
{
/* Attempt to connect with a remote Rhizome Direct instance,
and negotiate which BARs to synchronise. */
const char *modeName = (argc >= 3 ? argv[2] : "sync");
int mode=3; /* two-way sync */
if (!strcasecmp(modeName,"push")) mode=1; /* push only */
if (!strcasecmp(modeName,"pull")) mode=2; /* pull only */
DEBUGF("sync direction = %d",mode);
/* Get iterator capable of 64KB buffering.
In future we should parse the sync URL and base the buffer size on the
transport and allowable traffic volumes. */
rhizome_direct_transport_state_http
*state=calloc(sizeof(rhizome_direct_transport_state_http),1);
const char *sync_url=NULL;
int peer_count=confValueGetInt64("rhizome.direct.peer.count",0);
int peer_number=0;
char peer_var[128];
if (argv[3]) {
peer_count=1;
sync_url=argv[3];
}
if (peer_count<1) {
DEBUG("No rhizome direct peers were configured or supplied.");
}
/* XXX This code runs each sync in series, when we can probably do them in
parallel. But we can't really do them in parallel until we make the
synchronisation process fully asynchronous, which probably won't happen
for a while yet.
Also, we don't currently parse the URI protocol field fully. */
next_peer:
if (!sync_url) {
snprintf(peer_var,128,"rhizome.direct.peer.%d",peer_number);
sync_url=confValueGet(peer_var, NULL);
}
if (strlen(sync_url)>1020)
{
DEBUG("rhizome direct URI too long");
return -1;
}
char protocol[1024];
state->port=RHIZOME_HTTP_PORT;
int ok=0;
if (sscanf(sync_url,"%[^:]://%[^:]:%d",protocol,state->host,&state->port)>=2)
ok=1;
if (!ok) sprintf(protocol,"http");
if ((!ok)&&(sscanf(sync_url,"%[^:]:%d",state->host,&state->port)>=1))
ok=2;
if (!ok)
{
DEBUG("could not parse rhizome direct URI");
return -1;
}
DEBUGF("Rhizome direct peer is %s://%s:%d (parse route %d)",
protocol,state->host,state->port,ok);
if (strcasecmp(protocol,"http")) {
DEBUG("Unsupport Rhizome Direct synchronisation protocol."
" Only HTTP is supported at present.");
return -1;
}
rhizome_direct_sync_request
*s = rhizome_direct_new_sync_request(rhizome_direct_http_dispatch,
65536,0,mode,state);
rhizome_direct_start_sync_request(s);
if (rd_sync_handle_count>0)
while(fd_poll()&&(rd_sync_handle_count>0)) continue;
sync_url=NULL;
peer_number++;
if (peer_number<peer_count) goto next_peer;
return 0;
}
rhizome_direct_bundle_cursor *rhizome_direct_bundle_iterator(int buffer_size)
{
rhizome_direct_bundle_cursor *r=calloc(sizeof(rhizome_direct_bundle_cursor),1);
assert(r!=NULL);
r->buffer=malloc(buffer_size);
assert(r->buffer);
r->buffer_size=buffer_size;
r->size_low=0;
r->size_high=1024;
/* Make cursor initially unlimited in range */
rhizome_direct_bundle_iterator_unlimit(r);
return r;
}
void rhizome_direct_bundle_iterator_unlimit(rhizome_direct_bundle_cursor *r)
{
assert(r!=NULL);
r->limit_size_high=1LL<<48LL;
memset(r->limit_bid_high,0xff,RHIZOME_MANIFEST_ID_BYTES);
return;
}
int rhizome_direct_bundle_iterator_pickle_range(rhizome_direct_bundle_cursor *r,
unsigned char *pickled,
int pickle_buffer_size)
{
assert(r);
assert(pickle_buffer_size>=(1+4+1+4));
/* Pickled cursor ranges use the format:
byte - log2(start_size_high)
4 bytes - first eight bytes of start_bid_low.
byte - log2(size_high)
4 bytes - first eight bytes of bid_high.
For a total of 10 bytes.
We can get away with the short prefixes for the BIDs, because the worst case
scenario is that we include a small part of the BID address space that we
don't need to. That will happen MUCH less often than transferring cursor
ranges, which will happen with every rhizome direct sync.
*/
long long v;
int ltwov=0;
v=r->start_size_high;
while(v>1) { ltwov++; v=v>>1; }
pickled[0]=ltwov;
for(v=0;v<4;v++) pickled[1+v]=r->start_bid_low[v];
v=r->size_high;
DEBUGF("pickling size_high=%lld",r->size_high);
ltwov=0;
while(v>1) { ltwov++; v=v>>1; }
pickled[1+4]=ltwov;
for(v=0;v<4;v++) pickled[1+4+1+v]=r->bid_high[v];
return 1+4+1+4;
}
int rhizome_direct_bundle_iterator_unpickle_range(rhizome_direct_bundle_cursor *r,
const unsigned char *pickled,
int pickle_buffer_size)
{
assert(r);
if (pickle_buffer_size!=10) {
DEBUGF("pickled rhizome direct cursor ranges should be 10 bytes.");
return -1;
}
int v;
/* Get start of range */
r->size_high=1LL<<pickled[0];
r->size_low=(r->size_high/2)+1;
if (r->size_high<=1024) r->size_low=0;
for(v=0;v<4;v++) r->bid_low[v]=pickled[1+v];
for(;v<RHIZOME_MANIFEST_ID_BYTES;v++) r->bid_low[v]=0x00;
/* Get end of range */
r->limit_size_high=1LL<<pickled[1+4];
for(v=0;v<4;v++) r->limit_bid_high[v]=pickled[1+4+1+v];
for(;v<RHIZOME_MANIFEST_ID_BYTES;v++) r->limit_bid_high[v]=0xff;
return 0;
}
int rhizome_direct_bundle_iterator_fill(rhizome_direct_bundle_cursor *c,int max_bars)
{
int bundles_stuffed=0;
c->buffer_used=0;
/* Note where we are starting the cursor fill from, so that the caller can easily
communicate the range of interest to the far end. We will eventually have a
cursor set function that will allow that information to be loaded back in at
the far end. We will similarly need to have a mechanism to limit the end of
the range that the cursor will cover, so that responses to the exact range
covered can be provided.. But first things first, remembering where the cursor
started.
We keep the space for the pickled cursor range at the start of the buffer,
and fill it in at the end.
*/
/* This is the only information required to remember where we started: */
c->start_size_high=c->size_high;
bcopy(c->bid_low,c->start_bid_low,RHIZOME_MANIFEST_ID_BYTES);
c->buffer_offset_bytes=1+4+1+4; /* space for pickled cursor range */
/* -1 is magic value for fill right up */
if (max_bars==-1)
max_bars=(c->buffer_size-c->buffer_offset_bytes)/RHIZOME_BAR_BYTES;
DEBUGF("Iterating cursor size high %lld..%lld, max_bars=%d",
c->size_high,c->limit_size_high,max_bars);
while (bundles_stuffed<max_bars&&c->size_high<=c->limit_size_high)
{
/* Don't overrun the cursor's buffer */
int stuffable
=(c->buffer_size-c->buffer_used-c->buffer_offset_bytes)/RHIZOME_BAR_BYTES;
if (stuffable<=0) break;
/* Make sure we only get the range of BIDs allowed by the cursor limit.
If we are not yet at the bundle data size limit, then any bundle is okay.
If we are at the bundle data size limit, then we need to honour
c->limit_bid_high. */
unsigned char bid_max[RHIZOME_MANIFEST_ID_BYTES];
if (c->size_high==c->limit_size_high)
bcopy(c->limit_bid_high,bid_max,RHIZOME_MANIFEST_ID_BYTES);
else
memset(bid_max,0xff,RHIZOME_MANIFEST_ID_BYTES);
int stuffed_now=rhizome_direct_get_bars(c->bid_low,c->bid_high,
c->size_low,c->size_high,
bid_max,
&c->buffer[c->buffer_used
+c->buffer_offset_bytes],
stuffable);
bundles_stuffed+=stuffed_now;
c->buffer_used+=RHIZOME_BAR_BYTES*stuffed_now;
if (!stuffed_now) {
/* no more matches in this size bin, so move up a size bin */
c->size_low=c->size_high+1;
c->size_high*=2;
if (c->size_high<=1024) c->size_low=0;
DEBUGF("size=%lld..%lld",c->size_low,c->size_high);
/* Record that we covered to the end of that size bin */
memset(c->bid_high,0xff,RHIZOME_MANIFEST_ID_BYTES);
if (c->size_high>c->limit_size_high)
memset(c->bid_low,0xff,RHIZOME_MANIFEST_ID_BYTES);
else
memset(c->bid_low,0x00,RHIZOME_MANIFEST_ID_BYTES);
} else {
/* Continue from next BID */
bcopy(c->bid_high,c->bid_low,RHIZOME_MANIFEST_ID_BYTES);
int i;
for(i=RHIZOME_BAR_BYTES-1;i>=0;i--)
{
c->bid_low[i]++;
if (c->bid_low[i]) break;
}
if (i<0) break;
}
}
/* Record range of cursor that this call covered. */
rhizome_direct_bundle_iterator_pickle_range(c,c->buffer,c->buffer_offset_bytes);
return bundles_stuffed;
}
void rhizome_direct_bundle_iterator_free(rhizome_direct_bundle_cursor **c)
{
free((*c)->buffer); (*c)->buffer=NULL;
bzero(*c,sizeof(rhizome_direct_bundle_cursor));
*c=NULL;
}
/* Read upto the <bars_requested> next BARs from the Rhizome database,
beginning from the first BAR that corresponds to a manifest with
BID>=<bid_low>.
Sets <bid_high> to the highest BID for which a BAR was returned.
Return value is the number of BARs written into <bars_out>.
Only returns BARs for bundles within the specified size range.
This is used by the cursor wrapper function that passes over all of the
BARs in prioritised order.
XXX Once the rhizome database gets big, we will need to make sure
that we have suitable indexes. It is tempting to just pack BARs
by row_id, but the far end needs them in an orderly manner so that
it is possible to make provably complete comparison of the contents
of the respective rhizome databases.
*/
int rhizome_direct_get_bars(const unsigned char bid_low[RHIZOME_MANIFEST_ID_BYTES],
unsigned char bid_high[RHIZOME_MANIFEST_ID_BYTES],
long long size_low,long long size_high,
const unsigned char bid_max[RHIZOME_MANIFEST_ID_BYTES],
unsigned char *bars_out,
int bars_requested)
{
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
char query[1024];
snprintf(query,1024,
"SELECT BAR,ROWID,ID,FILESIZE FROM MANIFESTS"
" WHERE"
" FILESIZE BETWEEN %lld AND %lld"
" AND ID>='%s' AND ID<='%s'"
// The following formulation doesn't remove the weird returning of
// bundles with out of range filesize values
// " WHERE ID>='%s' AND ID<='%s' AND FILESIZE > %lld AND FILESIZE < %lld"
" ORDER BY BAR LIMIT %d;",
size_low, size_high,
alloca_tohex(bid_low,RHIZOME_MANIFEST_ID_BYTES),
alloca_tohex(bid_max,RHIZOME_MANIFEST_ID_BYTES),
bars_requested);
sqlite3_stmt *statement=sqlite_prepare(&retry, query);
sqlite3_blob *blob=NULL;
int bars_written=0;
while(bars_written<bars_requested
&& sqlite_step_retry(&retry, statement) == SQLITE_ROW)
{
int column_type=sqlite3_column_type(statement, 0);
switch(column_type) {
case SQLITE_BLOB:
if (blob)
sqlite3_blob_close(blob);
blob = NULL;
int ret;
int64_t filesize = sqlite3_column_int64(statement, 3);
if (filesize<size_low||filesize>size_high) {
DEBUGF("WEIRDNESS ALERT: filesize=%lld, but query was: %s",
filesize,query);
break;
}
int64_t rowid = sqlite3_column_int64(statement, 1);
do ret = sqlite3_blob_open(rhizome_db, "main", "manifests", "bar",
rowid, 0 /* read only */, &blob);
while (sqlite_code_busy(ret) && sqlite_retry(&retry, "sqlite3_blob_open"));
if (!sqlite_code_ok(ret)) {
WHYF("sqlite3_blob_open() failed, %s", sqlite3_errmsg(rhizome_db));
continue;
}
sqlite_retry_done(&retry, "sqlite3_blob_open");
int blob_bytes=sqlite3_blob_bytes(blob);
if (blob_bytes!=RHIZOME_BAR_BYTES) {
if (debug&DEBUG_RHIZOME)
DEBUG("Found a BAR that is the wrong size - ignoring");
sqlite3_blob_close(blob);
blob=NULL;
continue;
}
sqlite3_blob_read(blob,&bars_out[bars_written*RHIZOME_BAR_BYTES],
RHIZOME_BAR_BYTES,0);
sqlite3_blob_close(blob);
blob=NULL;
/* Remember the BID so that we cant write it into bid_high so that the
caller knows how far we got. */
fromhex(bid_high,
(const char *)sqlite3_column_text(statement, 2),
RHIZOME_MANIFEST_ID_BYTES);
bars_written++;
break;
default:
/* non-BLOB field. This is an error, but we will persevere with subsequent
rows, because they might be fine. */
break;
}
}
if (statement)
sqlite3_finalize(statement);
statement = NULL;
return bars_written;
}

1063
rhizome_direct_http.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <time.h>
#include <arpa/inet.h>
#include <assert.h>
#include "serval.h"
#include "rhizome.h"
#include "str.h"
@ -31,6 +33,7 @@ typedef struct rhizome_file_fetch_record {
rhizome_manifest *manifest;
char fileid[RHIZOME_FILEHASH_STRLEN + 1];
FILE *file;
char filename[1024];
char request[1024];
int request_len;
@ -46,6 +49,8 @@ typedef struct rhizome_file_fetch_record {
#define RHIZOME_FETCH_RXHTTPHEADERS 3
#define RHIZOME_FETCH_RXFILE 4
struct sockaddr_in peer;
} rhizome_file_fetch_record;
struct profile_total fetch_stats;
@ -382,27 +387,13 @@ int rhizome_position_candidate(int position)
void rhizome_import_received_bundle(struct rhizome_manifest *m)
{
// TODO: We already have the manifest struct in memory, should import the bundle
// directly from that, not by writing it to a file and re-reading it!
const char *id = rhizome_manifest_get(m, "id", NULL, 0);
if (id == NULL) {
WHY("Manifest missing ID");
return;
}
if (create_rhizome_import_dir() == -1)
return;
char filename[1024];
if (!FORM_RHIZOME_IMPORT_PATH(filename, "manifest.%s", id))
return;
/* Do really write the manifest unchanged */
m->finalised = 1;
m->manifest_bytes = m->manifest_all_bytes;
m->manifest_bytes = m->manifest_all_bytes; // store the signatures too
if (debug & DEBUG_RHIZOME_RX) {
DEBUGF("manifest bid=%s len=%d has %d signatories", id, m->manifest_bytes, m->sig_count);
DEBUGF("manifest len=%d has %d signatories", m->manifest_bytes, m->sig_count);
dump("manifest", m->manifestdata, m->manifest_all_bytes);
}
if (rhizome_write_manifest_file(m, filename) != -1)
rhizome_bundle_import(m, NULL, id, m->ttl - 1 /* TTL */);
rhizome_bundle_import(m, m->ttl - 1 /* TTL */);
}
/* Verifies manifests as late as possible to avoid wasting time. */
@ -518,7 +509,7 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, struct sockaddr_i
candidates[i].peer=*peerip;
int j;
if (0) {
if (1) {
DEBUG("Rhizome priorities fetch list now:");
for(j=0;j<candidate_count;j++)
DEBUGF("%02d:%s:size=%lld, priority=%d",
@ -552,9 +543,11 @@ void rhizome_enqueue_suggestions(struct sched_ent *alarm)
bcopy(&candidates[i],&candidates[0],bytes);
candidate_count-=i;
}
alarm->alarm = gettime_ms() + rhizome_fetch_interval_ms;
alarm->deadline = alarm->alarm + rhizome_fetch_interval_ms*3;
schedule(alarm);
if (alarm) {
alarm->alarm = gettime_ms() + rhizome_fetch_interval_ms;
alarm->deadline = alarm->alarm + rhizome_fetch_interval_ms*3;
schedule(alarm);
}
return;
}
@ -579,7 +572,7 @@ int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peeri
the cache slot number to implicitly store the first bits.
*/
if (debug & DEBUG_RHIZOME_RX)
if (1||debug & DEBUG_RHIZOME_RX)
DEBUGF("Fetching manifest bid=%s version=%lld size=%lld:", bid, m->version, filesize);
if (rhizome_manifest_version_cache_lookup(m)) {
@ -601,10 +594,12 @@ int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peeri
/* Don't queue if already queued */
int i;
for (i = 0; i < rhizome_file_fetch_queue_count; ++i) {
if (memcmp(m->cryptoSignPublic, file_fetch_queue[i].manifest->cryptoSignPublic, RHIZOME_MANIFEST_ID_BYTES) == 0) {
if (debug & DEBUG_RHIZOME_RX)
DEBUGF(" manifest fetch already queued");
return 3;
if (file_fetch_queue[i].manifest) {
if (memcmp(m->cryptoSignPublic, file_fetch_queue[i].manifest->cryptoSignPublic, RHIZOME_MANIFEST_ID_BYTES) == 0) {
if (debug & DEBUG_RHIZOME_RX)
DEBUGF(" manifest fetch already queued");
return 3;
}
}
}
@ -642,15 +637,15 @@ int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peeri
close(sock);
return -1;
}
dump("copying peerip",peerip,sizeof(*peerip));
struct sockaddr_in addr = *peerip;
addr.sin_family = AF_INET;
INFOF("RHIZOME HTTP REQUEST, CONNECT family=%u port=%u addr=%u.%u.%u.%u",
addr.sin_family, ntohs(addr.sin_port),
((unsigned char*)&addr.sin_addr.s_addr)[0],
((unsigned char*)&addr.sin_addr.s_addr)[1],
((unsigned char*)&addr.sin_addr.s_addr)[2],
((unsigned char*)&addr.sin_addr.s_addr)[3]
);
char buf[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &addr.sin_addr, buf, sizeof buf) == NULL) {
buf[0] = '*';
buf[1] = '\0';
}
INFOF("RHIZOME HTTP REQUEST, CONNECT family=%u port=%u addr=%s", addr.sin_family, ntohs(addr.sin_port), buf);
if (connect(sock, (struct sockaddr*)&addr, sizeof addr) == -1) {
if (errno == EINPROGRESS) {
if (debug & DEBUG_RHIZOME_RX)
@ -665,6 +660,7 @@ int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peeri
rhizome_file_fetch_record *q=&file_fetch_queue[rhizome_file_fetch_queue_count];
q->manifest = m;
*manifest_kept = 1;
bcopy(&addr,&q->peer,sizeof(q->peer));
q->alarm.poll.fd=sock;
strncpy(q->fileid, m->fileHexHash, RHIZOME_FILEHASH_STRLEN + 1);
q->request_len = snprintf(q->request, sizeof q->request, "GET /rhizome/file/%s HTTP/1.0\r\n\r\n", q->fileid);
@ -719,20 +715,11 @@ int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peeri
/* TODO: fetch via overlay */
return WHY("Rhizome fetching via overlay not implemented");
}
} else {
if (debug & DEBUG_RHIZOME_RX)
DEBUGF("We already have the file for this manifest; importing from manifest alone.");
rhizome_bundle_import(m, m->ttl-1);
}
else
{
if (debug & DEBUG_RHIZOME_RX)
DEBUGF("We already have the file for this manifest; importing from manifest alone.");
if (create_rhizome_import_dir() == -1)
return -1;
char filename[1024];
if (!FORM_RHIZOME_IMPORT_PATH(filename, "manifest.%s", bid))
return -1;
if (!rhizome_write_manifest_file(m, filename)) {
rhizome_bundle_import(m, NULL, bid, m->ttl-1);
}
}
}
return 0;
@ -761,6 +748,8 @@ int rhizome_fetch_close(rhizome_file_fetch_record *q){
}
void rhizome_fetch_write(rhizome_file_fetch_record *q){
if (debug & DEBUG_RHIZOME_RX)
DEBUGF("write_nonblock(%d, %s)", q->alarm.poll.fd, alloca_toprint(-1, &q->request[q->request_ofs], q->request_len-q->request_ofs));
int bytes = write_nonblock(q->alarm.poll.fd, &q->request[q->request_ofs], q->request_len-q->request_ofs);
if (bytes == -1) {
WHY("Got error while sending HTTP request. Closing.");
@ -804,9 +793,29 @@ void rhizome_write_content(rhizome_file_fetch_record *q, char *buffer, int bytes
DEBUGF("Received all of file via rhizome -- now to import it");
fclose(q->file);
q->file = NULL;
rhizome_import_received_bundle(q->manifest);
rhizome_manifest_free(q->manifest);
q->manifest = NULL;
if (q->manifest) {
rhizome_import_received_bundle(q->manifest);
rhizome_manifest_free(q->manifest);
q->manifest = NULL;
} else {
/* This was to fetch the manifest, so now fetch the file if needed */
DEBUGF("Received a manifest in response to supplying a manifest prefix.");
DEBUGF("XXX Not implemented scheduling the fetching of the file itself.");
/* Read the manifest and add it to suggestion queue, then immediately
call schedule queued items. */
rhizome_manifest *m=rhizome_new_manifest();
if (m) {
if (rhizome_read_manifest_file(m,q->filename,0)==-1) {
DEBUGF("Couldn't read manifest from %s",q->filename);
rhizome_manifest_free(m);
} else {
DEBUGF("All looks good for importing manifest %p",m);
dump("q->peer",&q->peer,sizeof(q->peer));
rhizome_suggest_queue_manifest_import(m,&q->peer);
rhizome_enqueue_suggestions(NULL);
}
}
}
rhizome_fetch_close(q);
return;
}
@ -821,13 +830,13 @@ void rhizome_write_content(rhizome_file_fetch_record *q, char *buffer, int bytes
void rhizome_fetch_poll(struct sched_ent *alarm)
{
rhizome_file_fetch_record *q=(rhizome_file_fetch_record *)alarm;
if (alarm->poll.revents==0){
// timeout, close the socket
rhizome_fetch_close(q);
return;
}
if (alarm->poll.revents & (POLLIN | POLLOUT)) {
switch(q->state) {
case RHIZOME_FETCH_CONNECTING:
@ -868,100 +877,199 @@ void rhizome_fetch_poll(struct sched_ent *alarm)
q->alarm.deadline = q->alarm.alarm + RHIZOME_IDLE_TIMEOUT;
schedule(&q->alarm);
q->request_len += bytes;
if (http_header_complete(q->request, q->request_len, bytes + 4)) {
if (http_header_complete(q->request, q->request_len, bytes)) {
if (debug & DEBUG_RHIZOME_RX)
DEBUGF("Got HTTP reply: %s", alloca_toprint(160, q->request, q->request_len));
/* We have all the reply headers, so parse them, taking care of any following bytes of
content. */
char *p = NULL;
if (!str_startswith(q->request, "HTTP/1.0 ", &p)) {
if (debug&DEBUG_RHIZOME_RX)
DEBUGF("Malformed HTTP reply: missing HTTP/1.0 preamble");
struct http_response_parts parts;
if (unpack_http_response(q->request, &parts) == -1) {
rhizome_fetch_close(q);
return;
}
int http_response_code = 0;
char *nump;
for (nump = p; isdigit(*p); ++p)
http_response_code = http_response_code * 10 + *p - '0';
if (p == nump || *p != ' ') {
if (debug&DEBUG_RHIZOME_RX)
DEBUGF("Malformed HTTP reply: missing decimal status code");
rhizome_fetch_close(q);
return;
}
if (http_response_code != 200) {
if (parts.code != 200) {
if (debug & DEBUG_RHIZOME_RX)
DEBUGF("Failed HTTP request: rhizome server returned %d != 200 OK", http_response_code);
DEBUGF("Failed HTTP request: rhizome server returned %d != 200 OK", parts.code);
rhizome_fetch_close(q);
return;
}
// This loop will terminate, because http_header_complete() above found at least
// "\n\n" at the end of the header, and probably "\r\n\r\n".
while (*p++ != '\n')
;
// Iterate over header lines until the last blank line.
long long content_length = -1;
while (*p != '\r' && *p != '\n') {
if (strcase_startswith(p, "Content-Length:", &p)) {
while (*p == ' ')
++p;
content_length = 0;
for (nump = p; isdigit(*p); ++p)
content_length = content_length * 10 + *p - '0';
if (p == nump || (*p != '\r' && *p != '\n')) {
if (debug & DEBUG_RHIZOME_RX) {
DEBUGF("Invalid HTTP reply: malformed Content-Length header");
rhizome_fetch_close(q);
return;
}
}
}
while (*p++ != '\n')
;
}
if (*p == '\r')
++p;
++p; // skip '\n' at end of blank line
if (content_length == -1) {
if (parts.content_length == -1) {
if (debug & DEBUG_RHIZOME_RX)
DEBUGF("Invalid HTTP reply: missing Content-Length header");
rhizome_fetch_close(q);
return;
}
q->file_len = content_length;
q->file_len = parts.content_length;
/* We have all we need. The file is already open, so just write out any initial bytes of
the body we read.
*/
q->state = RHIZOME_FETCH_RXFILE;
int content_bytes = q->request + q->request_len - p;
int content_bytes = q->request + q->request_len - parts.content_start;
if (content_bytes > 0)
rhizome_write_content(q, p, content_bytes);
rhizome_write_content(q, parts.content_start, content_bytes);
}
} else {
if (debug & DEBUG_RHIZOME_RX)
DEBUG("Empty read, closing connection");
rhizome_fetch_close(q);
return;
}
if (sigPipeFlag) {
if (debug & DEBUG_RHIZOME_RX)
DEBUG("Received SIGPIPE, closing connection");
rhizome_fetch_close(q);
return;
}
break;
default:
if (debug & DEBUG_RHIZOME_RX)
DEBUG("Closing rhizome fetch connection due to illegal/unimplemented state.");
rhizome_fetch_close(q);
return;
}
break;
default:
if (debug & DEBUG_RHIZOME_RX)
DEBUG("Closing rhizome fetch connection due to illegal/unimplemented state.");
rhizome_fetch_close(q);
return;
}
}
}
if (alarm->poll.revents & (POLLHUP | POLLERR)) {
rhizome_fetch_close(q);
}
}
return;
}
/*
This function takes a pointer to a buffer into which the entire HTTP response header has been
read. The caller must have ensured that the buffer contains at least one consecutive pair of
newlines '\n', optionally with carriage returns '\r' preceding and optionally interspersed with
nul characters '\0' (which can originate from telnet). The http_header_complete() function
is useful for this.
This returns pointers to within the supplied buffer, and may overwrite some characters in the
buffer, for example to nul-terminate a string that was terminated by space ' ' or newline '\r'
'\n' in the buffer. For that reason, it takes char* not const char* arguments and returns the
same. It is up to the caller to manage the lifetime of the returned pointers, which of course
will only be valid for as long as the buffer persists and is not overwritten.
@author Andrew Bettison <andrew@servalproject.com>
*/
int unpack_http_response(char *response, struct http_response_parts *parts)
{
parts->code = -1;
parts->reason = NULL;
parts->content_length = -1;
parts->content_start = NULL;
char *p = NULL;
if (!str_startswith(response, "HTTP/1.0 ", &p)) {
if (debug&DEBUG_RHIZOME_RX)
DEBUGF("Malformed HTTP reply: missing HTTP/1.0 preamble");
return -1;
}
if (!(isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2]) && p[3] == ' ')) {
if (debug&DEBUG_RHIZOME_RX)
DEBUGF("Malformed HTTP reply: missing three-digit status code");
return -1;
}
parts->code = (p[0]-'0') * 100 + (p[1]-'0') * 10 + p[2]-'0';
p += 4;
parts->reason = p;
while (*p != '\n')
++p;
if (p[-1] == '\r')
p[-1] = '\0';
*p++ = '\0';
// Iterate over header lines until the last blank line.
while (!(p[0] == '\n' || (p[0] == '\r' && p[1] == '\n'))) {
if (strcase_startswith(p, "Content-Length:", &p)) {
while (*p == ' ')
++p;
parts->content_length = 0;
char *nump = p;
while (isdigit(*p))
parts->content_length = parts->content_length * 10 + *p++ - '0';
if (p == nump || (*p != '\r' && *p != '\n')) {
if (debug & DEBUG_RHIZOME_RX)
DEBUGF("Invalid HTTP reply: malformed Content-Length header");
return -1;
}
}
while (*p++ != '\n')
;
}
if (*p == '\r')
++p;
++p; // skip '\n' at end of blank line
parts->content_start = p;
return 0;
}
int rhizome_fetch_request_manifest_by_prefix(struct sockaddr_in *peerip,
unsigned char *prefix,
int prefix_length,
int importP)
{
assert(peerip);
/* Transfer via HTTP over IPv4 */
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
return WHY_perror("socket");
if (set_nonblock(sock) == -1) {
close(sock);
return -1;
}
struct sockaddr_in addr = *peerip;
addr.sin_family = AF_INET;
INFOF("RHIZOME HTTP REQUEST, CONNECT family=%u port=%u addr=%u.%u.%u.%u",
addr.sin_family, ntohs(addr.sin_port),
((unsigned char*)&addr.sin_addr.s_addr)[0],
((unsigned char*)&addr.sin_addr.s_addr)[1],
((unsigned char*)&addr.sin_addr.s_addr)[2],
((unsigned char*)&addr.sin_addr.s_addr)[3]
);
if (connect(sock, (struct sockaddr*)&addr, sizeof addr) == -1) {
if (errno == EINPROGRESS) {
if (debug & DEBUG_RHIZOME_RX)
DEBUGF("connect() returned EINPROGRESS");
} else {
WHY_perror("connect");
WHY("Failed to open socket to peer's rhizome web server");
close(sock);
return -1;
}
}
rhizome_file_fetch_record *q=&file_fetch_queue[rhizome_file_fetch_queue_count];
q->manifest = NULL;
q->alarm.poll.fd=sock;
bzero(q->fileid, sizeof(q->fileid));
q->peer=*peerip;
q->request_len = snprintf(q->request, sizeof q->request, "GET /rhizome/manifestbyprefix/%s HTTP/1.0\r\n\r\n", alloca_tohex(prefix,prefix_length));
q->request_ofs=0;
q->state=RHIZOME_FETCH_CONNECTING;
q->file_len=-1;
q->file_ofs=0;
if (create_rhizome_import_dir() == -1)
return -1;
char filename[1024];
if (!FORM_RHIZOME_IMPORT_PATH(filename, "file.%s",
alloca_tohex(prefix,prefix_length))) {
close(sock);
return -1;
}
if (strlen(q->filename)<sizeof(q->filename))
strcpy(q->filename,filename);
else q->filename[0]=0;
if ((q->file = fopen(filename, "w")) == NULL) {
WHY_perror("fopen");
// if (debug & DEBUG_RHIZOME_RX)
DEBUGF("Could not open '%s' to write received file", filename);
close(sock);
return -1;
}
INFOF("RHIZOME HTTP REQUEST, GET \"/rhizome/manifestbyprefix/%s\"",
alloca_tohex(prefix,prefix_length));
/* Watch for activity on the socket */
q->alarm.function=rhizome_fetch_poll;
fetch_stats.name="rhizome_fetch_poll";
q->alarm.stats=&fetch_stats;
q->alarm.poll.events=POLLIN|POLLOUT;
watch(&q->alarm);
/* And schedule a timeout alarm */
q->alarm.alarm=gettime_ms() + RHIZOME_IDLE_TIMEOUT;
q->alarm.deadline = q->alarm.alarm + RHIZOME_IDLE_TIMEOUT;
schedule(&q->alarm);
rhizome_file_fetch_queue_count++;
if (debug & DEBUG_RHIZOME_RX)
DEBUGF("Queued file for fetching into %s (%d in queue)",
filename, rhizome_file_fetch_queue_count);
return 0;
}

View File

@ -20,65 +20,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#ifdef HAVE_SYS_FILIO_H
#include <sys/filio.h>
#endif
#include "serval.h"
#include "str.h"
#include "rhizome.h"
typedef struct rhizome_http_request {
struct sched_ent alarm;
long long initiate_time; /* time connection was initiated */
/* The HTTP request as currently received */
int request_length;
#define RHIZOME_HTTP_REQUEST_MAXLEN 1024
char request[RHIZOME_HTTP_REQUEST_MAXLEN];
/* Nature of the request */
int request_type;
#define RHIZOME_HTTP_REQUEST_RECEIVING -1
#define RHIZOME_HTTP_REQUEST_FROMBUFFER 1
#define RHIZOME_HTTP_REQUEST_FILE 2
#define RHIZOME_HTTP_REQUEST_SUBSCRIBEDGROUPLIST 4
#define RHIZOME_HTTP_REQUEST_ALLGROUPLIST 8
#define RHIZOME_HTTP_REQUEST_BUNDLESINGROUP 16
// manifests are small enough to send from a buffer
// #define RHIZOME_HTTP_REQUEST_BUNDLEMANIFEST 32
// for anything too big, we can just use a blob
#define RHIZOME_HTTP_REQUEST_BLOB 64
#define RHIZOME_HTTP_REQUEST_FAVICON 128
/* Local buffer of data to be sent.
If a RHIZOME_HTTP_REQUEST_FROMBUFFER, then the buffer is sent, and when empty
the request is closed.
Else emptying the buffer triggers a request to fetch more data. Only if no
more data is provided do we then close the request. */
unsigned char *buffer;
int buffer_size; // size
int buffer_length; // number of bytes loaded into buffer
int buffer_offset; // where we are between [0,buffer_length)
/* The source specification data which are used in different ways by different
request types */
char source[1024];
long long source_index;
long long source_count;
int source_record_size;
unsigned int source_flags;
sqlite3_blob *blob;
/* source_index used for offset in blob */
long long blob_end;
} rhizome_http_request;
static int rhizome_server_free_http_request(rhizome_http_request *r);
static int rhizome_server_http_send_bytes(rhizome_http_request *r);
static int rhizome_server_parse_http_request(rhizome_http_request *r);
static int rhizome_server_simple_http_response(rhizome_http_request *r, int result, const char *response);
static int rhizome_server_http_response_header(rhizome_http_request *r, int result, const char *mime_type, unsigned long long bytes);
static int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, char *column);
#define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32
struct sched_ent server_alarm;
@ -87,13 +35,18 @@ struct profile_total server_stats;
struct profile_total connection_stats;
/*
HTTP server and client code for rhizome transfers.
HTTP server and client code for rhizome transfers and rhizome direct.
Selection of either use is made when starting the HTTP server and
specifying the call-back function to use on client connections.
*/
unsigned short rhizome_http_server_port = 0;
static int rhizome_server_socket = -1;
static time_ms_t rhizome_server_last_start_attempt = -1;
int (*rhizome_http_parse_func)(rhizome_http_request *)=NULL;
const char *rhizome_http_parse_func_description="(null)";
// Format icon data using:
// od -vt u1 ~/Downloads/favicon.ico | cut -c9- | sed 's/ */,/g'
unsigned char favicon_bytes[]={
@ -132,7 +85,9 @@ int rhizome_http_server_running()
Return 1 if the server is already started successfully.
Return 2 if the server was not started because it is too soon since last failed attempt.
*/
int rhizome_http_server_start()
int rhizome_http_server_start(int (*parse_func)(rhizome_http_request *),
const char *parse_func_desc,
int port_low,int port_high)
{
if (rhizome_server_socket != -1)
return 1;
@ -146,7 +101,7 @@ int rhizome_http_server_start()
DEBUGF("Starting rhizome HTTP server");
unsigned short port;
for (port = RHIZOME_HTTP_PORT; port <= RHIZOME_HTTP_PORT_MAX; ++port) {
for (port = port_low; port <= port_high; ++port) {
/* Create a new socket, reusable and non-blocking. */
if (rhizome_server_socket == -1) {
rhizome_server_socket = socket(AF_INET,SOCK_STREAM,0);
@ -199,7 +154,12 @@ error:
return WHY("Failed to start rhizome HTTP server");
success:
INFOF("RHIZOME HTTP SERVER, START port=%d, fd=%d", port, rhizome_server_socket);
INFOF("RHIZOME HTTP SERVER, START port=%d fd=%d", port, rhizome_server_socket);
/* Remember which function to call when handling client connections */
rhizome_http_parse_func=parse_func;
rhizome_http_parse_func_description=parse_func_desc;
rhizome_http_server_port = port;
/* Add Rhizome HTTPd server to list of file descriptors to watch */
server_alarm.function = rhizome_server_poll;
@ -221,11 +181,38 @@ void rhizome_client_poll(struct sched_ent *alarm)
}
switch(r->request_type)
{
case RHIZOME_HTTP_REQUEST_RECEIVING_MULTIPART:
{
/* Reading multi-part form data. Read some bytes and proces them. */
char buffer[16384];
sigPipeFlag=0;
int bytes = read_nonblock(r->alarm.poll.fd, buffer, 16384);
/* If we got some data, see if we have found the end of the HTTP request */
if (bytes > 0) {
// reset inactivity timer
r->alarm.alarm = gettime_ms() + RHIZOME_IDLE_TIMEOUT;
r->alarm.deadline = r->alarm.alarm + RHIZOME_IDLE_TIMEOUT;
unschedule(&r->alarm);
schedule(&r->alarm);
rhizome_direct_process_post_multipart_bytes(r,buffer,bytes);
}
/* We don't drop the connection on an empty read, because that results
in connections dropping when they shouldn't, including during testing.
The idle timeout should drop the connections instead.
*/
if (sigPipeFlag) {
if (debug & DEBUG_RHIZOME_TX)
DEBUG("Received SIGPIPE, closing connection");
rhizome_server_free_http_request(r);
return;
}
}
break;
case RHIZOME_HTTP_REQUEST_RECEIVING:
/* Keep reading until we have two CR/LFs in a row */
r->request[r->request_length] = '\0';
sigPipeFlag=0;
int bytes = read_nonblock(r->alarm.poll.fd, &r->request[r->request_length], RHIZOME_HTTP_REQUEST_MAXLEN - r->request_length);
int bytes = read_nonblock(r->alarm.poll.fd, &r->request[r->request_length], sizeof r->request - r->request_length);
/* If we got some data, see if we have found the end of the HTTP request */
if (bytes > 0) {
// reset inactivity timer
@ -234,9 +221,9 @@ void rhizome_client_poll(struct sched_ent *alarm)
unschedule(&r->alarm);
schedule(&r->alarm);
r->request_length += bytes;
if (http_header_complete(r->request, r->request_length, bytes + 4)) {
if (http_header_complete(r->request, r->request_length, bytes)) {
/* We have the request. Now parse it to see if we can respond to it */
rhizome_server_parse_http_request(r);
if (rhizome_http_parse_func!=NULL) rhizome_http_parse_func(r);
}
} else {
if (debug & DEBUG_RHIZOME_TX)
@ -259,6 +246,8 @@ void rhizome_client_poll(struct sched_ent *alarm)
return;
}
static unsigned int rhizome_http_request_uuid_counter=0;
void rhizome_server_poll(struct sched_ent *alarm)
{
if (alarm->poll.revents & (POLLIN | POLLOUT)) {
@ -266,8 +255,9 @@ void rhizome_server_poll(struct sched_ent *alarm)
unsigned int addr_len = sizeof addr;
int sock;
while ((sock = accept(rhizome_server_socket, &addr, &addr_len)) != -1) {
struct sockaddr_in *peerip=NULL;
if (addr.sa_family == AF_INET) {
struct sockaddr_in *peerip = (struct sockaddr_in *)&addr;
peerip = (struct sockaddr_in *)&addr;
INFOF("RHIZOME HTTP SERVER, ACCEPT addrlen=%u family=%u port=%u addr=%u.%u.%u.%u",
addr_len, peerip->sin_family, peerip->sin_port,
((unsigned char*)&peerip->sin_addr.s_addr)[0],
@ -277,14 +267,18 @@ void rhizome_server_poll(struct sched_ent *alarm)
);
} else {
INFOF("RHIZOME HTTP SERVER, ACCEPT addrlen=%u family=%u data=%s",
addr_len, addr.sa_family, alloca_tohex((unsigned char *)addr.sa_data, sizeof addr.sa_data)
);
addr_len, addr.sa_family, alloca_tohex((unsigned char *)addr.sa_data, sizeof addr.sa_data)
);
}
rhizome_http_request *request = calloc(sizeof(rhizome_http_request), 1);
if (request == NULL) {
WHYF_perror("calloc(%u, 1)", sizeof(rhizome_http_request));
WHY("Cannot respond to request, out of memory");
} else {
request->uuid=rhizome_http_request_uuid_counter++;
if (peerip) request->requestor=*peerip;
else bzero(&request->requestor,sizeof(request->requestor));
request->data_file_name[0]=0;
/* We are now trying to read the HTTP request */
request->request_type=RHIZOME_HTTP_REQUEST_RECEIVING;
request->alarm.function = rhizome_client_poll;
@ -300,17 +294,15 @@ void rhizome_server_poll(struct sched_ent *alarm)
schedule(&request->alarm);
}
}
if (errno != EAGAIN) {
if (errno != EAGAIN)
WARN_perror("accept");
}
}
if (alarm->poll.revents & (POLLHUP | POLLERR)) {
INFO("Error on tcp listen socket");
}
}
static int rhizome_server_free_http_request(rhizome_http_request *r)
int rhizome_server_free_http_request(rhizome_http_request *r)
{
unwatch(&r->alarm);
unschedule(&r->alarm);
@ -323,7 +315,7 @@ static int rhizome_server_free_http_request(rhizome_http_request *r)
return 0;
}
static int rhizome_server_sql_query_http_response(rhizome_http_request *r,
int rhizome_server_sql_query_http_response(rhizome_http_request *r,
char *column,char *table,char *query_body,
int bytes_per_row,int dehexP)
{
@ -392,7 +384,7 @@ static int rhizome_server_sql_query_http_response(rhizome_http_request *r,
return rhizome_server_sql_query_fill_buffer(r, table, column);
}
static int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, char *column)
int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, char *column)
{
unsigned char blob_value[r->source_record_size*2+1];
@ -412,12 +404,12 @@ static int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *t
return WHY("Not enough space to fit any records");
}
sqlite3_stmt *statement = sqlite_prepare("%s LIMIT %lld,%d", r->source, r->source_index, record_count);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "%s LIMIT %lld,%d", r->source, r->source_index, record_count);
if (!statement)
return -1;
if (debug & DEBUG_RHIZOME_TX)
DEBUG(sqlite3_sql(statement));
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
while( r->buffer_length + r->source_record_size < r->buffer_size
&& sqlite_step_retry(&retry, statement) == SQLITE_ROW
) {
@ -478,9 +470,10 @@ static int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *t
return 0;
}
int http_header_complete(const char *buf, size_t len, size_t tail)
int http_header_complete(const char *buf, size_t len, size_t read_since_last_call)
{
const char *bufend = buf + len;
size_t tail = read_since_last_call + 4;
if (tail < len)
buf = bufend - tail;
int count = 0;
@ -495,7 +488,8 @@ int http_header_complete(const char *buf, size_t len, size_t tail)
return count == 2;
}
static int rhizome_server_parse_http_request(rhizome_http_request *r)
int rhizome_direct_parse_http_request(rhizome_http_request *r);
int rhizome_server_parse_http_request(rhizome_http_request *r)
{
/* Switching to writing, so update the call-back */
r->alarm.poll.events=POLLOUT;
@ -505,7 +499,9 @@ static int rhizome_server_parse_http_request(rhizome_http_request *r)
// Parse the HTTP "GET" line.
char *path = NULL;
size_t pathlen = 0;
if (str_startswith(r->request, "GET ", &path)) {
if (str_startswith(r->request, "POST ", &path)) {
return rhizome_direct_parse_http_request(r);
} else if (str_startswith(r->request, "GET ", &path)) {
char *p;
// This loop is guaranteed to terminate before the end of the buffer, because we know that the
// buffer contains at least "\n\n" and maybe "\r\n\r\n" at the end of the header block.
@ -558,8 +554,42 @@ static int rhizome_server_parse_http_request(rhizome_http_request *r)
} else if (str_startswith(path, "/rhizome/manifest/", &id)) {
// TODO: Stream the specified manifest
rhizome_server_simple_http_response(r, 500, "<html><h1>Not implemented</h1></html>\r\n");
} else {
} else if (str_startswith(path, "/rhizome/manifestbyprefix/", &id)) {
/* Manifest by prefix */
char bid_low[RHIZOME_MANIFEST_ID_STRLEN+1];
char bid_high[RHIZOME_MANIFEST_ID_STRLEN+1];
int i;
for (i=0;i<RHIZOME_MANIFEST_ID_STRLEN
&&path[strlen("/rhizome/manifestbyprefix/")+i];i++) {
bid_low[i]=path[strlen("/rhizome/manifestbyprefix/")+i];
bid_high[i]=path[strlen("/rhizome/manifestbyprefix/")+i];
}
for(;i<RHIZOME_MANIFEST_ID_STRLEN;i++) {
bid_low[i]='0';
bid_high[i]='f';
}
bid_low[RHIZOME_MANIFEST_ID_STRLEN]=0;
bid_high[RHIZOME_MANIFEST_ID_STRLEN]=0;
DEBUGF("Looking for manifest between %s and %s",
bid_low,bid_high);
long long rowid = -1;
sqlite_exec_int64(&rowid, "select rowid from manifests where id between '%s' and '%s';", bid_low,bid_high);
if (rowid >= 0 && sqlite3_blob_open(rhizome_db, "main", "manifests", "manifest", rowid, 0, &r->blob) != SQLITE_OK)
rowid = -1;
if (rowid == -1) {
DEBUGF("Row not found");
rhizome_server_simple_http_response(r, 404, "<html><h1>Payload not found</h1></html>\r\n");
} else {
DEBUGF("row id = %d",rowid);
r->source_index = 0;
r->blob_end = sqlite3_blob_bytes(r->blob);
rhizome_server_http_response_header(r, 200, "application/binary", r->blob_end - r->source_index);
r->request_type |= RHIZOME_HTTP_REQUEST_BLOB;
}
}else {
rhizome_server_simple_http_response(r, 404, "<html><h1>Not found</h1></html>\r\n");
DEBUGF("Sending 404 not found for '%s'",path);
}
} else {
if (debug & DEBUG_RHIZOME_TX)
@ -578,20 +608,18 @@ static int rhizome_server_parse_http_request(rhizome_http_request *r)
static const char *httpResultString(int response_code) {
switch (response_code) {
case 200: return "OK";
case 201: return "Created";
case 206: return "Partial Content";
case 404: return "Not found";
case 500: return "Internal server error";
default: return "A suffusion of yellow";
default:
if (response_code<=4)
return "Unknown status code";
else
return "A suffusion of yellow";
}
}
struct http_response {
unsigned int result_code;
const char * content_type;
unsigned long long content_length;
const char * body;
};
static strbuf strbuf_build_http_response(strbuf sb, const struct http_response *h)
{
strbuf_sprintf(sb, "HTTP/1.0 %03u %s\r\n", h->result_code, httpResultString(h->result_code));
@ -603,7 +631,7 @@ static strbuf strbuf_build_http_response(strbuf sb, const struct http_response *
return sb;
}
static int rhizome_server_set_response(rhizome_http_request *r, const struct http_response *h)
int rhizome_server_set_response(rhizome_http_request *r, const struct http_response *h)
{
strbuf b = strbuf_local((char *) r->buffer, r->buffer_size);
strbuf_build_http_response(b, h);
@ -627,21 +655,26 @@ static int rhizome_server_set_response(rhizome_http_request *r, const struct htt
r->buffer_offset = 0;
r->request_type |= RHIZOME_HTTP_REQUEST_FROMBUFFER;
if (debug & DEBUG_RHIZOME_TX)
DEBUGF("Sending HTTP response: %s", alloca_toprint(120, (const char *)r->buffer, r->buffer_length));
DEBUGF("Sending HTTP response: %s", alloca_toprint(160, (const char *)r->buffer, r->buffer_length));
return 0;
}
static int rhizome_server_simple_http_response(rhizome_http_request *r, int result, const char *response)
int rhizome_server_simple_http_response(rhizome_http_request *r, int result, const char *response)
{
struct http_response hr;
hr.result_code = result;
hr.content_type = "text/html";
hr.content_length = strlen(response);
hr.body = response;
if (result==400) {
DEBUGF("Rejecting http request as malformed due to: %s",
response);
}
r->request_type=0;
return rhizome_server_set_response(r, &hr);
}
static int rhizome_server_http_response_header(rhizome_http_request *r, int result, const char *mime_type, unsigned long long bytes)
int rhizome_server_http_response_header(rhizome_http_request *r, int result, const char *mime_type, unsigned long long bytes)
{
struct http_response hr;
hr.result_code = result;
@ -657,7 +690,7 @@ static int rhizome_server_http_response_header(rhizome_http_request *r, int resu
0: connection finished.
<0: an error occurred.
*/
static int rhizome_server_http_send_bytes(rhizome_http_request *r)
int rhizome_server_http_send_bytes(rhizome_http_request *r)
{
// keep writing until the write would block or we run out of data
while(r->request_type){

View File

@ -24,6 +24,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "overlay_address.h"
#include "overlay_packet.h"
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar)
{
@ -33,6 +39,8 @@ int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar)
and geographic bounding box information that is used to help manage flooding of
bundles.
Old BAR format (no longer used):
64 bits - manifest ID prefix.
56 bits - low 56 bits of version number.
8 bits - TTL of bundle in hops.
@ -41,6 +49,18 @@ int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar)
16 bits - min longitude (-180 - +180).
16 bits - max latitude (-90 - +90).
16 bits - max longitude (-180 - +180).
New BAR format with longer manifest ID prefix:
120 bits - manifest ID prefix.
8 bits - log2(length) of associated file.
56 bits - low 56 bits of version number.
16 bits - min latitude (-90 - +90).
16 bits - min longitude (-180 - +180).
16 bits - max latitude (-90 - +90).
16 bits - max longitude (-180 - +180).
8 bits - TTL of bundle in hops (0xff = unlimited distribution)
*/
if (!m) { RETURN(WHY("null manifest passed in")); }
@ -48,13 +68,13 @@ int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar)
int i;
/* Manifest prefix */
for(i=0;i<8;i++) bar[i]=m->cryptoSignPublic[i];
/* Version */
for(i=0;i<7;i++) bar[8+6-i]=(m->version>>(8*i))&0xff;
/* TTL */
if (m->ttl>0) bar[15]=m->ttl-1; else bar[15]=0;
for(i=0;i<RHIZOME_BAR_PREFIX_BYTES;i++)
bar[RHIZOME_BAR_PREFIX_OFFSET+i]=m->cryptoSignPublic[i];
/* file length */
for(i=0;i<8;i++) bar[16+7-i]=(m->fileLength>>(8*i))&0xff;
bar[RHIZOME_BAR_FILESIZE_OFFSET]=log2(m->fileLength);
/* Version */
for(i=0;i<7;i++) bar[RHIZOME_BAR_VERSION_OFFSET+6-i]=(m->version>>(8*i))&0xff;
/* geo bounding box */
double minLat=rhizome_manifest_get_double(m,"min_lat",-90);
if (minLat<-90) minLat=-90; if (minLat>90) minLat=90;
@ -63,22 +83,47 @@ int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar)
double maxLat=rhizome_manifest_get_double(m,"max_lat",+90);
if (maxLat<-90) maxLat=-90; if (maxLat>90) maxLat=90;
double maxLong=rhizome_manifest_get_double(m,"max_long",+180);
if (maxLong<-180) maxLong=-180; if (maxLong>180) maxLong=180;
if (maxLong<-180) maxLong=-180; if (maxLong>180) maxLong=180;
unsigned short v;
v=(minLat+90)*(65535/180); bar[24]=(v>>8)&0xff; bar[25]=(v>>0)&0xff;
v=(minLong+180)*(65535/360); bar[26]=(v>>8)&0xff; bar[27]=(v>>0)&0xff;
v=(maxLat+90)*(65535/180); bar[28]=(v>>8)&0xff; bar[29]=(v>>0)&0xff;
v=(maxLong+180)*(65535/360); bar[30]=(v>>8)&0xff; bar[31]=(v>>0)&0xff;
int o=RHIZOME_BAR_GEOBOX_OFFSET;
v=(minLat+90)*(65535/180); bar[o++]=(v>>8)&0xff; bar[o++]=(v>>0)&0xff;
v=(minLong+180)*(65535/360); bar[o++]=(v>>8)&0xff; bar[o++]=(v>>0)&0xff;
v=(maxLat+90)*(65535/180); bar[o++]=(v>>8)&0xff; bar[o++]=(v>>0)&0xff;
v=(maxLong+180)*(65535/360); bar[o++]=(v>>8)&0xff; bar[o++]=(v>>0)&0xff;
/* TTL */
if (m->ttl>0) bar[RHIZOME_BAR_TTL_OFFSET]=m->ttl-1;
else bar[RHIZOME_BAR_TTL_OFFSET]=0;
RETURN(0);
}
long long rhizome_bar_version(unsigned char *bar)
{
long long version=0;
int i;
// for(i=0;i<7;i++) bar[8+6-i]=(m->version>>(8*i))&0xff;
for(i=0;i<7;i++) version|=bar[RHIZOME_BAR_VERSION_OFFSET+6-i]<<(8LL*i);
return version;
}
/* This function only displays the first 8 bytes, and should not be used
for comparison. */
unsigned long long rhizome_bar_bidprefix_ll(unsigned char *bar)
{
long long bidprefix=0;
int i;
for(i=0;i<8;i++)
bidprefix|=((unsigned long long)bar[RHIZOME_BAR_PREFIX_OFFSET+7-i])<<(8*i);
return bidprefix;
}
int bundles_available=-1;
int bundle_offset[2]={0,0};
int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buffer *e)
{
IN();
int voice_mode=0;
/* behave differently during voice mode.
Basically don't encourage people to grab stuff from us, but keep
@ -89,10 +134,14 @@ int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buff
We need to change manifest table to include payload length to make our life
easy here (also would let us order advertisements by size of payload).
For now, we will just advertised only occassionally.
XXX Actually, we will move all processing of Rhizome into a separate process
so that the CPU delays caused by Rhizome verifying signatures isn't a problem.
We will still want to limit network usage during calls, however.
*/
time_ms_t now = gettime_ms();
if (now<rhizome_voice_timeout)
RETURN(0);
if (now<rhizome_voice_timeout) voice_mode=1;
if (voice_mode) if (random()&3) { RETURN(0); }
int pass;
int bytes=e->sizeLimit-e->position;
@ -167,10 +216,10 @@ int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buff
ob_checkpoint(e);
switch(pass) {
case 0: /* Full manifests */
statement = sqlite_prepare("SELECT MANIFEST,ROWID FROM MANIFESTS LIMIT %d,%d", bundle_offset[pass], slots);
statement = sqlite_prepare(&retry, "SELECT MANIFEST,ROWID FROM MANIFESTS LIMIT %d,%d", bundle_offset[pass], slots);
break;
case 1: /* BARs */
statement = sqlite_prepare("SELECT BAR,ROWID FROM MANIFESTS LIMIT %d,%d", bundle_offset[pass], slots);
statement = sqlite_prepare(&retry, "SELECT BAR,ROWID FROM MANIFESTS LIMIT %d,%d", bundle_offset[pass], slots);
break;
}
if (!statement)
@ -353,7 +402,7 @@ int overlay_rhizome_saw_advertisements(int i, struct overlay_frame *f, long long
/* Ignoring manifest that has caused us problems recently */
if (1) WARNF("Ignoring manifest with errors: %s*", manifest_id_prefix);
}
else if (m&&(!m->errors))
else if (m->errors == 0)
{
/* Manifest is okay, so see if it is worth storing */
if (rhizome_manifest_version_cache_lookup(m)) {
@ -361,7 +410,6 @@ int overlay_rhizome_saw_advertisements(int i, struct overlay_frame *f, long long
if (debug & DEBUG_RHIZOME_RX) DEBUG("We already have that manifest or newer.");
} else {
if (debug & DEBUG_RHIZOME_RX) DEBUG("Not seen before.");
rhizome_suggest_queue_manifest_import(m, &httpaddr);
// the above function will free the manifest structure, make sure we don't free it again
m=NULL;
@ -374,10 +422,10 @@ int overlay_rhizome_saw_advertisements(int i, struct overlay_frame *f, long long
a minute. */
rhizome_queue_ignore_manifest(m, &httpaddr, 60000);
}
if (m)
if (m) {
rhizome_manifest_free(m);
m=NULL;
m = NULL;
}
}
break;
}

View File

@ -826,6 +826,7 @@ int directory_registration();
int directory_service_init();
struct command_line_option;
int app_rhizome_direct_sync(int argc, const char *const *argv, struct command_line_option *o, void *context);
#ifdef HAVE_VOIPTEST
int app_pa_phone(int argc, const char *const *argv, struct command_line_option *o, void *context);
#endif
@ -892,7 +893,6 @@ extern int sigIoFlag;
void sigPipeHandler(int signal);
void sigIoHandler(int signal);
int rhizome_http_server_start();
int overlay_mdp_setup_sockets();
int schedule(struct sched_ent *alarm);
@ -931,6 +931,7 @@ void dump_stack();
#define OUT() fd_func_exit(&_this_call);
#define RETURN(X) { OUT() return(X); }
#define RETURNNULL { OUT() return(NULL); }

View File

@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "xprintf.h"
#define MAX_SPACES 120
@ -285,7 +286,7 @@ int isOverlayPacket(XPRINTF xpf, const unsigned char *packet, size_t *ofs, size_
if (cantDecodeFrame) {
xprintf(xpf,"%sWARNING: Cannot decode compressed and/or encrypted frame.\n",indent(8));
_dump(xpf, frame, frame_len, 0, "%s", indent(10));
_dump(xpf, frame, next_frame_ofs - *ofs, 0, "%s", indent(10));
}
else {
/* Decrypt and/or decompress frame */

View File

@ -740,7 +740,13 @@ int createServerSocket()
This makes life easier when we restart with an exec after receiving
a bad signal. */
fcntl(sock, F_SETFL,
fcntl(sock, F_GETFL, NULL)|O_CLOEXEC);
fcntl(sock, F_GETFL, NULL)|
#ifdef FD_CLOEXEC
FD_CLOEXEC
#else
O_CLOEXEC
#endif
);
int i=1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i));

14
sha2.c
View File

@ -36,8 +36,22 @@
#ifdef HAVE_SYS_ENDIAN_H
#include <sys/endian.h>
#endif
#ifdef HAVE_SYS_BYTEORDER_H
#include <sys/byteorder.h>
#endif
#include "sha2.h"
/* Translate from Solaris */
#ifndef BYTE_ORDER
#define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */
#define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */
#ifdef _BIG_ENDIAN
#define BYTE_ORDER BIG_ENDIAN
#else
#define BYTE_ORDER LITTLE_ENDIAN
#endif
#endif
/*
* ASSERT NOTE:
* Some sanity checking code is included using assert(). On my FreeBSD

22
str.c
View File

@ -17,8 +17,11 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "str.h"
#include "log.h"
int str_startswith(char *str, const char *substring, char **afterp)
{
@ -42,15 +45,13 @@ int strcase_startswith(char *str, const char *substring, char **afterp)
return 1;
}
int parse_argv(char *cmdline, char delim, char **argv, int max_argv){
int parse_argv(char *cmdline, char delim, char **argv, int max_argv)
{
int argc=0;
if (*cmdline && argc<max_argv){
argv[argc++]=cmdline;
}
// TODO quoted argument handling?
while(*cmdline){
if (*cmdline==delim){
*cmdline=0;
@ -62,3 +63,16 @@ int parse_argv(char *cmdline, char delim, char **argv, int max_argv){
return argc;
}
/* Like strstr() but doesn't depend on null termination */
char *str_str(char *haystack, const char *needle, int haystack_len)
{
size_t needle_len = strlen(needle);
if (needle_len == 0)
return haystack;
if (haystack_len >= needle_len) {
for (; *haystack && haystack_len >= needle_len; ++haystack, --haystack_len)
if (strncmp(haystack, needle, needle_len) == 0)
return haystack;
}
return NULL;
}

8
str.h
View File

@ -37,6 +37,12 @@ int str_startswith(char *str, const char *substring, char **afterp);
*/
int strcase_startswith(char *str, const char *substring, char **afterp);
/* like strstr(), but doesn't depend on null termination.
@author Paul Gardner-Stephen <paul@servalproject.org>
@author Andrew Bettison <andrew@servalproject.com>
*/
char *str_str(char *haystack, const char *needle, int haystack_len);
int parse_argv(char *cmdline, char delim, char **argv, int max_argv);
#endif
#endif

View File

@ -38,7 +38,7 @@ static inline strbuf _toprint(strbuf sb, char c)
else if (c >= ' ' && c <= '~')
strbuf_putc(sb, c);
else
strbuf_sprintf(sb, "\\x%02x", c);
strbuf_sprintf(sb, "\\x%02x", (unsigned char) c);
return sb;
}
@ -54,8 +54,9 @@ static strbuf inline _overrun(strbuf sb, const char *suffix)
static strbuf inline _overrun_quote(strbuf sb, char quote, const char *suffix)
{
if (strbuf_overrun(sb)) {
strbuf_trunc(sb, -strlen(suffix) - 1);
strbuf_putc(sb, quote);
strbuf_trunc(sb, -strlen(suffix) - (quote ? 1 : 0));
if (quote)
strbuf_putc(sb, quote);
strbuf_puts(sb, suffix);
}
return sb;
@ -75,30 +76,34 @@ strbuf strbuf_toprint(strbuf sb, const char *str)
return _overrun(sb, "...");
}
strbuf strbuf_toprint_quoted_len(strbuf sb, char quote, const char *buf, size_t len)
strbuf strbuf_toprint_quoted_len(strbuf sb, const char quotes[2], const char *buf, size_t len)
{
strbuf_putc(sb, quote);
if (quotes && quotes[0])
strbuf_putc(sb, quotes[0]);
for (; len && !strbuf_overrun(sb); ++buf, --len)
if (*buf == quote) {
if (quotes && *buf == quotes[1]) {
strbuf_putc(sb, '\\');
strbuf_putc(sb, quote);
strbuf_putc(sb, *buf);
} else
_toprint(sb, *buf);
strbuf_putc(sb, quote);
return _overrun_quote(sb, quote, "...");
if (quotes && quotes[1])
strbuf_putc(sb, quotes[1]);
return _overrun_quote(sb, quotes ? quotes[1] : '\0', "...");
}
strbuf strbuf_toprint_quoted(strbuf sb, char quote, const char *str)
strbuf strbuf_toprint_quoted(strbuf sb, const char quotes[2], const char *str)
{
strbuf_putc(sb, quote);
if (quotes && quotes[0])
strbuf_putc(sb, quotes[0]);
for (; *str && !strbuf_overrun(sb); ++str)
if (*str == quote) {
if (quotes && *str == quotes[1]) {
strbuf_putc(sb, '\\');
strbuf_putc(sb, quote);
strbuf_putc(sb, *str);
} else
_toprint(sb, *str);
strbuf_putc(sb, quote);
return _overrun_quote(sb, quote, "...");
if (quotes && quotes[1])
strbuf_putc(sb, quotes[1]);
return _overrun_quote(sb, quotes ? quotes[1] : '\0', "...");
}
strbuf strbuf_append_poll_events(strbuf sb, short events)

View File

@ -39,12 +39,12 @@ strbuf strbuf_toprint(strbuf sb, const char *str);
* backslash within the text.
* @author Andrew Bettison <andrew@servalproject.com>
*/
strbuf strbuf_toprint_quoted_len(strbuf sb, char quote, const char *buf, size_t len);
strbuf strbuf_toprint_quoted_len(strbuf sb, const char quotes[2], const char *buf, size_t len);
/* Equivalent to strbuf_toprint_quoted_len(sb, str, strlen(str)).
* @author Andrew Bettison <andrew@servalproject.com>
*/
strbuf strbuf_toprint_quoted(strbuf sb, char quote, const char *str);
strbuf strbuf_toprint_quoted(strbuf sb, const char quotes[2], const char *str);
/* Append a symbolic representation of the poll(2) event flags.
* @author Andrew Bettison <andrew@servalproject.com>

View File

@ -22,6 +22,7 @@ servald_source_root="${testdefs_sh%/*}"
servald_build_root="$servald_source_root"
servald_build_executable="$servald_build_root/servald"
export TFW_LOGDIR="${TFW_LOGDIR:-$servald_build_root/testlog}"
addr_localhost="127.0.0.1"
declare -a instance_stack=()
@ -36,7 +37,7 @@ extract_stdout_keyvalue_optional() {
local _var="$1"
local _label="$2"
local _rexp="$3"
local _line=$(replayStdout | grep "^$_label:")
local _line=$(replayStdout | $GREP "^$_label:")
local _value=
local _return=1
if [ -n "$_line" ]; then
@ -421,7 +422,7 @@ get_servald_pids() {
fi
local mypid=$$
# XXX The following line will not find any PIDs if there are spaces in "$servald".
local pids=$(ps -u$UID -o pid,args | awk -v mypid="$mypid" -v servald="$servald" '$1 != mypid && $2 == servald {print $1}')
local pids=$(ps -u$UID -o pid,args | $AWK -v mypid="$mypid" -v servald="$servald" '$1 != mypid && $2 == servald {print $1}')
[ -n "$var" ] && eval "$var=($pids)"
[ -n "$pids" ]
}
@ -546,16 +547,21 @@ configure_servald_server() {
}
# Utility function:
# - start a set of servald server processes running on a shared dummy interface and with its own
# private monitor and MDP abstract socket names
# - set variable DUMMYNET to the full path name of shared dummy interface
# - set variables LOGx to the full path of server log file for instance x: LOGA, LOGB, etc,
# - start a set of servald server processes running on a shared dummy interface
# and with its own private monitor and MDP abstract socket names
# - set variables DUMMYx to the full path name of shared dummy interface
# - set variables LOGx to the full path of server log file for instance x: LOGA,
# LOGB, etc,
# - wait for all instances to detect each other
# - assert that all instances are in each others' peer lists
start_servald_instances() {
local DUMMY=dummy
case "$1" in
dummy*) DUMMY="$1"; shift;;
esac
push_instance
tfw_log "# start servald instances $*"
DUMMYNET=$SERVALD_VAR/dummy
tfw_log "# start servald instances DUMMY=$DUMMY $*"
local DUMMYNET="$SERVALD_VAR/$DUMMY"
>$DUMMYNET
local I
for I; do
@ -567,6 +573,7 @@ start_servald_instances() {
executeOk_servald config set mdp.socket "org.servalproject.servald.mdp.socket.$TFWUNIQUE.$instance_name"
configure_servald_server
start_servald_server
eval DUMMY$instance_name="$DUMMYNET"
eval LOG$instance_name="$(shellarg "$instance_servald_log")"
done
# Now wait until they see each other.

View File

@ -35,12 +35,12 @@ assert_manifest_complete() {
assertGrep "$manifest" "^date=$rexp_date\$"
assertGrep "$manifest" "^version=$rexp_version\$"
assertGrep "$manifest" "^filesize=$rexp_filesize\$"
if grep -q '^filesize=0$' "$manifest"; then
if $GREP -q '^filesize=0$' "$manifest"; then
assertGrep --matches=0 "$manifest" "^filehash="
else
assertGrep "$manifest" "^filehash=$rexp_filehash\$"
fi
if grep -q '^service=file$' "$manifest"; then
if $GREP -q '^service=file$' "$manifest"; then
assertGrep "$manifest" "^name="
fi
}
@ -50,13 +50,14 @@ assert_rhizome_list() {
assertStdoutIs --stderr --line=1 -e '11\n'
assertStdoutIs --stderr --line=2 -e 'service:id:version:date:.inserttime:.selfsigned:filesize:filehash:sender:recipient:name\n'
local filename
local re__inserttime="$rexp_date"
for filename; do
re__selfsigned=1
case "$filename" in
*!) filename="${filename%!}"; re__selfsigned=0;;
esac
unpack_manifest_for_grep "$filename"
assertStdoutGrep --stderr --matches=1 "^$re_service:$re_manifestid:.*:$re__selfsigned:$re_filesize:$re_filehash:$re_sender:$re_recipient:$re_name\$"
assertStdoutGrep --stderr --matches=1 "^$re_service:$re_manifestid:$re_version:$re_date:$re__inserttime:$re__selfsigned:$re_filesize:$re_filehash:$re_sender:$re_recipient:$re_name\$"
done
}
@ -66,7 +67,7 @@ assert_stdout_add_file() {
shift
unpack_manifest_for_grep "$filename"
opt_name=false
if replayStdout | grep -q '^service:file$'; then
if replayStdout | $GREP -q '^service:file$'; then
opt_name=true
fi
fieldnames='service|manifestid|secret|filesize|filehash|name'
@ -90,7 +91,7 @@ assert_stdout_add_file() {
${opt_manifestid:-true} && assertStdoutGrep --matches=1 "^manifestid:$re_manifestid\$"
${opt_secret:-true} && assertStdoutGrep --matches=1 "^secret:$re_secret\$"
${opt_filesize:-true} && assertStdoutGrep --matches=1 "^filesize:$re_filesize\$"
if replayStdout | grep -q '^filesize:0$'; then
if replayStdout | $GREP -q '^filesize:0$'; then
assertStdoutGrep --matches=0 "^filehash:"
else
${opt_filehash:-true} && assertStdoutGrep --matches=1 "^filehash:$re_filehash\$"
@ -107,9 +108,10 @@ unpack_manifest_for_grep() {
re_service="$rexp_service"
re_manifestid="$rexp_manifestid"
re_version="$rexp_version"
re_date="$rexp_date"
re_secret="$rexp_bundlesecret"
re_name=$(escape_grep_basic "${filename##*/}")
local filesize=$(sed -n -e '/^filesize=/s///p' "$filename.manifest" 2>/dev/null)
local filesize=$($SED -n -e '/^filesize=/s///p' "$filename.manifest" 2>/dev/null)
if [ "$filesize" = 0 ]; then
re_filesize=0
re_filehash=
@ -120,17 +122,18 @@ unpack_manifest_for_grep() {
fi
# If there is a manifest file that looks like it matches this payload
# file, then use its file hash to check the rhizome list '' output.
local filehash=$(sed -n -e '/^filehash=/s///p' "$filename.manifest" 2>/dev/null)
local filehash=$($SED -n -e '/^filehash=/s///p' "$filename.manifest" 2>/dev/null)
if [ "$filehash" = "$re_filehash" ]; then
re_manifestid=$(sed -n -e '/^id=/s///p' "$filename.manifest")
re_version=$(sed -n -e '/^version=/s///p' "$filename.manifest")
re_service=$(sed -n -e '/^service=/s///p' "$filename.manifest")
re_manifestid=$($SED -n -e '/^id=/s///p' "$filename.manifest")
re_version=$($SED -n -e '/^version=/s///p' "$filename.manifest")
re_date=$($SED -n -e '/^date=/s///p' "$filename.manifest")
re_service=$($SED -n -e '/^service=/s///p' "$filename.manifest")
re_service=$(escape_grep_basic "$re_service")
re_sender=$(sed -n -e '/^sender=/s///p' "$filename.manifest")
re_recipient=$(sed -n -e '/^recipient=/s///p' "$filename.manifest")
re_sender=$($SED -n -e '/^sender=/s///p' "$filename.manifest")
re_recipient=$($SED -n -e '/^recipient=/s///p' "$filename.manifest")
case "$re_service" in
file)
re_name=$(sed -n -e '/^name=/s///p' "$filename.manifest")
re_name=$($SED -n -e '/^name=/s///p' "$filename.manifest")
re_name=$(escape_grep_basic "$re_name")
;;
*)
@ -155,7 +158,7 @@ assert_manifest_newer() {
strip_signatures() {
for file; do
cat -v "$file" | sed -e '/^^@/,$d' >"tmp.$file" && mv -f "tmp.$file" "$file"
cat -v "$file" | $SED -e '/^^@/,$d' >"tmp.$file" && mv -f "tmp.$file" "$file"
done
}
@ -172,7 +175,7 @@ extract_manifest() {
local _manifestfile="$2"
local _label="$3"
local _rexp="$4"
local _value=$(sed -n -e "/^$_label=$_rexp\$/s/^$_label=//p" "$_manifestfile")
local _value=$($SED -n -e "/^$_label=$_rexp\$/s/^$_label=//p" "$_manifestfile")
assert --message="$_manifestfile contains valid '$_label=' line" \
--dump-on-fail="$_manifestfile" \
[ -n "$_value" ]
@ -199,6 +202,10 @@ extract_manifest_filehash() {
extract_manifest "$1" "$2" filehash "$rexp_filehash"
}
extract_manifest_name() {
extract_manifest "$1" "$2" name ".*"
}
extract_manifest_version() {
extract_manifest "$1" "$2" version "$rexp_version"
}
@ -211,3 +218,20 @@ compute_filehash() {
[ "${#_hash}" -eq 128 ] || error "file hash incorrect length: $_hash"
[ -n "$_var" ] && eval $_var="$_hash"
}
rhizome_http_server_started() {
local logvar=LOG${1#+}
$GREP 'RHIZOME HTTP SERVER,.*START.*port=[0-9]' "${!logvar}"
}
get_rhizome_server_port() {
local _var="$1"
local _logvar=LOG${2#+}
local _port=$($SED -n -e '/.*RHIZOME HTTP SERVER.*START/{s/.*port=\([0-9]\{1,\}\).*/\1/p;q}' "${!_logvar}")
assert --message="instance $2 Rhizome HTTP server port number is known" [ -n "$_port" ]
if [ -n "$_var" ]; then
eval "$_var=\$_port"
tfw_log "$_var=$_port"
fi
return 0
}

View File

@ -54,6 +54,25 @@
# }
# runTests "$@"
AWK=awk
SED=sed
GREP=grep
TSFMT='+%Y-%m-%d %H:%M:%S'
SYSTYPE=`uname -s`
if [ $SYSTYPE = "SunOS" ]; then
abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }
AWK=gawk
SED=gsed
GREP=ggrep
fi
if [ $SYSTYPE = "Linux" ]; then
# Get nanosecond resolution
TSFMT='+%Y-%m-%d %H:%M:%S.%N'
fi
usage() {
echo -n "\
Usage: ${0##*/} [options] [--]
@ -256,7 +275,7 @@ runTests() {
} >"$_tfw_logdir/$testNumber.$testName.$result"
exit 0
) </dev/null &
local job=$(jobs %% | sed -n -e '1s/^\[\([0-9]\{1,\}\)\].*/\1/p')
local job=$(jobs %% | $SED -n -e '1s/^\[\([0-9]\{1,\}\)\].*/\1/p')
_tfw_running_jobs+=($job)
_tfw_job_pgids[$job]=$(jobs -p %%)
ln -f -s "$_tfw_results_dir/$testName" "$_tfw_results_dir/job-$job"
@ -571,31 +590,37 @@ tfw_cat() {
local show_nonprinting=
for file; do
case $file in
--header=*)
header="${1#*=}"
continue
;;
-v|--show-nonprinting)
show_nonprinting=-v
continue
;;
--stdout)
tfw_log "#----- ${header:-stdout of ($executed)} -----"
cat $show_nonprinting $_tfw_tmp/stdout
tfw_log "#-----"
header=
show_nonprinting=
file="$_tfw_tmp/stdout"
header="${header:-stdout of ($executed)}"
;;
--stderr)
tfw_log "#----- ${header:-stderr of ($executed)} -----"
cat $show_nonprinting $_tfw_tmp/stderr
tfw_log "#-----"
header=
show_nonprinting=
file="$_tfw_tmp/stderr"
header="${header:-stderr of ($executed)}"
;;
--header=*) header="${1#*=}";;
-v|--show-nonprinting) show_nonprinting=-v;;
*)
tfw_log "#----- ${header:-${file#$_tfw_tmp/}} -----"
cat $show_nonprinting "$file"
tfw_log "#-----"
header=
show_nonprinting=
header="${header:-${file#$_tfw_tmp/}}"
;;
esac
done >&$_tfw_log_fd
local missing_nl=
tfw_log "#----- $header -----"
cat $show_nonprinting "$file" >&$_tfw_log_fd
if [ "$(tail -1c "$file")" != "$newline" ]; then
echo >&$_tfw_log_fd
missing_nl=" (no newline at end)"
fi
tfw_log "#-----$missing_nl"
header=
show_nonprinting=
done
}
tfw_core_backtrace() {
@ -724,7 +749,7 @@ _tfw_abspath() {
}
_tfw_timestamp() {
local ts=$(date '+%Y-%m-%d %H:%M:%S.%N')
local ts=$(date "$TSFMT")
echo "${ts%[0-9][0-9][0-9][0-9][0-9][0-9]}"
}
@ -823,7 +848,7 @@ _tfw_execute() {
_tfw_parse_times_to_milliseconds() {
local label="$1"
local var="$2"
local milliseconds=$(awk '$1 == "'"$label"'" {
local milliseconds=$($AWK '$1 == "'"$label"'" {
value = $2
minutes = 0
if (match(value, "[0-9]+m")) {
@ -935,7 +960,7 @@ _tfw_matches_rexp() {
local rexp="$1"
shift
for arg; do
if ! echo "$arg" | grep -q -e "$rexp"; then
if ! echo "$arg" | $GREP -q -e "$rexp"; then
return 1
fi
done
@ -994,11 +1019,11 @@ _tfw_assert_stdxxx_is() {
fi
case "$_tfw_opt_line" in
'') ln -f "$_tfw_tmp/$qual" "$_tfw_tmp/content";;
*) sed -n -e "${_tfw_opt_line}p" "$_tfw_tmp/$qual" >"$_tfw_tmp/content";;
*) $SED -n -e "${_tfw_opt_line}p" "$_tfw_tmp/$qual" >"$_tfw_tmp/content";;
esac
local message="${_tfw_message:-${_tfw_opt_line:+line $_tfw_opt_line of }$qual of ($executed) is $(shellarg "$@")}"
echo -n "$@" >$_tfw_tmp/stdxxx_is.tmp
if ! cmp --quiet $_tfw_tmp/stdxxx_is.tmp "$_tfw_tmp/content"; then
if ! cmp -s $_tfw_tmp/stdxxx_is.tmp "$_tfw_tmp/content"; then
_tfw_failmsg "assertion failed: $message"
_tfw_backtrace
return 1
@ -1050,7 +1075,7 @@ _tfw_assert_grep() {
_tfw_error "$file is not readable"
ret=$?
else
local matches=$(( $(grep --regexp="$pattern" "$file" | wc -l) + 0 ))
local matches=$(( $($GREP --regexp="$pattern" "$file" | wc -l) + 0 ))
local done=false
local ret=0
local info="$matches match"$([ $matches -ne 1 ] && echo "es")
@ -1161,10 +1186,10 @@ _tfw_find_tests() {
_tfw_shopt oo -s extdebug
local name
for name in $(builtin declare -F |
sed -n -e '/^declare -f test_[A-Za-z]/s/^declare -f test_//p' |
$SED -n -e '/^declare -f test_[A-Za-z]/s/^declare -f test_//p' |
while read name; do builtin declare -F "test_$name"; done |
sort --key 2,2n --key 3,3 |
sed -e 's/^test_//' -e 's/[ ].*//')
sort -k 2,2n -k 3,3 |
$SED -e 's/^test_//' -e 's/[ ].*//')
do
local number=$((${#_tfw_tests[*]} + 1))
local testName=
@ -1246,14 +1271,14 @@ _tfw_failmsg() {
}
_tfw_backtrace() {
tfw_log '#----- backtrace -----'
tfw_log '#----- shell backtrace -----'
local -i up=1
while [ "${BASH_SOURCE[$up]}" == "${BASH_SOURCE[0]}" ]; do
let up=up+1
done
local -i i=0
while [ $up -lt ${#FUNCNAME[*]} -a "${BASH_SOURCE[$up]}" != "${BASH_SOURCE[0]}" ]; do
tfw_log "[$i] ${FUNCNAME[$(($up-1))]}() called from ${FUNCNAME[$up]}() at line ${BASH_LINENO[$(($up-1))]} of ${BASH_SOURCE[$up]}"
echo "[$i] ${FUNCNAME[$(($up-1))]}() called from ${FUNCNAME[$up]}() at line ${BASH_LINENO[$(($up-1))]} of ${BASH_SOURCE[$up]}" >&$_tfw_log_fd
let up=up+1
let i=i+1
done

View File

@ -54,8 +54,8 @@ setup_dnahelper() {
export SID_JOE_F=1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF
export SID_ECCLES=1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDE0
dnahelper="$TFWTMP/dnahelper"
cat >"$dnahelper" <<'EOF'
#!/bin/bash
echo "#!$BASH" >"$dnahelper"
cat >>"$dnahelper" <<'EOF'
echo STARTED
while read line
do
@ -233,8 +233,8 @@ setup_ExecArg1() {
setup_servald
assert_no_servald_processes
dnahelper="$TFWTMP/dnahelper"
cat >"$dnahelper" <<'EOF'
#!/bin/sh
echo "#!$BASH" >"$dnahelper"
cat >>"$dnahelper" <<'EOF'
echo STARTED
while read line
do

18
tests/dnaprotocol Normal file → Executable file
View File

@ -90,8 +90,8 @@ doc_LookupEmpty="Lookup by empty string"
test_LookupEmpty() {
executeOk_servald dna lookup ""
assertStdoutLineCount '==' 2
assertStdoutGrep --matches=1 "^sid://$SIDA/local/$DIDA:$DIDA:$NAMEA$"
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB$"
assertStdoutGrep --matches=1 "^sid://$SIDA/local/$DIDA:$DIDA:$NAMEA\$"
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
}
doc_LookupNonExistent="Lookup non-existent phone number"
@ -104,14 +104,14 @@ doc_LookupLocal="Lookup local phone number"
test_LookupLocal() {
executeOk_servald dna lookup "$DIDA"
assertStdoutLineCount '==' 1
assertStdoutGrep --matches=1 "^sid://$SIDA/local/$DIDA:$DIDA:$NAMEA$"
assertStdoutGrep --matches=1 "^sid://$SIDA/local/$DIDA:$DIDA:$NAMEA\$"
}
doc_LookupRemote="Lookup remote phone number"
test_LookupRemote() {
executeOk_servald dna lookup "$DIDB"
assertStdoutLineCount '==' 1
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB$"
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
}
doc_NodeinfoLocal="Node info auto-resolves for local identities"
@ -148,8 +148,8 @@ setup_multi_helper() {
setup_servald
assert_no_servald_processes
dnahelper="$TFWTMP/dnahelper"
cat >"$dnahelper" <<'EOF'
#!/bin/sh
echo "#!$BASH" >"$dnahelper"
cat >>"$dnahelper" <<'EOF'
echo STARTED
while read line
do
@ -197,8 +197,8 @@ setup_MultiLookupHelperTwo() {
test_MultiLookupHelperTwo() {
executeOk_servald dna lookup 00002
assertStdoutLineCount '==' 2
assertStdoutGrep --matches=1 "uri:A2:00002:Name Two$"
assertStdoutGrep --matches=1 "uri:B2:00002:Name Four$"
assertStdoutGrep --matches=1 "uri:A2:00002:Name Two\$"
assertStdoutGrep --matches=1 "uri:B2:00002:Name Four\$"
}
doc_MultiLookupHelperOne="Lookup phone number one node replies"
@ -208,7 +208,7 @@ setup_MultiLookupHelperOne() {
test_MultiLookupHelperOne() {
executeOk_servald dna lookup 00001
assertStdoutLineCount '==' 1
assertStdoutGrep --matches=1 "uri:B3:00001:Name Five$"
assertStdoutGrep --matches=1 "uri:B3:00001:Name Five\$"
}
runTests "$@"

View File

@ -328,7 +328,7 @@ setup_AddUpdateSameVersion() {
setup_AddDuplicate
cp file1.manifest file1_2.manifest
strip_signatures file1_2.manifest
sed -i -e '/^date=/d;/^filehash=/d;/^filesize=/d' file1_2.manifest
$SED -i -e '/^date=/d;/^filehash=/d;/^filesize=/d' file1_2.manifest
tfw_cat -v file1_2.manifest
assertGrep --matches=0 file1_2.manifest '^filehash='
extract_manifest_version '' file1_2.manifest # asserts has version= line
@ -351,7 +351,7 @@ setup_AddUpdateNewVersion() {
setup_AddUpdateSameVersion
extract_manifest_version version file1_2.manifest
let version=version+1
sed -i -e "/^version=/s/=.*/=$version/" file1_2.manifest
$SED -i -e "/^version=/s/=.*/=$version/" file1_2.manifest
assertGrep --matches=1 file1_2.manifest "^version=$version$"
}
test_AddUpdateNewVersion() {
@ -367,7 +367,7 @@ test_AddUpdateNewVersion() {
doc_AddUpdateNoAuthor="Cannot add new payload to authorless manifest"
setup_AddUpdateNoAuthor() {
setup_AddUpdateNewVersion
sed -i -e '/^BK=/d' file1_2.manifest
$SED -i -e '/^BK=/d' file1_2.manifest
}
test_AddUpdateNoAuthor() {
tfw_cat -v file1_2.manifest
@ -395,7 +395,7 @@ test_AddUpdateNoAuthorWithSecret() {
doc_AddUpdateAutoVersion="Add new payload to existing manifest with automatic version"
setup_AddUpdateAutoVersion() {
setup_AddUpdateSameVersion
sed -i -e '/^version=/d' file1_2.manifest
$SED -i -e '/^version=/d' file1_2.manifest
assertGrep --matches=0 file1_2.manifest '^version='
}
test_AddUpdateAutoVersion() {

View File

@ -43,25 +43,52 @@ configure_servald_server() {
executeOk_servald config set debug.rhizometx on
executeOk_servald config set debug.rhizomerx on
executeOk_servald config set server.respawn_on_signal off
executeOk_servald config set mdp.wifi.tick_ms 100
executeOk_servald config set mdp.wifi.tick_ms 500
executeOk_servald config set mdp.selfannounce.ticks_per_full_address 1
executeOk_servald config set rhizome.fetch_interval_ms 100
}
# Predicate function:
# - return true if the file bundle identified by $BID and $VERSION has been
# - return true if the file bundle identified by arg1=BID and arg2=VERSION has been
# received by all the given instances
# - does this by examining the server log files of the respective instances
# for tell-tale INFO messages
bundle_received_by() {
local BID="$1"
local VERSION="$2"
shift 2
local rexp="RHIZOME ADD MANIFEST service=file bid=$BID version=$VERSION"
local I
for I; do
logvar="LOG${I#+}"
grep "RHIZOME ADD MANIFEST service=file bid=$BID version=$VERSION" "${!logvar}" || return 1
case "$I" in
+*)
local logvar="LOG${I#+}"
grep "$rexp" "${!logvar}" || return 1
;;
--stderr)
replayStderr | grep "$rexp" || return 1
;;
*)
error "invalid instance argument: $I"
return 1
;;
esac
done
return 0
}
setup_curl_7() {
case "$(curl --version | tr '\n' ' ')" in
curl\ @(7|8|9|[1-9][0-1]).*\ Protocols:*\ http\ *) ;;
'') fail "curl(1) command is not present";;
*) fail "curl(1) version is not adequate (expecting 7 or higher)";;
esac
unset http_proxy
unset HTTP_PROXY
unset HTTPS_PROXY
unset ALL_PROXY
}
setup_common() {
setup_servald
setup_rhizome
@ -81,7 +108,7 @@ extract_manifest_vars() {
add_file() {
local name="$1"
[ -e "$name" ] || echo 'File $name' >"$name"
[ -e "$name" ] || echo "File $name" >"$name"
local sidvar="SID$instance_name"
executeOk_servald rhizome add file "${!sidvar}" '' "$name" "$name.manifest"
executeOk_servald rhizome list ''
@ -95,13 +122,23 @@ update_file() {
[ -e "$new_name" ] || echo 'File $new_name' >"$new_name"
local sidvar="SID$instance_name"
[ "$new_name" != "$orig_name" ] && cp "$orig_name.manifest" "$new_name.manifest"
sed -i -e '/^date=/d;/^filehash=/d;/^filesize=/d;/^version=/d;/^name=/d' "$new_name.manifest"
$SED -i -e '/^date=/d;/^filehash=/d;/^filesize=/d;/^version=/d;/^name=/d' "$new_name.manifest"
executeOk_servald rhizome add file "${!sidvar}" '' "$new_name" "$new_name.manifest"
executeOk_servald rhizome list ''
assert_rhizome_list "$new_name"
extract_manifest_vars "$new_name.manifest"
}
assert_received() {
local name="${1?}"
local _hash
if [ -s "$name" ]; then
extract_manifest_filehash _hash "$name.manifest"
executeOk_servald rhizome extract file "$_hash" extracted
assert cmp "$name" extracted
fi
}
doc_FileTransfer="New bundle and update transfer to one node"
setup_FileTransfer() {
setup_common
@ -112,13 +149,17 @@ setup_FileTransfer() {
foreach_instance +B assert_peers_are_instances +A
}
test_FileTransfer() {
wait_until bundle_received_by +B
wait_until bundle_received_by $BID $VERSION +B
set_instance +B
executeOk_servald rhizome list ''
assert_rhizome_list file1!
assert_received file1
set_instance +A
update_file file1 file2
set_instance +B
wait_until bundle_received_by +B
wait_until bundle_received_by $BID $VERSION +B
executeOk_servald rhizome list ''
assert_rhizome_list file2!
assert_received file2
}
@ -135,21 +176,11 @@ setup_FileTransferBig() {
foreach_instance +B assert_peers_are_instances +A
}
test_FileTransferBig() {
wait_until bundle_received_by +B
wait_until bundle_received_by $BID $VERSION +B
set_instance +B
assert_received file1
}
assert_received() {
local name="${1?}"
executeOk_servald rhizome list ''
assert_rhizome_list "$name!"
local _hash
if [ -s "$name" ]; then
extract_manifest_filehash _hash "$name.manifest"
executeOk_servald rhizome extract file "$_hash" extracted
assert cmp "$name" extracted
fi
assert_rhizome_list file1!
assert_received file1
}
doc_FileTransferMulti="New bundle transfers to four nodes"
@ -164,10 +195,12 @@ setup_FileTransferMulti() {
foreach_instance +D assert_peers_are_instances +A +B +C +E
}
test_FileTransferMulti() {
wait_until bundle_received_by +B +C +D +E
wait_until bundle_received_by $BID $VERSION +B +C +D +E
local I
for I in +B +C +D +E; do
set_instance $I
executeOk_servald rhizome list ''
assert_rhizome_list file1!
assert_received file1
done
}
@ -180,15 +213,168 @@ setup_FileTransferDelete() {
start_servald_instances +A +B
foreach_instance +A assert_peers_are_instances +B
foreach_instance +B assert_peers_are_instances +A
wait_until bundle_received_by +B
wait_until bundle_received_by $BID $VERSION +B
set_instance +A
>file1_2
update_file file1 file1_2
}
test_FileTransferDelete() {
wait_until bundle_received_by +B
wait_until bundle_received_by $BID $VERSION +B
set_instance +B
executeOk_servald rhizome list ''
assert_rhizome_list file1_2!
assert_received file1_2
}
doc_HttpImport="Import bundle using HTTP POST multi-part form."
setup_HttpImport() {
setup_curl_7
setup_common
cat >README.WHYNOTSIPS <<'EOF'
When we were looking at implementing secure calls for OpenBTS it was suggested
that we configure Asterisk to use SIPS/ZRTP. This would have been relatively
easy to setup, however there are a few problems.
Number one is that when Asterisk checks the certificates it will either
validate the certificate (checking the chain of trust and so on) and then
check that the common name attribute on the certificate matches the hostname
of the peer, or it will do none of these checks. This code is in main/tcptls.c
line 206 (in version 1.8.14.1).
This is undesirable in a setup where there is limited or no infrastructure as
there is not likely to be a DNS server setup, or even rigid IP assignments
that would allow a static hosts file based setup. This situation would force
the administrator to disable the checks completely which would allow a trivial
man in the middle attack.
It would be possible to modify Asterisk to have a third way where it validates
the certificate and checks the chain of trust but does not look at the common
name. We decided against this approach as the VOMP channel driver was written
in time to avoid it.
EOF
set_instance +B
executeOk_servald rhizome add file $SIDB '' README.WHYNOTSIPS README.WHYNOTSIPS.manifest
assert_manifest_complete README.WHYNOTSIPS.manifest
assert_stdout_add_file README.WHYNOTSIPS
set_instance +A
start_servald_instances +A
wait_until rhizome_http_server_started +A
get_rhizome_server_port PORTA +A
}
test_HttpImport() {
executeOk curl \
--silent --fail --show-error \
--output http.output \
--dump-header http.headers \
--write-out '%{http_code}\n' \
--form 'data=@README.WHYNOTSIPS' \
--form 'manifest=@README.WHYNOTSIPS.manifest' \
"$addr_localhost:$PORTA/rhizome/import"
tfw_cat http.headers http.output
executeOk_servald rhizome list ''
assert_rhizome_list README.WHYNOTSIPS!
assert_received README.WHYNOTSIPS
}
doc_HttpAddLocal="Add file locally using HTTP, returns manifest"
setup_HttpAddLocal() {
setup_curl_7
setup_common
set_instance +A
executeOk_servald config set rhizome.api.addfile.uri "/rhizome/secretaddfile"
executeOk_servald config set rhizome.api.addfile.author $SIDA
start_servald_instances +A
wait_until rhizome_http_server_started +A
get_rhizome_server_port PORTA +A
}
test_HttpAddLocal() {
echo 'File file1' >file1
executeOk curl --silent --form 'data=@file1' "http://$addr_localhost:$PORTA/rhizome/secretaddfile" --output file1.manifest
assert_manifest_complete file1.manifest
executeOk_servald rhizome list ''
assert_rhizome_list file1
extract_manifest_name name file1.manifest
assert [ "$name" = file1 ]
assert_received file1
}
setup_sync() {
set_instance +A
add_file file1
BID1=$BID
VERSION1=$VERSION
start_servald_instances dummy1 +A
wait_until rhizome_http_server_started +A
get_rhizome_server_port PORTA +A
set_instance +B
executeOk_servald config set log.show_time on
executeOk_servald config set debug.rhizome on
executeOk_servald config set debug.rhizometx on
executeOk_servald config set debug.rhizomerx on
executeOk_servald config set rhizome.direct.peer.count "1"
executeOk_servald config set rhizome.direct.peer.0 "http://${addr_localhost}:${PORTA}"
add_file file2
BID2=$BID
VERSION2=$VERSION
}
doc_DirectPush="One way push bundle to unconnected node"
setup_DirectPush() {
setup_common
setup_sync
}
test_DirectPush() {
set_instance +B
executeOk_servald rhizome direct push
tfw_cat --stdout --stderr
assert bundle_received_by $BID2 $VERSION2 +A
set_instance +A
executeOk_servald rhizome list ''
assert_rhizome_list file1 file2!
assert_received file2
set_instance +B
executeOk_servald rhizome list ''
assert_rhizome_list file2
}
doc_DirectPull="One way pull bundle from unconnected node"
setup_DirectPull() {
setup_common
setup_sync
}
test_DirectPull() {
set_instance +B
executeOk_servald rhizome direct pull
tfw_cat --stdout --stderr
assert bundle_received_by $BID1 $VERSION1 --stderr
set_instance +A
executeOk_servald rhizome list ''
assert_rhizome_list file1
set_instance +B
executeOk_servald rhizome list ''
assert_rhizome_list file1! file2
assert_received file1
}
doc_DirectSync="Two-way sync bundles between unconnected nodes"
setup_DirectSync() {
setup_common
setup_sync
}
test_DirectSync() {
set_instance +B
executeOk_servald rhizome direct sync
tfw_cat --stdout --stderr
assert bundle_received_by $BID1 $VERSION1 --stderr
assert bundle_received_by $BID2 $VERSION2 +A
set_instance +A
executeOk_servald rhizome list ''
assert_rhizome_list file1 file2!
assert_received file2
set_instance +B
executeOk_servald rhizome list ''
assert_rhizome_list file1! file2
assert_received file1
}
runTests "$@"