mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-20 03:36:42 +00:00
Merge branch 'rhizomedirect' into 'master'
This commit is contained in:
commit
89343c69cd
@ -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 \
|
||||
|
15
Makefile.in
15
Makefile.in
@ -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@
|
||||
|
@ -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;
|
||||
|
9
batman.c
9
batman.c
@ -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);
|
||||
|
||||
|
4
client.c
4
client.c
@ -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;
|
||||
|
@ -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
1
config.guess
vendored
@ -1 +0,0 @@
|
||||
/usr/share/libtool/config/config.guess
|
1530
config.guess
vendored
Executable file
1530
config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1
config.sub
vendored
1
config.sub
vendored
@ -1 +0,0 @@
|
||||
/usr/share/libtool/config/config.sub
|
1782
config.sub
vendored
Executable file
1782
config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
18
configure.in
18
configure.in
@ -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.)"
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -1 +0,0 @@
|
||||
/usr/share/libtool/config/install-sh
|
527
install-sh
Executable file
527
install-sh
Executable 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:
|
16
keyring.c
16
keyring.c
@ -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
63
log.c
@ -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
25
log.h
@ -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__)
|
||||
|
||||
|
7983
m4/libtool.m4
vendored
Normal file
7983
m4/libtool.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
384
m4/ltoptions.m4
vendored
Normal file
384
m4/ltoptions.m4
vendored
Normal 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
123
m4/ltsugar.m4
vendored
Normal 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
23
m4/ltversion.m4
vendored
Normal 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
98
m4/lt~obsolete.m4
vendored
Normal 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])])
|
32
monitor.c
32
monitor.c
@ -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) {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
/*
|
||||
|
@ -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)"));
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
4
peers.c
4
peers.c
@ -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
121
rhizome.c
@ -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
240
rhizome.h
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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
855
rhizome_direct.c
Normal 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
1063
rhizome_direct_http.c
Normal file
File diff suppressed because it is too large
Load Diff
346
rhizome_fetch.c
346
rhizome_fetch.c
@ -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;
|
||||
}
|
||||
|
213
rhizome_http.c
213
rhizome_http.c
@ -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){
|
||||
|
@ -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;
|
||||
}
|
||||
|
3
serval.h
3
serval.h
@ -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); }
|
||||
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
8
server.c
8
server.c
@ -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
14
sha2.c
@ -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
22
str.c
@ -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
8
str.h
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
23
testdefs.sh
23
testdefs.sh
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
18
tests/dnaprotocol
Normal file → Executable 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 "$@"
|
||||
|
@ -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() {
|
||||
|
@ -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 "$@"
|
||||
|
Loading…
Reference in New Issue
Block a user