Merge branch 'master' into andrew

Conflicts:
	log.c
This commit is contained in:
Andrew Bettison 2012-06-22 11:18:48 +09:30
commit 274e5c007c
18 changed files with 789 additions and 191 deletions

View File

@ -42,6 +42,8 @@ SERVALD_SRC_FILES = \
serval-dna/keyring.c \
serval-dna/vomp.c \
serval-dna/lsif.c \
serval-dna/dna_helper.c \
serval-dna/sighandlers.c \
serval-dna/monitor.c \
serval-dna/monitor-cli.c \
serval-dna/codecs.c \

View File

@ -45,6 +45,8 @@ SRCS= main.c \
lsif.c \
monitor.c \
monitor-cli.c \
dna_helper.c \
sighandlers.c \
codecs.c \
audiodevices.c \
audio_msm_g1.c \
@ -68,11 +70,15 @@ HDRS= fifo.h \
sqlite-amalgamation-3070900/sqlite3.h
LDFLAGS=@LDFLAGS@ @PORTAUDIO_LIBS@ @SRC_LIBS@ @SPANDSP_LIBS@ @CODEC2_LIBS@ @PTHREAD_LIBS@
CFLAGS= @CPPFLAGS@ @CFLAGS@ @PORTAUDIO_CFLAGS@ @SRC_CFLAGS@ @SPANDSP_CFLAGS@ @PTHREAD_CFLAGS@ $(VOIPTEST_CFLAGS) -Wall -Wno-unused-value
CFLAGS= @CPPFLAGS@ @CFLAGS@ @PORTAUDIO_CFLAGS@ @SRC_CFLAGS@ @SPANDSP_CFLAGS@ @PTHREAD_CFLAGS@ $(VOIPTEST_CFLAGS)
CFLAGS+=-Wall -Wno-unused-value
#CFLAGS+=-Wunreachable-code
#CFLAGS+=-O0
DEFS= @DEFS@
all: dna libservald.so
all: dna
sqlite3.o: sqlite3.c
@echo CC $<
@ -86,6 +92,8 @@ dna: $(OBJS)
@echo LINK $@
@$(CC) $(CFLAGS) -Wall -o $@ $(OBJS) $(LDFLAGS)
# This does not build on 64 bit elf platforms as NaCL isn't built with -fPIC
# DOC 20120615
libservald.so: $(OBJS)
@echo LINK $@
@$(CC) $(CFLAGS) -Wall -shared -o $@ $(OBJS) $(LDFLAGS)

16
README.DUMMYNETS Normal file
View File

@ -0,0 +1,16 @@
@PGS/20120615
Sometimes it is helpful to run more than one servald instance on a given machine
for debugging purposes. To make this easier, there is a dummy interface driver
that servald knows about. To use it:
1. create an empty file, e.g., dummynet0, somewhere convenient
2. For each servald instance you wish to use it, set the interface specification to include the dummynet file. Use a specification like "+>pathtodummynetfile", where pathtodummynetfile is the relative path from the instance path of that servald instance to the dummynet file. For example, you might run:
% servald config set interfaces "+eth0,+>../dummynet0"
3. Run each servald instance. They should now use the dummy network.
NOTE: Because dummynets are files, not sockets, poll/select does not work on them. As a result the main overlay loop has slightly different behaviour and timing characteristics when a dummynet is in use.
TODO: Convert dummynet interface to use a unixdomain socket, and a simple dummynet server that reflects packets among the clients connected, so that all socket semantics (including use of poll/select) are preserved.

View File

@ -48,6 +48,6 @@ int bufferAudioForPlayback(int codec,long long start_time,long long end_time,
decode codecs etc here. */
/* send audio to device */
int bytesWritten=audev->write(&data[0],dataLen);
// int bytesWritten=audev->write(&data[0],dataLen);
return 0;
}

View File

@ -426,8 +426,10 @@ int app_dna_lookup(int argc, const char *const *argv, struct command_line_option
if (create_serval_instance_dir() == -1)
return -1;
int sid_count=0;
unsigned char sids[128][SID_SIZE];
int uri_count=0;
#define MAXREPLIES 256
#define MAXURILEN 256
char uris[MAXREPLIES][MAXURILEN];
const char *did;
if (cli_arg(argc, argv, o, "did", &did, NULL, "*") == -1)
@ -484,20 +486,29 @@ int app_dna_lookup(int argc, const char *const *argv, struct command_line_option
WHYF(" Error message: %s", mdp.error.message);
}
else if ((rx.packetTypeAndFlags&MDP_TYPE_MASK)==MDP_TX) {
/* Display match unless it is a duplicate.
XXX - For wildcard searches, each sid will only show up once. */
int i;
for(i=0;i<sid_count;i++)
if (!memcmp(&rx.in.src.sid[0],&sids[i][0],SID_SIZE))
break;
if (i==sid_count) {
cli_puts(overlay_render_sid(&rx.in.src.sid[0])); cli_delim(":");
cli_puts((char *)&rx.in.payload[0]); cli_delim(":");
cli_puts((char *)&rx.in.payload[32]); cli_delim("\n");
if (sid_count<128) {
bcopy(&rx.in.src.sid[0],&sids[i][0],SID_SIZE);
sid_count++;
}
/* Extract DID, Name, URI from response. */
if (strlen((char *)rx.in.payload)<512) {
char did[512];
char name[512];
char uri[512];
if (!parseDnaReply(rx.in.payload,rx.in.payload_length,
did,name,uri))
{
/* Have we seen this response before? */
int i;
for(i=0;i<uri_count;i++)
if (!strcmp(uri,uris[i])) break;
if (i==uri_count) {
/* Not previously seen, so report it */
cli_puts(uri); cli_delim(":");
cli_puts(did); cli_delim(":");
cli_puts(name); cli_delim("\n");
/* Remember that we have seen it */
if (uri_count<MAXREPLIES&&strlen(uri)<MAXURILEN) {
strcpy(uris[uri_count++],uri);
}
}
}
}
}
else WHYF("packettype=0x%x",rx.packetTypeAndFlags);
@ -1505,18 +1516,19 @@ int app_keyring_list(int argc, const char *const *argv, struct command_line_opti
{
int kpn;
keypair *kp;
unsigned char *sid=NULL,*did=NULL;
unsigned char *sid=NULL,*did=NULL,*name=NULL;
for(kpn=0;kpn<k->contexts[cn]->identities[in]->keypair_count;kpn++)
{
kp=k->contexts[cn]->identities[in]->keypairs[kpn];
if (kp->type==KEYTYPE_CRYPTOBOX) sid=kp->public_key;
if (kp->type==KEYTYPE_DID) did=kp->private_key;
if (kp->type==KEYTYPE_DID) { did=kp->private_key; name=kp->public_key; }
}
if (sid||did) {
int i;
if (sid) for(i=0;i<SID_SIZE;i++) cli_printf("%02x",sid[i]);
if (sid||did) {
if (sid) cli_printf("%s",overlay_render_sid(sid));
cli_delim(":");
if (did) cli_puts((char*)did);
cli_delim(":");
if (name) cli_puts((char*)name);
cli_delim("\n");
}
}
@ -1630,6 +1642,34 @@ int app_test_rfs(int argc, const char *const *argv, struct command_line_option *
return 0;
}
int app_crypt_test(int argc, const char *const *argv, struct command_line_option *o)
{
unsigned char nonce[crypto_box_curve25519xsalsa20poly1305_NONCEBYTES];
unsigned char k[crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES];
unsigned char plain_block[65536];
urandombytes(nonce,sizeof(nonce));
urandombytes(k,sizeof(k));
int len,i;
overlay_gettime_ms();
for(len=16;len<=65536;len*=2) {
unsigned long long start=overlay_gettime_ms();
for (i=0;i<1000;i++) {
bzero(&plain_block[0],crypto_box_curve25519xsalsa20poly1305_ZEROBYTES);
crypto_box_curve25519xsalsa20poly1305_afternm
(plain_block,plain_block,len,nonce,k);
}
unsigned long long end=overlay_gettime_ms();
printf("%d bytes - 100 tests took %lldms - mean time = %.2fms\n",
len,end-start,(end-start)*1.0/i);
}
return 0;
}
int app_node_info(int argc, const char *const *argv, struct command_line_option *o)
{
const char *sid;
@ -1641,7 +1681,7 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
mdp.packetTypeAndFlags=MDP_NODEINFO;
if (argc>3) resolveDid=1;
mdp.nodeinfo.resolve_did=0; // so we know that we don't have a result yet.
mdp.nodeinfo.resolve_did=1; // Request resolution of DID and Name by local server if it can.
/* get SID or SID prefix
XXX - Doesn't correctly handle odd-lengthed SID prefixes (ignores last digit).
@ -1718,18 +1758,19 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
continue;
}
{
int bytes=m2.in.payload_length;
if ((bytes+1)>=sizeof(mdp.nodeinfo.did)+sizeof(mdp.nodeinfo.name)){
WHYF("Result is too large");
continue;
}
bcopy(&m2.in.payload[0],&mdp.nodeinfo.did[0],32);
bcopy(&m2.in.payload[32],&mdp.nodeinfo.name[0],64);
mdp.nodeinfo.did[bytes]=0;
mdp.nodeinfo.resolve_did=1;
break;
{
char did[512];
char name[512];
char uri[512];
if (!parseDnaReply(m2.in.payload,m2.in.payload_length,
did,name,uri))
{
/* Got a good DNA reply, copy it into place */
bcopy(did,mdp.nodeinfo.did,32);
bcopy(name,mdp.nodeinfo.name,64);
mdp.nodeinfo.resolve_did=1;
break;
}
}
}
}
@ -1845,6 +1886,8 @@ command_line_option command_line_options[]={
"Test RFS field calculation"},
{app_monitor_cli,{"monitor","[<sid>]",NULL},0,
"Interactive servald monitor interface. Specify SID to auto-dial that peer and insert dummy audio data"},
{app_crypt_test,{"crypt","test",NULL},0,
"Run cryptography speed test"},
#ifdef HAVE_VOIPTEST
{app_pa_phone,{"phone",NULL},0,
"Run phone test application"},

177
dna_helper.c Normal file
View File

@ -0,0 +1,177 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 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.
*/
#include "serval.h"
/*
The challenge with making an interface for calling an external program to
resolve a DID into a URI is that it really should be asynchronous, so that
servald can't pause due to delays in looking up DIDs by helper applications.
This can be partially mitigated by having a cache, so that at least for repeated
requests the helper doesn't need to be called each time. This is very important
because the DNA protocol relies on pre-emptive retries to ensure reception of
a request over a lossy network.
The second part of the solution is to create an asynchronous queue for requests,
by passing them via file descriptor to a single persistent instance of the DNA
helper application, and polling the output of that application for results, and
then passing them out to their destinations. This ensures that the process is
asynchronous and non-blocking, regardless of how much time the helper application
requires. Then the helper will just be another file descriptor to poll in the
main loop.
*/
int dna_helper_stdin=-1;
int dna_helper_stdout=-1;
int parseDnaReply(unsigned char *bytes,int count,
char *did,char *name,char *uri)
{
bzero(did,32); bzero(name,64);
bzero(uri,512);
int i,l;
l=0;
for(i=0;i<511&&i<count&&bytes[i]!=0x0a;i++)
did[l++]=bytes[i];
did[l]=0;
if (i>=count||i>=511) return WHY("DNA response does not contain name field");
l=0; i++;
for(;i<511&&i<count&&bytes[i]!=0x0a;i++)
name[l++]=bytes[i];
name[l]=0;
if (i>=count||i>=511) return WHY("DNA response does not contain URI field");
l=0; i++;
for(;i<511&&i<count&&bytes[i]!=0;i++)
uri[l++]=bytes[i];
uri[l]=0;
/* DEBUGF("did='%s', name='%s', uri='%s'",did,name,uri); */
return 0;
}
int dna_helper_start(const char *command)
{
int stdin_fds[2];
int stdout_fds[2];
if (pipe(stdin_fds)) return -1;
if (pipe(stdout_fds)) {
close(stdin_fds[0]); close(stdin_fds[1]);
return -1;
}
int pid=-1;
if ((pid=fork())!=0) {
/* Child, should exec() to become helper after installing file descriptors. */
if (dup2(stdin_fds[1],0)) exit(-1); /* replace stdin */
if (dup2(stdout_fds[0],1)) exit(-1); /* replace stdout */
if (dup2(stdout_fds[0],2)) exit(-1); /* replace stderr */
execl(command,command,NULL);
/* execl() should never return, since it replaces this process with a new
one. Thus something bad must have happened. */
exit(-1);
} else {
if (pid==-1) {
/* fork failed */
close(stdin_fds[0]); close(stdin_fds[1]);
close(stdout_fds[0]); close(stdout_fds[1]);
return -1;
} else {
/* Parent, should put file descriptors into place for use */
dna_helper_stdin=stdin_fds[0];
dna_helper_stdout=stdout_fds[1];
return 0;
}
}
return -1;
}
int dna_helper_enqueue(char *did, unsigned char *requestorSid)
{
/* Check if we have a helper configured. If not, then set
dna_helper_stdin to magic value of -2 so that we don't waste time
in future looking up the dna helper configuration value. */
if (dna_helper_stdin==-2) return -1;
if (dna_helper_stdin==-1) {
const char *dna_helper = confValueGet("dna.helper",NULL);
if (!dna_helper||!dna_helper[0]) {
dna_helper_stdin=-2;
return -1;
}
/* Okay, so we have a helper configured.
Run it */
dna_helper_start(dna_helper);
if (dna_helper_stdin<0)
return -1;
}
/* Write request to dna helper.
Request takes form: DID<space>SID-of-Requestor\n
By passing the requestor's SID to the helper, we don't need to maintain
any state, as all we have to do is wait for responses from the helper,
which will include the requestor's SID.
*/
signal(SIGPIPE,sigPipeHandler);
sigPipeFlag=0;
write(dna_helper_stdin,did,strlen(did));
write(dna_helper_stdin," ",1);
write(dna_helper_stdin,overlay_render_sid(requestorSid),SID_SIZE*2);
write(dna_helper_stdin,"\n",1);
if (sigPipeFlag) {
/* Assume broken pipe due to dead helper.
Next request will cause it to be restarted.
(Losing the current request is not a big problem, because
DNA preemptively retries, anyway.
XXX In fact, we should probably have a limit to the number of restarts
in quick succession so that we don't waste lots of time with a buggy or
suicidal helper.
*/
close(dna_helper_stdin);
close(dna_helper_stdout);
dna_helper_stdin=-1;
dna_helper_stdout=-1;
return -1;
}
return 0;
}
int dna_return_resolution(overlay_mdp_frame *mdp, unsigned char *fromSid,
const char *did,const char *name,const char *uri)
{
/* copy SID out into source address of frame */
bcopy(fromSid,&mdp->out.src.sid[0],SID_SIZE);
/* and build reply as did\nname\nURI<NUL> */
snprintf((char *)&mdp->out.payload[0],512,"%s\n%s\n%s",
did,name,uri);
mdp->out.payload_length=strlen((char *)mdp->out.payload)+1;
/* Dispatch response */
mdp->packetTypeAndFlags&=MDP_FLAG_MASK;
mdp->packetTypeAndFlags|=MDP_TX;
overlay_mdp_dispatch(mdp,0 /* system generated */,
NULL,0);
return 0;
}

23
lsif.c
View File

@ -112,7 +112,7 @@ int scrapeProcNetRoute()
int
lsif(void) {
char buf[8192], addrtxt[INET_ADDRSTRLEN], bcasttxt[INET_ADDRSTRLEN];
char buf[8192];
struct ifconf ifc;
int sck, nInterfaces, ofs;
struct ifreq *ifr;
@ -165,12 +165,14 @@ lsif(void) {
bcopy(&ifr->ifr_ifru.ifru_addr, &local, sizeof(local));
bcopy(&ifr->ifr_ifru.ifru_broadaddr, &broadcast ,sizeof(broadcast));
assert(inet_ntop(AF_INET, (const void *)&local.sin_addr, addrtxt, INET_ADDRSTRLEN) != NULL);
assert(inet_ntop(AF_INET, (const void *)&broadcast.sin_addr, bcasttxt, INET_ADDRSTRLEN) != NULL);
if (debug & DEBUG_OVERLAYINTERFACES) INFOF("name=%s addr=%s, broad=%s\n",
if (debug & DEBUG_OVERLAYINTERFACES) {
char addrtxt[INET_ADDRSTRLEN], bcasttxt[INET_ADDRSTRLEN];
assert(inet_ntop(AF_INET, (const void *)&local.sin_addr, addrtxt, INET_ADDRSTRLEN) != NULL);
assert(inet_ntop(AF_INET, (const void *)&broadcast.sin_addr, bcasttxt, INET_ADDRSTRLEN) != NULL);
INFOF("name=%s addr=%s, broad=%s\n",
ifr->ifr_name,
addrtxt, bcasttxt);
}
overlay_interface_register(ifr->ifr_name, local, broadcast);
nInterfaces++;
}
@ -187,7 +189,6 @@ lsif(void) {
int
doifaddrs(void) {
struct ifaddrs *ifaddr, *ifa;
char addrtxt[INET_ADDRSTRLEN], bcasttxt[INET_ADDRSTRLEN];
char *name;
struct sockaddr_in local, netmask, broadcast;
@ -217,10 +218,12 @@ doifaddrs(void) {
/* Compute broadcast address */
broadcast.sin_addr.s_addr |= (~netmask.sin_addr.s_addr);
assert(inet_ntop(AF_INET, (const void *)&local.sin_addr, addrtxt, INET_ADDRSTRLEN) != NULL);
assert(inet_ntop(AF_INET, (const void *)&broadcast.sin_addr, bcasttxt, INET_ADDRSTRLEN) != NULL);
if (debug & DEBUG_OVERLAYINTERFACES) INFOF("name=%s addr=%s broad=%s", name, addrtxt, bcasttxt);
if (debug & DEBUG_OVERLAYINTERFACES){
char addrtxt[INET_ADDRSTRLEN], bcasttxt[INET_ADDRSTRLEN];
assert(inet_ntop(AF_INET, (const void *)&local.sin_addr, addrtxt, INET_ADDRSTRLEN) != NULL);
assert(inet_ntop(AF_INET, (const void *)&broadcast.sin_addr, bcasttxt, INET_ADDRSTRLEN) != NULL);
INFOF("name=%s addr=%s broad=%s", name, addrtxt, bcasttxt);
}
overlay_interface_register(name,local,broadcast);
}

View File

@ -77,7 +77,8 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
addr.sun_path[0]=0;
snprintf(&addr.sun_path[1],100,"org.servalproject.servald.monitor.socket");
snprintf(&addr.sun_path[1],100,
confValueGet("monitor.socket",DEFAULT_MONITOR_SOCKET_NAME));
int len = 1+strlen(&addr.sun_path[1]) + sizeof(addr.sun_family);
char *p=(char *)&addr;
printf("last char='%c' %02x\n",p[len-1],p[len-1]);

View File

@ -84,14 +84,19 @@ int monitor_setup_sockets()
}
#ifdef linux
/* Use abstract namespace as Android has no writable FS which supports sockets */
/* Use abstract namespace as Android has no writable FS which supports sockets.
Abstract namespace is just plain better, anyway, as no dead files end up
hanging around. */
name.sun_path[0]=0;
/* XXX: 104 comes from OSX sys/un.h - no #define (note Linux has UNIX_PATH_MAX and it's 108(!)) */
snprintf(&name.sun_path[1],104-2,"org.servalproject.servald.monitor.socket");
snprintf(&name.sun_path[1],104-2,
confValueGet("monitor.socket",DEFAULT_MONITOR_SOCKET_NAME));
/* Doesn't include trailing nul */
len = 1+strlen(&name.sun_path[1]) + sizeof(name.sun_family);
#else
snprintf(name.sun_path,104-1,"%s/org.servalproject.servald.monitor.socket",serval_instancepath());
snprintf(name.sun_path,104-1,"%s/",
serval_instancepath(),
confValueGet("monitor.socket",DEFAULT_MONITOR_SOCKET_NAME));
unlink(name.sun_path);
/* Includes trailing nul */
len = 1+strlen(name.sun_path) + sizeof(name.sun_family);
@ -520,8 +525,8 @@ int monitor_process_data(int index)
if (vomp_sample_size(c->sample_codec)!=c->data_offset)
return
WHYF("Ignoring sample block of incorrect size (expected %d, got %d bytes)",
vomp_sample_size(c->sample_codec)!=c->data_offset);
WHYF("Ignoring sample block of incorrect size (expected %d, got %d bytes for codec %d)",
vomp_sample_size(c->sample_codec), c->data_offset, c->sample_codec);
fcntl(c->socket,F_SETFL,
fcntl(c->socket, F_GETFL, NULL)|O_NONBLOCK);
@ -723,7 +728,8 @@ int server_probe(int *pid)
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
addr.sun_path[0]=0;
snprintf(&addr.sun_path[1],100,"org.servalproject.servald.monitor.socket");
snprintf(&addr.sun_path[1],100,
confValueGet("monitor.socket",DEFAULT_MONITOR_SOCKET_NAME));
int len = 1+strlen(&addr.sun_path[1]) + sizeof(addr.sun_family);
char *p=(char *)&addr;
if (0) DEBUGF("last char='%c' %02x\n",p[len-1],p[len-1]);

View File

@ -70,6 +70,41 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
/* @PGS/20120615 */
int last_valid=0;
int last_line;
const char *last_file;
const char *last_func;
long long last_time;
/* @PGS/20120615 */
void TIMING_PAUSE()
{
last_valid=0;
}
/* @PGS/20120615 */
void _TIMING_CHECK(const char *file,const char *func,int line)
{
long long now=overlay_gettime_ms();
if (last_valid) {
if (now-last_time>5) {
// More than 5ms spent in a given task, complain
char msg[1024];
snprintf(msg,1024,"Spent %lldms between %s:%d in %s() and here",
now-last_time,last_file,last_line,last_func);
logMessage(LOG_LEVEL_WARN,file,line,func,"%s",msg);
}
}
last_valid=1;
last_file=file;
last_func=func;
last_line=line;
last_time=now;
}
int overlayMode=0;
overlay_txqueue overlay_tx[OQ_MAX];
@ -121,23 +156,31 @@ int overlayServerMode()
while(1) {
TIMING_CHECK();
server_shutdown_check();
TIMING_CHECK();
/* Work out how long we can wait before we need to tick */
long long ms=overlay_time_until_next_tick();
memabuseCheck();
TIMING_CHECK();
//int filesPresent=0;
fds[0].fd=sock; fds[0].events=POLLIN;
fdcount=1;
rhizome_server_get_fds(fds,&fdcount,128);
TIMING_CHECK();
rhizome_fetching_get_fds(fds,&fdcount,128);
TIMING_CHECK();
overlay_mdp_get_fds(fds,&fdcount,128);
TIMING_CHECK();
monitor_get_fds(fds,&fdcount,128);
TIMING_CHECK();
for(i=0;i<overlay_interface_count;i++)
{
/* Make socket non-blocking so that poll() behaves correctly.
We then set non-blocking before actually reading from it */
/* Make socket blocking so that poll() behaves correctly. */
fcntl(overlay_interfaces[i].fd, F_SETFL,
fcntl(overlay_interfaces[i].fd, F_GETFL, NULL)&(~O_NONBLOCK));
@ -159,7 +202,8 @@ int overlayServerMode()
if (ms>5) ms=5;
}
}
TIMING_CHECK();
/* Progressively update link scores to neighbours etc, and find out how long before
we should next tick the route table.
Basically the faster the CPU and the sparser the route table, the less often we
@ -169,9 +213,15 @@ int overlayServerMode()
int vomp_tick_time=vomp_tick_interval();
if (ms>vomp_tick_time) ms=vomp_tick_time;
TIMING_CHECK();
if (debug&DEBUG_VERBOSE_IO)
DEBUGF("Waiting via poll() for up to %lldms", ms);
TIMING_PAUSE();
/* Sanity check maximum poll timeout */
if (ms<1) ms=1;
if (ms>15000) ms=15000;
int r = poll(fds, fdcount, ms);
TIMING_CHECK();
if (r == -1)
WHY_perror("poll");
else if (debug&DEBUG_VERBOSE_IO) {
@ -182,7 +232,9 @@ int overlayServerMode()
DEBUGF("fd #%d is ready (0x%x)\n", fds[i].fd, fds[i].revents);
}
/* Do high-priority audio handling first */
TIMING_CHECK();
vomp_tick();
TIMING_CHECK();
if (r > 0) {
/* We have data, so try to receive it */
@ -204,27 +256,43 @@ int overlayServerMode()
}
}
TIMING_CHECK();
overlay_rx_messages();
TIMING_CHECK();
if (rhizome_enabled()) {
TIMING_CHECK();
rhizome_server_poll();
TIMING_CHECK();
rhizome_fetch_poll();
TIMING_CHECK();
overlay_mdp_poll();
TIMING_CHECK();
monitor_poll();
TIMING_CHECK();
}
} else {
/* No data before tick occurred, so do nothing.
Well, for now let's just check anyway. */
if (debug&DEBUG_IO) fprintf(stderr,"poll() timeout.\n");
TIMING_CHECK();
overlay_rx_messages();
TIMING_CHECK();
if (rhizome_enabled()) {
TIMING_CHECK();
rhizome_server_poll();
TIMING_CHECK();
rhizome_fetch_poll();
TIMING_CHECK();
overlay_mdp_poll();
TIMING_CHECK();
monitor_poll();
TIMING_CHECK();
}
}
TIMING_CHECK();
/* Check if we need to trigger any ticks on any interfaces */
overlay_check_ticks();
TIMING_CHECK();
}
return 0;

View File

@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <assert.h>
#include <time.h>
#include "serval.h"
@ -113,7 +114,7 @@ int overlay_interface_arg(char *arg)
if (!r) return WHY("calloc(struct interface rules),1) failed");
if (sscanf(arg,"%[+-]%n%[^=+-]%n=%[^:]%n:%d%n:%[^:]%n",
if (sscanf(arg,"%[+-]%n%[^=:,]%n=%[^:]%n:%d%n:%[^:]%n",
sign,&n,interface_name,&n,typestring,&n,&port,&n,speed,&n)>=1)
{
if (n<strlen(arg)) { free(r); return WHY("Extra junk at end of interface specification"); }
@ -180,17 +181,19 @@ int overlay_interface_args(const char *arg)
int
overlay_interface_init_socket(int interface, struct sockaddr_in src_addr, struct sockaddr_in broadcast) {
char srctxt[INET_ADDRSTRLEN];
#define I(X) overlay_interfaces[interface].X
I(broadcast_address) = broadcast;
I(fileP) = 0;
I(fd) = socket(PF_INET,SOCK_DGRAM,0);
if (I(fd)<0) {
if (I(fd) < 0) {
WHY_perror("socket()");
WHYF("Could not create UDP socket for interface: %s",strerror(errno));
goto error;
} else
WHYF("interface #%d fd=%d",interface,I(fd));
INFOF("interface #%d fd=%d",interface, I(fd));
int reuseP = 1;
if (setsockopt(I(fd), SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) < 0) {
@ -214,18 +217,20 @@ overlay_interface_init_socket(int interface, struct sockaddr_in src_addr, struct
a bad signal. */
fcntl(I(fd), F_SETFL, fcntl(I(fd), F_GETFL, NULL) | O_CLOEXEC);
/* @PGS/20120615
Use the broadcast address, so that we can reliably receive broadcast
traffic on all platforms. BUT on OSX we really need a non-broadcast socket
to send from, because you cannot send from a broadcast socket on OSX it seems.
*/
broadcast.sin_family = AF_INET;
broadcast.sin_port = htons(I(port));
/* XXX Is this right? Are we really setting the local side address?
I was in a plane when at the time, so couldn't Google it.
*/
if (debug&DEBUG_PACKETRX) fprintf(stderr,"src_addr=%08x\n",(unsigned int)src_addr.sin_addr.s_addr);
if (bind(I(fd),(struct sockaddr *)&src_addr,sizeof(src_addr))) {
if (bind(I(fd), (struct sockaddr *)&broadcast, sizeof(broadcast))) {
WHY_perror("bind");
WHY("MP HLR server could not bind to requested UDP port (bind() failed)");
goto error;
}
if (debug&(DEBUG_PACKETRX|DEBUG_IO)) fprintf(stderr,"Bound to port 0x%04x\n",src_addr.sin_port);
assert(inet_ntop(AF_INET, (const void *)&broadcast.sin_addr, srctxt, INET_ADDRSTRLEN) != NULL);
if (debug & (DEBUG_PACKETRX | DEBUG_IO)) INFOF("Bound to %s:%d", srctxt, ntohs(broadcast.sin_port));
return 0;
@ -266,9 +271,18 @@ int overlay_interface_init(char *name,struct sockaddr_in src_addr,struct sockadd
if (name[0]=='>') {
I(fileP)=1;
char dummyfile[1024];
if (!FORM_SERVAL_INSTANCE_PATH(dummyfile, &name[1]) || (I(fd) = open(dummyfile,O_APPEND|O_RDWR)) < 1) {
if (name[1]=='/') {
/* Absolute path */
snprintf(dummyfile,1024,"%s",&name[1]);
} else
/* Relative to instance path */
if (!FORM_SERVAL_INSTANCE_PATH(dummyfile, &name[1]))
return WHY("could not form dummy interfance name");
if ((I(fd) = open(dummyfile,O_APPEND|O_RDWR)) < 1) {
return WHY("could not open dummy interface file for append");
}
/* Seek to end of file as initial reading point */
I(offset)=lseek(I(fd),0,SEEK_END); /* socket gets reused to hold file offset */
/* XXX later add pretend location information so that we can decide which "packets" to receive
@ -360,7 +374,6 @@ int overlay_rx_messages()
} else {
/* Read from UDP socket */
int recvttl=1;
errno=0;
plen=recvwithttl(overlay_interfaces[i].fd,packet,sizeof(packet),
&recvttl,&src_addr,&addrlen);
if (plen<0) {
@ -433,9 +446,14 @@ int overlay_broadcast_ensemble(int interface_number,
if (overlay_interfaces[interface_number].fileP)
{
char buf[2048];
bzero(&buf[0],128);
/* Version information */
buf[0]=1; buf[1]=0;
buf[2]=0; buf[3]=0;
/* PID of creator */
buf[4]=getpid()&0xff; buf[5]=getpid()>>8;
/* TODO make a structure for all this stuff */
/* bytes 4-5 = half-power beam height (uint16) */
/* bytes 6-7 = half-power beam width (uint16) */
/* bytes 8-11 = range in metres, centre beam (uint32) */
@ -564,69 +582,72 @@ overlay_interface_register(char *name,
return 0;
}
time_t overlay_last_interface_discover_time=0;
int overlay_interface_discover()
{
int have_route;
/* Don't waste too much time and effort on interface discovery,
especially if we can't attach to a given interface for some reason. */
if (overlay_last_interface_discover_time>time(0))
overlay_last_interface_discover_time=time(0);
if ((time(0)-overlay_last_interface_discover_time)<2) return 0;
overlay_last_interface_discover_time=time(0);
static time_t overlay_last_interface_discover_time = 0;
int
overlay_interface_discover(void) {
int no_route, i;
time_t now;
struct interface_rules *r;
struct sockaddr_in dummyaddr;
/* Don't waste too much time and effort on interface discovery,
especially if we can't attach to a given interface for some reason. */
now = time(NULL);
if (overlay_last_interface_discover_time > now)
overlay_last_interface_discover_time = now;
/* The Android ndk doesn't have ifaddrs.h, so we have to use the netlink interface.
However, netlink is only available on Linux, so for BSD systems, e.g., Mac, we
need to use the ifaddrs method.
if ((now - overlay_last_interface_discover_time) < 2)
return 0;
Also, ifaddrs will work on non-linux systems which is considered critical.
*/
overlay_last_interface_discover_time = now;
/* Mark all interfaces as not observed, so that we know if we need to cull any */
int i;
for(i=0;i<overlay_interface_count;i++) overlay_interfaces[i].observed--;
for(i = 0; i < overlay_interface_count; i++)
overlay_interfaces[i].observed = 0;
/* Check through for any virtual dummy interfaces */
struct interface_rules *r=interface_filter;
while(r) {
if (r->namespec[0]=='>') {
for(i=0;i<overlay_interface_count;i++) if (!strcasecmp(overlay_interfaces[i].name,r->namespec)) break;
if (i<overlay_interface_count)
/* We already know about this interface, so just update it */
overlay_interfaces[i].observed=1;
else {
/* New interface, so register it */
struct sockaddr_in dummyaddr;
if (overlay_interface_init(r->namespec,dummyaddr,dummyaddr,
1000000,PORT_DNA,OVERLAY_INTERFACE_WIFI))
{ if (debug&DEBUG_OVERLAYINTERFACES)
WHY("Could not initialise newly seen interface"); }
else
if (debug&DEBUG_OVERLAYINTERFACES) fprintf(stderr,"Registered interface %s\n",r->namespec);
}
for (r = interface_filter; r != NULL; r = r->next) {
if (r->namespec[0] != '>')
continue;
for(i = 0; i < overlay_interface_count; i++)
if (!strcasecmp(overlay_interfaces[i].name,r->namespec))
break;
if (i < overlay_interface_count)
/* We already know about this interface, so just update it */
overlay_interfaces[i].observed = 1;
else {
/* New interface, so register it */
if (overlay_interface_init(r->namespec,dummyaddr,dummyaddr,
1000000,PORT_DNA,OVERLAY_INTERFACE_WIFI)) {
if (debug & DEBUG_OVERLAYINTERFACES) WHYF("Could not initialise newly seen interface %s", r->namespec);
}
else
if (debug & DEBUG_OVERLAYINTERFACES) INFOF("Registered interface %s",r->namespec);
}
r=r->next;
}
have_route = 1;
/* Look for real interfaces */
no_route = 1;
#ifdef HAVE_IFADDRS_H
if (have_route != 0)
have_route = doifaddrs();
if (no_route != 0)
no_route = doifaddrs();
#endif
#ifdef SIOCGIFCONF
if (have_route != 0)
have_route = lsif();
if (no_route != 0)
no_route = lsif();
#endif
#ifdef linux
if (have_route != 0)
have_route = scrapeProcNetRoute();
if (no_route != 0)
no_route = scrapeProcNetRoute();
#endif
if (have_route != 0) {
FATAL("Unable to get any routing information");
if (no_route != 0) {
FATAL("Unable to get any interface information");
}
return 0;
@ -781,9 +802,12 @@ int overlay_queue_dump(overlay_txqueue *q)
int overlay_tick_interface(int i, long long now)
{
int frame_pax=0;
overlay_buffer *e=NULL;
#define MAX_FRAME_PAX 1024
overlay_frame *pax[MAX_FRAME_PAX];
TIMING_CHECK();
if (overlay_interfaces[i].bits_per_second<1) {
/* An interface with no speed budget is for listening only, so doesn't get ticked */
return 0;
@ -794,7 +818,7 @@ int overlay_tick_interface(int i, long long now)
/* Get a buffer ready, and limit it's size appropriately.
XXX size limit should be reduced from MTU.
XXX we should also take account of the volume of data likely to be in the TX buffer. */
overlay_buffer *e=ob_new(overlay_interfaces[i].mtu);
e=ob_new(overlay_interfaces[i].mtu);
if (!e) return WHY("ob_new() failed");
ob_limitsize(e,overlay_interfaces[i].mtu/4);
@ -803,7 +827,7 @@ int overlay_tick_interface(int i, long long now)
unsigned char bytes[]={/* Magic */ 'O',0x10,
/* Version */ 0x00,0x01};
if (ob_append_bytes(e,bytes,4)) {
ob_free(e);
ob_free(e);
return WHY("ob_append_bytes() refused to append magic bytes.");
}
@ -820,6 +844,7 @@ int overlay_tick_interface(int i, long long now)
Give priority to newly observed nodes so that good news travels quickly to help roaming.
XXX - Don't forget about PONGing reachability reports to allow use of monodirectional links.
*/
TIMING_CHECK();
overlay_stuff_packet_from_queue(i,e,OQ_MESH_MANAGEMENT,now,pax,&frame_pax,MAX_FRAME_PAX);
/* We previously limited manifest space to 3/4 of MTU, but that causes problems for
@ -828,23 +853,30 @@ int overlay_tick_interface(int i, long long now)
#warning reduce to <= mtu*3/4 once we have compacty binary canonical manifest format
ob_limitsize(e,overlay_interfaces[i].mtu*4/4);
TIMING_CHECK();
/* Add advertisements for ROUTES not Rhizome bundles.
Rhizome bundle advertisements are lower priority */
overlay_route_add_advertisements(i,e);
ob_limitsize(e,overlay_interfaces[i].mtu);
TIMING_CHECK();
/* 4. XXX Add lower-priority queued data */
overlay_stuff_packet_from_queue(i,e,OQ_ISOCHRONOUS_VIDEO,now,pax,&frame_pax,MAX_FRAME_PAX);
overlay_stuff_packet_from_queue(i,e,OQ_ORDINARY,now,pax,&frame_pax,MAX_FRAME_PAX);
overlay_stuff_packet_from_queue(i,e,OQ_OPPORTUNISTIC,now,pax,&frame_pax,MAX_FRAME_PAX);
/* 5. XXX Fill the packet up to a suitable size with anything that seems a good idea */
TIMING_CHECK();
if (rhizome_enabled())
overlay_rhizome_add_advertisements(i,e);
if (debug&DEBUG_PACKETCONSTRUCTION)
dump("assembled packet",&e->bytes[0],e->length);
TIMING_CHECK();
/* Now send the frame. This takes the form of a special DNA packet with a different
service code, which we setup earlier. */
if (debug&DEBUG_OVERLAYINTERFACES)
@ -923,10 +955,14 @@ int overlay_tick_interface(int i, long long now)
}
}
}
if (e) ob_free(e); e=NULL;
return 0;
}
else return WHY("overlay_broadcast_ensemble() failed");
else {
if (e) ob_free(e); e=NULL;
return WHY("overlay_broadcast_ensemble() failed");
}
TIMING_CHECK();
}
@ -936,15 +972,18 @@ overlay_check_ticks(void) {
/* Check if any interface(s) are due for a tick */
int i;
TIMING_CHECK();
/* Check for changes to interfaces */
overlay_interface_discover();
TIMING_CHECK();
long long now = overlay_gettime_ms();
/* Now check if the next tick time for the interfaces is no later than that time.
If so, trigger a tick on the interface. */
if (debug & DEBUG_OVERLAYINTERFACES) INFOF("Examining %d interfaces.",overlay_interface_count);
for(i = 0; i < overlay_interface_count; i++) {
TIMING_CHECK();
/* Only tick live interfaces */
if (overlay_interfaces[i].observed > 0) {
if (debug & DEBUG_VERBOSE_IO) INFOF("Interface %s ticks every %dms, last at %lld.",
@ -952,12 +991,16 @@ overlay_check_ticks(void) {
overlay_interfaces[i].tick_ms,
overlay_interfaces[i].last_tick_ms);
if (now >= overlay_interfaces[i].last_tick_ms + overlay_interfaces[i].tick_ms) {
/* This interface is due for a tick */
overlay_tick_interface(i, now);
overlay_interfaces[i].last_tick_ms = now;
TIMING_CHECK();
/* This interface is due for a tick */
overlay_tick_interface(i, now);
TIMING_CHECK();
overlay_interfaces[i].last_tick_ms = now;
}
} else
if (debug & DEBUG_VERBOSE_IO) INFOF("Interface %s is awol.", overlay_interfaces[i].name);
if (debug & DEBUG_VERBOSE_IO) INFOF("Interface %s is awol.", overlay_interfaces[i].name);
TIMING_CHECK();
}
return 0;

View File

@ -42,7 +42,8 @@ int overlay_mdp_setup_sockets()
/* XXX The 100 should be replaced with the actual maximum allowed.
Apparently POSIX requires it to be at least 100, but I would still feel
more comfortable with using the appropriate constant. */
snprintf(&name.sun_path[1],100,"org.servalproject.mesh.overlay.mdp");
snprintf(&name.sun_path[1],100,
confValueGet("mdp.socket",DEFAULT_MDP_SOCKET_NAME);
len = 1+strlen(&name.sun_path[1]) + sizeof(name.sun_family);
mdp_abstract_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
@ -476,10 +477,20 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
}
if (match>-1) {
struct sockaddr_un addr;
printf("unix domain socket '%s'\n",mdp_bindings_sockets[match]);
bcopy(mdp_bindings_sockets[match],&addr.sun_path[0],mdp_bindings_socket_name_lengths[match]);
addr.sun_family=AF_UNIX;
int r=sendto(mdp_named_socket,mdp,overlay_mdp_relevant_bytes(mdp),0,(struct sockaddr*)&addr,sizeof(addr));
if (r==overlay_mdp_relevant_bytes(mdp)) return 0;
errno=0;
int len=overlay_mdp_relevant_bytes(mdp);
int r=sendto(mdp_named_socket,mdp,len,0,(struct sockaddr*)&addr,sizeof(addr));
if (r==overlay_mdp_relevant_bytes(mdp)) {
return 0;
}
if (errno==ENOENT) {
/* far-end of socket has died, so drop binding */
printf("Closing dead MDP client '%s'\n",mdp_bindings_sockets[match]);
overlay_mdp_releasebindings(&addr,mdp_bindings_socket_name_lengths[match]);
}
WHY_perror("sendto(e)");
return WHY("Failed to pass received MDP frame to client");
} else {
@ -505,12 +516,22 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
/* make sure it is null terminated */
did[pll]=0;
/* remember source sid for putting back later */
unsigned char srcsid[32];
bcopy(&mdp->out.src.sid[0],&srcsid[0],SID_SIZE);
/* now switch addresses around for any replies */
overlay_mdp_swap_src_dst(mdp);
overlay_mdp_frame mdpreply;
int results=0;
while(keyring_find_did(keyring,&cn,&in,&kp,did))
{
bzero(&mdpreply,sizeof(mdpreply));
/* mark as outgoing MDP message */
mdpreply.packetTypeAndFlags=MDP_TX;
/* Set source and destination addresses */
bcopy(&mdp->out.dst.sid,mdpreply.out.src.sid,SID_SIZE);
bcopy(&mdp->out.src.sid,mdpreply.out.dst.sid,SID_SIZE);
mdpreply.out.src.port=mdp->out.dst.port;
mdpreply.out.dst.port=mdp->out.src.port;
/* package DID and Name into reply (we include the DID because
it could be a wild-card DID search, but the SID is implied
in the source address of our reply). */
@ -518,46 +539,42 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
->private_key_len>64)
/* skip excessively long DID records */
continue;
/* copy SID out into source address of frame */
/* and null-terminated DID */
bcopy(&keyring->contexts[cn]->identities[in]->keypairs[0]
->public_key[0],&mdp->out.src.sid[0],SID_SIZE);
bcopy(keyring->contexts[cn]->identities[in]->keypairs[kp]
->private_key,&mdp->out.payload[0],
keyring->contexts[cn]->identities[in]->keypairs[kp]
->private_key_len);
bcopy(keyring->contexts[cn]->identities[in]->keypairs[kp]
->public_key,&mdp->out.payload[keyring
->contexts[cn]
->identities[in]
->keypairs[kp]
->private_key_len],
keyring->contexts[cn]->identities[in]->keypairs[kp]
->private_key_len);
/* set length */
mdp->out.payload_length=
unsigned char *unpackedDid=
keyring->contexts[cn]->identities[in]->keypairs[kp]
->private_key_len
+keyring->contexts[cn]->identities[in]->keypairs[kp]
->public_key_len;
/* mark as outgoing MDP message */
mdp->packetTypeAndFlags&=MDP_FLAG_MASK;
mdp->packetTypeAndFlags|=MDP_TX;
overlay_mdp_dispatch(mdp,0 /* system generated */,
NULL,0);
kp++;
->private_key;
unsigned char *packedSid=
keyring->contexts[cn]->identities[in]->keypairs[0]
->public_key;
char *name=
(char *)keyring->contexts[cn]->identities[in]->keypairs[kp]
->public_key;
/* copy SID out into source address of frame */
bcopy(packedSid,&mdpreply.out.src.sid[0],SID_SIZE);
/* and build reply as did\nname\nURI<NUL> */
snprintf((char *)&mdpreply.out.payload[0],512,"%s\n%s\nsid://%s/%s",
unpackedDid,name,overlay_render_sid(packedSid),
unpackedDid);
mdpreply.out.payload_length=strlen((char *)mdpreply.out.payload)+1;
/* deliver reply */
overlay_mdp_dispatch(&mdpreply,0 /* system generated */,NULL,0);
kp++;
results++;
}
/* and switch addresses back around in case the caller was planning on
using MDP structure again (this happens if there is a loop-back reply
and the frame needs sending on, as happens with broadcasts. MDP ping
is a simple application where this occurs).
Similarly restore destination address & MDP payload content and
length */
overlay_mdp_swap_src_dst(mdp);
bcopy(&srcsid[0],&mdp->out.src.sid[0],SID_SIZE);
bcopy(&did[0],&mdp->out.payload[0],pll);
mdp->out.payload_length=pll;
if (!results) {
/* No local results, so see if servald has been configured to use
a DNA-helper that can provide additional mappings. This provides
a generalised interface for resolving telephone numbers into URIs.
The first use will be for resolving DIDs to SIP addresses for
OpenBTS boxes run by the OTI/Commotion project.
The helper is run asynchronously, and the replies will be delivered
when results become available, so this function will return
immediately, so as not to cause blockages and delays in servald.
*/
dna_helper_enqueue(did,mdp->out.src.sid);
}
return 0;
}
break;
@ -600,7 +617,8 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
default:
/* Unbound socket. We won't be sending ICMP style connection refused
messages, partly because they are a waste of bandwidth. */
return WHY("Received packet for which no listening process exists");
return WHYF("Received packet for which no listening process exists (MDP ports: src=%d, dst=%d",
mdp->out.src.port,mdp->out.dst.port);
}
}
break;
@ -672,6 +690,8 @@ int overlay_mdp_sanitytest_sourceaddr(sockaddr_mdp *src,int userGeneratedFrameP,
printf("addr=%s port=%u (0x%x)\n",
overlay_render_sid(src->sid),src->port,src->port);
if (recvaddr) printf("recvaddr='%s'\n",
recvaddr->sun_path);
return WHY("No such socket binding:unix domain socket tuple exists -- someone might be trying to spoof someone else's connection");
}
@ -1076,7 +1096,7 @@ int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp)
end of the string, to avoid information leaks */
len=&mdp->error.message[0]-(char *)mdp;
len+=strlen(mdp->error.message)+1;
INFOF("mdp return/error code: %d:%s",mdp->error.error,mdp->error.message);
if (mdp->error.error) INFOF("mdp return/error code: %d:%s",mdp->error.error,mdp->error.message);
break;
case MDP_VOMPEVENT:
/* XXX too hard to work out precisely for now. */
@ -1138,9 +1158,10 @@ int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms)
mdp->packetTypeAndFlags=MDP_ERROR;
mdp->error.error=1;
snprintf(mdp->error.message,128,"Timeout waiting for reply to MDP packet (packet was successfully sent).");
return WHY("Timeout waiting for server response");
return -1; /* WHY("Timeout waiting for server response"); */
}
int ttl=-1;
if (!overlay_mdp_recv(mdp,&ttl)) {
/* If all is well, examine result and return error code provided */

View File

@ -192,7 +192,7 @@ int sendToPeers(unsigned char *packet,int packet_len,int method,int peerId,struc
bzero(&peer_addr, sizeof(peer_addr));
peer_addr.sin_family=AF_INET;
peer_addr.sin_port = htons(4110);
peer_addr.sin_port = htons(PORT_DNA);
if (method==REQ_PARALLEL) i=0; else { i=peerId; maxPeer=i; }
for(;i<=maxPeer;i++)

View File

@ -31,8 +31,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
int rhizome_server_socket=-1;
int sigPipeFlag=0;
int sigIoFlag=0;
rhizome_http_request *rhizome_live_http_requests[RHIZOME_SERVER_MAX_LIVE_REQUESTS];
int rhizome_server_live_request_count=0;
@ -62,19 +60,6 @@ unsigned char favicon_bytes[]={
,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int favicon_len=318;
void sigPipeHandler(int signal)
{
sigPipeFlag++;
return;
}
void sigIoHandler(int signal)
{
WHY("sigio");
sigIoFlag++;
return;
}
int rhizome_server_start()
{
if (rhizome_server_socket>-1) return 0;

View File

@ -114,6 +114,11 @@ struct in_addr {
/* bzero(3) is deprecated in favour of memset(3). */
#define bzero(addr,len) memset((addr), 0, (len))
/* @PGS/20120615 */
#define TIMING_CHECK() _TIMING_CHECK(__FILE__,__FUNCTION__,__LINE__)
void _TIMING_CHECK(const char *file,const char *func,int line);
void TIMING_PAUSE();
/* UDP Port numbers for various Serval services.
The overlay mesh works over DNA */
#define PORT_DNA 4110
@ -1517,3 +1522,17 @@ int stopAudio();
#define SERVER_NOTRUNNING 3
#define SERVER_RUNNING 4
int server_probe(int *pid);
int dna_helper_enqueue(char *did, unsigned char *requestorSid);
int dna_return_resolution(overlay_mdp_frame *mdp, unsigned char *fromSid,
const char *did,const char *name,const char *uri);
int parseDnaReply(unsigned char *bytes,int count,
char *did,char *name,char *uri);
extern int sigPipeFlag;
extern int sigIoFlag;
void sigPipeHandler(int signal);
void sigIoHandler(int signal);
#define DEFAULT_MONITOR_SOCKET_NAME "org.servalproject.servald.monitor.socket"
#define DEFAULT_MDP_SOCKET_NAME "org.servalproject.servald.mdp.socket"

33
sighandlers.c Normal file
View File

@ -0,0 +1,33 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 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.
*/
int sigPipeFlag=0;
int sigIoFlag=0;
void sigPipeHandler(int signal)
{
sigPipeFlag++;
return;
}
void sigIoHandler(int signal)
{
sigIoFlag++;
return;
}

View File

@ -191,13 +191,16 @@ signal_all_servald_processes() {
# first SIGTERM then SIGHUP and finally SIGKILL
# - assert that no more servald processes are running
kill_all_servald_processes() {
if signal_all_servald_processes TERM; then
sleep 2
if signal_all_servald_processes HUP; then
sleep 2
# PGS 20120621 - Made fast so that tests can be run quickly
# TODO: Make this better by checking that things really have died, and take
# exactly the time required, rather than using fixed delays
# if signal_all_servald_processes TERM; then
# sleep 2
# if signal_all_servald_processes HUP; then
# sleep 2
signal_all_servald_processes KILL
fi
fi
# fi
# fi
}
# Utility function:

170
tests/dnaprotocol Executable file
View File

@ -0,0 +1,170 @@
#!/bin/bash
# Tests for Serval DNA server operations.
#
# Copyright 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.
source "${0%/*}/../testframework.sh"
source "${0%/*}/../testdefs.sh"
setup() {
setup_servald
assert_no_servald_processes
set_instance
}
teardown() {
# TODO Disabled until stopping multiple-instances are supported
# TODO stop_all_servald_servers
kill_all_servald_processes
assert_no_servald_processes
}
setup_servald_instance() {
set_instance $1
executeOk_servald config set interfaces "+>$2"
executeOk_servald config set monitor.socket "org.servalproject.servald.monitor.socket.$1"
executeOk_servald config set mdp.socket "org.servalproject.servald.mdp.socket.$1"
executeOk_servald keyring add
assert [ -e "$SERVALINSTANCE_PATH/serval.keyring" ]
executeOk_servald keyring list
tfw_cat --stdout
sid=$(replayStdout | sed -ne "1s/^\($rexp_sid\):.*\$/\1/p")
assert --message='main identity known' [ -n "$sid" ]
executeOk_servald set did $sid 5550001 "Agent $1 Smith"
start_servald_server $1
executeOk_servald status
tfw_cat --stdout
}
setup_servald_instances() {
setup_servald
DUMMYNET=/tmp/dummy
rm $DUMMYNET
touch $DUMMYNET
assert [ -e $DUMMYNET ]
setup_servald_instance A $DUMMYNET
SIDA=$sid
setup_servald_instance B $DUMMYNET
SIDB=$sid
# Now make sure that they can see each other
sleep 5 # Should be plenty of time
set_instance A
echo "Dummynet file $DUMMYNET after 5 seconds: "`ls -l $DUMMYNET`
executeOk_servald id peers
assertStdoutLineCount '==' 1
}
doc_MultipleServalDTest="Can start multiple servald instances communicating via a dummy interface"
setup_MultipleServalDTest() {
setup
}
test_MultipleServalDTest() {
setup_servald_instances
}
doc_DNAWildcardSearchFindsSelf="DNA lookup of wildcard finds (star method)"
setup_DNAWildcardSearchFindsSelf() {
setup
}
test_DNAWildcardSearchFindsSelf() {
setup_servald_instances
set_instance A
executeOk_servald dna lookup "*"
assertStdoutLineCount '==' 2
assertStdoutGrep --matches=1 "^sid://$SIDA/5550001:5550001:Agent A Smith$"
assertStdoutGrep --matches=1 "^sid://$SIDB/5550001:5550001:Agent B Smith$"
}
doc_DNAWildcardSearchFindsSelfEmpty="DNA lookup of wildcard (empty query method)"
setup_DNAWildcardSearchFindsSelfEmpty() {
setup
}
test_DNAWildcardSearchFindsSelfEmpty() {
setup_servald_instances
set_instance A
executeOk_servald dna lookup ""
assertStdoutLineCount '==' 2
assertStdoutGrep --matches=1 "^sid://$SIDA/5550001:5550001:Agent A Smith$"
assertStdoutGrep --matches=1 "^sid://$SIDB/5550001:5550001:Agent B Smith$"
}
doc_DNASpecificLookup="DNA Lookup by phone number"
setup_DNASpecificLookup() {
setup
}
test_DNASpecificLookup() {
setup_servald_instances
set_instance A
# Make sure we get no false positives
executeOk_servald dna lookup "5551234"
assertStdoutLineCount '==' 0
executeOk_servald dna lookup "555000"
assertStdoutLineCount '==' 0
executeOk_servald dna lookup "55500011"
assertStdoutLineCount '==' 0
# Make sure we get the right results, and no duplicates
executeOk_servald dna lookup "5550001"
assertStdoutLineCount '==' 2
assertStdoutGrep --matches=1 "^sid://$SIDA/5550001:5550001:Agent A Smith$"
assertStdoutGrep --matches=1 "^sid://$SIDB/5550001:5550001:Agent B Smith$"
}
doc_DNANodeInfoLocalResolution="'node info' auto-resolves for local identities"
setup_DNANodeInfoLocalResolution() {
setup
}
test_DNANodeInfoLocalResolution() {
setup_servald_instances
set_instance A
# node info for a local identity returns DID/Name since it is free, even
# if it isn't asked for.
executeOk_servald node info $SIDA
assertStdoutLineCount '==' 1
assertStdoutGrep --matches=1 "Agent A Smith"
assertStdoutGrep --matches=0 "did-not-resolved"
}
doc_DNANodeInfoRemoteResolution="'node info' for remote identities"
setup_DNANodeInfoRemoteResolution() {
setup
}
test_DNANodeInfoRemoteResolution() {
setup_servald_instances
set_instance A
# if resolvedid is not specified for a remote identity, then don't resolve
# it.
executeOk_servald node info $SIDB
assertStdoutLineCount '==' 1
assertStdoutGrep --matches=0 "Agent B Smith"
assertStdoutGrep --matches=1 "did-not-resolved"
# But if it resolvedid is specified, then do resolve it using DNA
executeOk_servald node info $SIDB resolvedid
assertStdoutLineCount '==' 1
assertStdoutGrep --matches=1 "Agent B Smith"
assertStdoutGrep --matches=0 "did-not-resolved"
}
runTests "$@"