Merge branch 'eventscheduler' into master

Conflicts:
	commandline.c
	monitor.c
	overlay.c
	overlay_interface.c
	overlay_packetformats.c
	rhizome_fetch.c
	rhizome_http.c
	rhizome_packetformats.c
	serval.h
	server.c
	testdefs.sh
	testframework.sh
	tests/dnaprotocol
	tests/server
This commit is contained in:
Andrew Bettison 2012-07-03 10:26:22 +09:30
commit 8020ea3b74
31 changed files with 2281 additions and 2079 deletions

View File

@ -22,7 +22,8 @@ SERVALD_SRC_FILES = \
serval-dna/gateway.c \
serval-dna/overlay.c \
serval-dna/overlay_broadcast.c \
serval-dna/packetformats.c \
serval-dna/performance_timing.c \
serval-dna/packetformats.c \
serval-dna/peers.c \
serval-dna/randombytes.c \
serval-dna/rhizome.c \
@ -44,6 +45,7 @@ SERVALD_SRC_FILES = \
serval-dna/lsif.c \
serval-dna/dna_helper.c \
serval-dna/sighandlers.c \
serval-dna/fdqueue.c \
serval-dna/monitor.c \
serval-dna/monitor-cli.c \
serval-dna/codecs.c \

View File

@ -24,6 +24,7 @@ SRCS= main.c \
overlay_payload.c \
overlay_route.c \
packetformats.c \
performance_timing.c \
peers.c \
randombytes.c \
responses.c \
@ -47,6 +48,7 @@ SRCS= main.c \
monitor-cli.c \
dna_helper.c \
sighandlers.c \
fdqueue.c \
codecs.c \
audiodevices.c \
audio_msm_g1.c \

View File

@ -418,7 +418,7 @@ int audio_msm_g1_poll_fds(struct pollfd *fds,int slots)
int count=0;
if (playFd>-1&&slots>0) {
fds[count].fd=playFd;
fds[count].events=POLL_IN;
fds[count].events=POLLIN;
count++; slots--;
}
return count;

View File

@ -325,7 +325,7 @@ int getReplyPackets(int method,int peer,int batchP,struct response_set *response
if (debug&DEBUG_SIMULATION) DEBUGF("Simulation mode: Dropped packet due to simulated link parameters");
continue;
}
if (!packetOk(-1,buffer,len,transaction_id,ttl,recvaddr,recvaddrlen,0)) {
if (!packetOk(NULL,buffer,len,transaction_id,ttl,recvaddr,recvaddrlen,0)) {
/* Packet passes tests - extract responses and append them to the end of the response list */
if (extractResponses(client_addr,buffer,len,responses))
return WHY("Problem extracting response fields from reply packets");

View File

@ -1746,24 +1746,37 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
if (overlay_mdp_bind(srcsid,port)) port=0;
if (port) {
int i;
for(i=0;i<(3000/125);i++) {
m2.packetTypeAndFlags=MDP_TX;
m2.out.src.port=port;
bcopy(&srcsid[0],&m2.out.src.sid[0],SID_SIZE);
bcopy(&mdp.nodeinfo.sid[0],&m2.out.dst.sid[0],SID_SIZE);
m2.out.dst.port=MDP_PORT_DNALOOKUP;
/* search for any DID */
m2.out.payload[0]=0;
m2.out.payload_length=1;
if (overlay_mdp_send(&m2,MDP_AWAITREPLY,125)){
if (0) {
WHY("Poll for DNA number resolution failed");
if (m2.packetTypeAndFlags==MDP_ERROR)
WHYF("error.error=%d, error.message=%s",m2.error.error,m2.error.message);
}
unsigned long long now = overlay_gettime_ms();
unsigned long long timeout = now+3000;
unsigned long long next_send = now;
while(now < timeout){
now=overlay_gettime_ms();
if (now >= next_send){
m2.packetTypeAndFlags=MDP_TX;
m2.out.src.port=port;
bcopy(&srcsid[0],&m2.out.src.sid[0],SID_SIZE);
bcopy(&mdp.nodeinfo.sid[0],&m2.out.dst.sid[0],SID_SIZE);
m2.out.dst.port=MDP_PORT_DNALOOKUP;
/* search for any DID */
m2.out.payload[0]=0;
m2.out.payload_length=1;
overlay_mdp_send(&m2,0,0);
next_send+=125;
continue;
}
long long timeout_ms = (next_send>timeout?timeout:next_send) - now;
if (overlay_mdp_client_poll(timeout_ms)<=0)
continue;
int ttl=-1;
if (overlay_mdp_recv(&m2,&ttl))
continue;
if ((m2.packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR){
// TODO log error?
continue;
}
@ -1777,8 +1790,7 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
continue;
}
// we might receive a response from an ealier request
// TODO, don't send another query just yet, we should try to receieve another response first
// we might receive a late response from an ealier request, ignore it
if (memcmp(&m2.in.src.sid[0],&mdp.nodeinfo.sid[0],SID_SIZE)){
WHYF("Unexpected result from SID %s", overlay_render_sid(m2.in.src.sid));
continue;
@ -1790,13 +1802,13 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
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;
}
{
/* 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;
}
}
}
}

191
fdqueue.c Normal file
View File

@ -0,0 +1,191 @@
/*
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"
#include <poll.h>
#define MAX_WATCHED_FDS 128
struct pollfd fds[MAX_WATCHED_FDS];
int fdcount=0;
struct sched_ent *fd_callbacks[MAX_WATCHED_FDS];
struct sched_ent *next_alarm=NULL;
struct profile_total poll_stats={NULL,0,"Idle (in poll)",0,0,0};
void list_alarms(){
long long now=overlay_gettime_ms();
struct sched_ent *alarm = next_alarm;
int i;
INFO("Alarms;");
while(alarm){
INFOF("%s in %lldms",
(alarm->stats?alarm->stats->name:"Unnamed"),
alarm->alarm - now);
alarm = alarm->_next;
}
INFO("File handles;");
for (i=0;i<fdcount;i++)
INFOF("%s watching #%d",
(fd_callbacks[i]->stats?fd_callbacks[i]->stats->name:"Unnamed"),
fds[i].fd);
}
// add an alarm to the list of scheduled function calls.
// simply populate .alarm with the absolute time, and .function with the method to call.
// on calling .poll.revents will be zero.
int schedule(struct sched_ent *alarm){
long long now=overlay_gettime_ms();
struct sched_ent *node = next_alarm, *last = NULL;
while(node!=NULL){
if (node->alarm > alarm->alarm)
break;
last = node;
node = node->_next;
}
if (last == NULL){
next_alarm = alarm;
}else{
last->_next=alarm;
}
alarm->_prev = last;
if(node!=NULL)
node->_prev = alarm;
alarm->_next = node;
return 0;
}
// remove a function from the schedule before it has fired
// safe to unschedule twice...
int unschedule(struct sched_ent *alarm){
struct sched_ent *prev = alarm->_prev;
struct sched_ent *next = alarm->_next;
if (prev)
prev->_next = next;
else if(next_alarm==alarm)
next_alarm = next;
if (next)
next->_prev = prev;
alarm->_prev = NULL;
alarm->_next = NULL;
return 0;
}
// start watching a file handle, call this function again if you wish to change the event mask
int watch(struct sched_ent *alarm){
if (alarm->_poll_index>=0 && fd_callbacks[alarm->_poll_index]==alarm){
// updating event flags
INFOF("Updating watch %s, #%d for %d", (alarm->stats?alarm->stats->name:"Unnamed"), alarm->poll.fd, alarm->poll.events);
}else{
INFOF("Adding watch %s, #%d for %d", (alarm->stats?alarm->stats->name:"Unnamed"), alarm->poll.fd, alarm->poll.events);
if (fdcount>=MAX_WATCHED_FDS)
return WHY("Too many file handles to watch");
fd_callbacks[fdcount]=alarm;
alarm->_poll_index=fdcount;
fdcount++;
}
fds[alarm->_poll_index]=alarm->poll;
return 0;
}
// stop watching a file handle
int unwatch(struct sched_ent *alarm){
int index = alarm->_poll_index;
if (index <0 || fds[index].fd!=alarm->poll.fd)
return WHY("Attempted to unwatch a handle that is not being watched");
fdcount--;
if (index!=fdcount){
// squash fds
fds[index] = fds[fdcount];
fd_callbacks[index] = fd_callbacks[fdcount];
fd_callbacks[index]->_poll_index=index;
}
fds[fdcount].fd=-1;
fd_callbacks[fdcount]=NULL;
alarm->_poll_index=-1;
INFOF("%s stopped watching #%d for %d", (alarm->stats?alarm->stats->name:"Unnamed"), alarm->poll.fd, alarm->poll.events);
return 0;
}
void call_alarm(struct sched_ent *alarm, int revents){
struct call_stats call_stats;
struct profile_total *stats = alarm->stats;
if (stats)
fd_func_enter(&call_stats);
alarm->poll.revents = revents;
alarm->function(alarm);
if (stats)
fd_func_exit(&call_stats, stats);
}
int fd_checkalarms()
{
long long now=overlay_gettime_ms();
if (next_alarm!=NULL&&next_alarm->alarm <=now){
struct sched_ent *alarm = next_alarm;
unschedule(alarm);
call_alarm(alarm, 0);
now=overlay_gettime_ms();
}
if (next_alarm)
return next_alarm->alarm - now;
return 15000;
}
int fd_poll()
{
int i, r;
/* See if any alarms have expired before we do anything.
This also returns the time to the next alarm that is due. */
int ms=fd_checkalarms();
/* Make sure we don't have any silly timeouts that will make us wait for ever. */
if (ms<0) ms=0;
/* Wait for action or timeout */
{
struct call_stats call_stats;
fd_func_enter(&call_stats);
r=poll(fds, fdcount, ms);
fd_func_exit(&call_stats, &poll_stats);
}
/* If file descriptors are ready, then call the appropriate functions */
if (r>0) {
for(i=0;i<fdcount;i++)
if (fds[i].revents) {
/* Make socket non-blocking */
SET_NONBLOCKING(fds[i].fd);
call_alarm(fd_callbacks[i], fds[i].revents);
/* Make socket blocking again */
SET_BLOCKING(fds[i].fd);
}
}
return 0;
}

View File

@ -1118,10 +1118,12 @@ int keyring_sanitise_position(const keyring_file *k,int *cn,int *in,int *kp)
unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid,
unsigned char **sas_public)
{
IN();
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");
if (!keyring_find_sid(k,&cn,&in,&kp,sid)) {
RETURN(WHYNULL("Could not find SID in keyring, so can't find SAS"));
}
for(kp=0;kp<k->contexts[cn]->identities[in]->keypair_count;kp++)
if (k->contexts[cn]->identities[in]->keypairs[kp]->type==KEYTYPE_CRYPTOSIGN)
@ -1129,10 +1131,11 @@ unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid,
if (sas_public)
*sas_public=
k->contexts[cn]->identities[in]->keypairs[kp]->public_key;
return k->contexts[cn]->identities[in]->keypairs[kp]->private_key;
if (0) WHYF("Found SAS entry for %s*",overlay_render_sid_prefix(sid,7));
RETURN(k->contexts[cn]->identities[in]->keypairs[kp]->private_key);
}
return WHYNULL("Identity lacks SAS");
RETURN(WHYNULL("Identity lacks SAS"));
}
struct sid_sas_mapping {
@ -1201,6 +1204,8 @@ int keyring_mapping_request(keyring_file *k,overlay_mdp_frame *req)
return overlay_mdp_dispatch(req,1,NULL,0);
} else {
/* It's probably a response. */
WHYF("Received %d byte key mapping response",
req->out.payload_length);
switch(req->out.payload[0]) {
case KEYTYPE_CRYPTOSIGN:
{
@ -1219,6 +1224,7 @@ int keyring_mapping_request(keyring_file *k,overlay_mdp_frame *req)
bcopy(&compactsignature[0],&signature[0],32);
bcopy(&req->out.src.sid[0],&signature[32],SID_SIZE);
bcopy(&compactsignature[32],&signature[32+SID_SIZE],32);
int r=crypto_sign_edwards25519sha512batch_open(plain,&plain_len,
signature,siglen,
sas_public);
@ -1276,19 +1282,26 @@ unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid)
For now we will just use a non-persistent cache for safety (and it happens
to be easy to implement as well :)
*/
IN();
int i;
long long now=overlay_gettime_ms();
for(i=0;i<sid_sas_mapping_count;i++)
{
if (memcmp(sid,sid_sas_mappings[i].sid,SID_SIZE)) continue;
if (sid_sas_mappings[i].validP) return sid_sas_mappings[i].sas_public;
if (sid_sas_mappings[i].validP)
{ if (0)
WHYF("Found SAS public entry for %s*",overlay_render_sid_prefix(sid,7));
RETURN(sid_sas_mappings[i].sas_public); }
/* Don't flood the network with mapping requests */
if ((now-sid_sas_mappings[i].last_request_time_in_ms)<1000) return NULL;
if (((now-sid_sas_mappings[i].last_request_time_in_ms)<1000)
&&((now-sid_sas_mappings[i].last_request_time_in_ms)>=0))
{ WHYF("Too soon to ask for SAS mapping again."); RETURN(NULL); }
/* we can request again, so fall out to where we do that.
i is set to this mapping, so the request process will update this
record. */
break;
}
WHYF("Asking for SAS mapping for %s",overlay_render_sid(sid));
/* allocate mapping slot or replace one at random, depending on how full things
are */
@ -1304,7 +1317,7 @@ unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid)
sid_sas_mappings[i].validP=0;
sid_sas_mappings[i].last_request_time_in_ms=now;
/* request mapping. */
/* request mapping (send request auth-crypted). */
overlay_mdp_frame mdp;
mdp.packetTypeAndFlags=MDP_TX;
bcopy(&sid[0],&mdp.out.dst.sid[0],SID_SIZE);
@ -1316,12 +1329,14 @@ unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid)
==KEYTYPE_CRYPTOBOX)
bcopy(keyring->contexts[0]->identities[0]->keypairs[0]->public_key,
mdp.out.src.sid,SID_SIZE);
else return WHYNULL("couldn't request SAS (I don't know who I am)");
else { RETURN(WHYNULL("couldn't request SAS (I don't know who I am)")); }
mdp.out.payload_length=1;
mdp.out.payload[0]=KEYTYPE_CRYPTOSIGN;
overlay_mdp_dispatch(&mdp,0 /* system generated */,
NULL,0);
return NULL;
if (overlay_mdp_dispatch(&mdp,0 /* system generated */,
NULL,0))
{ RETURN(WHYNULL("Failed to send SAS resolution request")); }
WHYF("Dispatched SAS resolution request");
RETURN(NULL);
}
int keyring_find_sid(const keyring_file *k,int *cn,int *in,int *kp, const unsigned char *sid)
@ -1434,9 +1449,10 @@ struct nm_record nm_cache[NM_CACHE_SLOTS];
unsigned char *keyring_get_nm_bytes(sockaddr_mdp *known,sockaddr_mdp *unknown)
{
if (!known) return WHYNULL("known pub key is null");
if (!unknown) return WHYNULL("unknown pub key is null");
if (!keyring) return WHYNULL("keyring is null");
IN();
if (!known) { RETURN(WHYNULL("known pub key is null")); }
if (!unknown) { RETURN(WHYNULL("unknown pub key is null")); }
if (!keyring) { RETURN(WHYNULL("keyring is null")); }
int i;
@ -1447,14 +1463,14 @@ unsigned char *keyring_get_nm_bytes(sockaddr_mdp *known,sockaddr_mdp *unknown)
crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)) continue;
if (memcmp(nm_cache[i].unknown_key,unknown->sid,
crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)) continue;
return nm_cache[i].nm_bytes;
{ RETURN(nm_cache[i].nm_bytes); }
}
/* 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.");
{ RETURN(WHYNULL("known key is not in fact known.")); }
/* work out where to store it */
if (nm_slots_used<NM_CACHE_SLOTS) {
@ -1475,5 +1491,5 @@ unsigned char *keyring_get_nm_bytes(sockaddr_mdp *known,sockaddr_mdp *unknown)
->identities[in]
->keypairs[kp]->private_key);
return nm_cache[i].nm_bytes;
RETURN(nm_cache[i].nm_bytes);
}

1
lsif.c
View File

@ -50,6 +50,7 @@
#if __MACH__
#include <net/if_dl.h>
#endif
#include <net/if.h>
/* On platforms that have variable length
ifreq use the old fixed length interface instead */

View File

@ -132,11 +132,9 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
if (audev&&audev->poll_fds) fdcount+=audev->poll_fds(&fds[fdcount],128-fdcount);
poll(fds,fdcount,1000);
fcntl(fd,F_SETFL,
fcntl(fd, F_GETFL, NULL)|O_NONBLOCK);
SET_NONBLOCKING(fd);
if (interactiveP)
fcntl(STDIN_FILENO,F_SETFL,
fcntl(STDIN_FILENO, F_GETFL, NULL)|O_NONBLOCK);
SET_NONBLOCKING(STDIN_FILENO);
int bytes;
int i;
@ -184,10 +182,8 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
audioRecordBufferBytes-=audioRecordBufferOffset;
}
fcntl(fd,F_SETFL,
fcntl(fd, F_GETFL, NULL)&~O_NONBLOCK);
fcntl(STDIN_FILENO,F_SETFL,
fcntl(STDIN_FILENO, F_GETFL, NULL)&~O_NONBLOCK);
SET_BLOCKING(fd);
SET_BLOCKING(STDIN_FILENO);
}
return 0;

456
monitor.c
View File

@ -34,11 +34,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define MONITOR_LINE_LENGTH 160
#define MONITOR_DATA_SIZE MAX_AUDIO_BYTES
struct monitor_context {
struct sched_ent alarm;
#define MONITOR_VOMP (1<<0)
#define MONITOR_RHIZOME (1<<1)
#define MONITOR_PEERS (1<<2)
int flags;
int socket;
char line[MONITOR_LINE_LENGTH];
int line_length;
#define MONITOR_STATE_COMMAND 1
@ -56,23 +56,24 @@ int monitor_socket_count=0;
struct monitor_context monitor_sockets[MAX_MONITOR_SOCKETS];
long long monitor_last_update_time=0;
int monitor_process_command(int index,char *cmd);
int monitor_process_data(int index);
static void monitor_new_socket(int s);
int monitor_process_command(struct monitor_context *c);
int monitor_process_data(struct monitor_context *c);
static void monitor_new_client(int s);
struct sched_ent named_socket;
struct profile_total named_stats;
struct profile_total client_stats;
int monitor_named_socket=-1;
int monitor_setup_sockets()
{
struct sockaddr_un name;
int len;
int sock;
bzero(&name, sizeof(name));
name.sun_family = AF_UNIX;
if (monitor_named_socket!=-1)
return 0;
if ((monitor_named_socket = socket(AF_UNIX, SOCK_STREAM, 0))==-1) {
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0))==-1) {
WHY_perror("socket");
goto error;
}
@ -96,84 +97,51 @@ int monitor_setup_sockets()
len = 1+strlen(name.sun_path) + sizeof(name.sun_family);
#endif
if(bind(monitor_named_socket, (struct sockaddr *)&name, len)==-1) {
if(bind(sock, (struct sockaddr *)&name, len)==-1) {
WHY_perror("bind");
goto error;
}
if(listen(monitor_named_socket,MAX_MONITOR_SOCKETS)==-1) {
if(listen(sock,MAX_MONITOR_SOCKETS)==-1) {
WHY_perror("listen");
goto error;
}
int reuseP=1;
if(setsockopt(monitor_named_socket, SOL_SOCKET, SO_REUSEADDR,
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
&reuseP, sizeof(reuseP)) < 0) {
WHY_perror("setsockopt");
WHY("Could not indicate reuse addresses. Not necessarily a problem (yet)");
}
int send_buffer_size=64*1024;
if(setsockopt(monitor_named_socket, SOL_SOCKET, SO_RCVBUF,
if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
&send_buffer_size, sizeof(send_buffer_size))==-1)
WHY_perror("setsockopt");
if (debug&(DEBUG_IO|DEBUG_VERBOSE_IO)) DEBUG("Monitor server socket setup");
named_socket.function=monitor_poll;
named_stats.name="monitor_poll";
named_socket.stats=&named_stats;
named_socket.poll.fd=sock;
named_socket.poll.events=POLLIN;
watch(&named_socket);
return 0;
error:
close(monitor_named_socket);
monitor_named_socket=-1;
close(sock);
return -1;
}
int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax)
void monitor_poll(struct sched_ent *alarm)
{
/* Make sure sockets are open */
monitor_setup_sockets();
int s,i,m;
unsigned char buffer[1024];
char msg[1024];
struct sockaddr *ignored_address=(struct sockaddr *)&buffer[0];
socklen_t ignored_length=sizeof(ignored_address);
/* This block should work, but in reality it doesn't.
poll() on linux is ALWAYS claiming that accept() can be
run. So we just have to check it whenever some other fd triggers
poll to break, which fortunately is fairly often. */
if ((*fdcount)>=fdmax) return -1;
if (monitor_named_socket>-1)
{
if (debug&(DEBUG_IO|DEBUG_VERBOSE_IO)) {
DEBUGF("Monitor named unix domain socket is poll() slot #%d (fd %d)\n",
*fdcount,monitor_named_socket);
}
fds[*fdcount].fd=monitor_named_socket;
fds[*fdcount].events=POLLIN;
(*fdcount)++;
}
int i;
if (debug&(DEBUG_IO|DEBUG_VERBOSE_IO))
DEBUGF("looking at %d monitor clients",monitor_socket_count);
for(i=0;i<monitor_socket_count;i++) {
if ((*fdcount)>=fdmax) return -1;
if (debug&(DEBUG_IO|DEBUG_VERBOSE_IO)) {
DEBUGF("Monitor named unix domain client socket is poll() slot #%d (fd %d)\n",
*fdcount,monitor_sockets[i].socket);
}
fds[*fdcount].fd=monitor_sockets[i].socket;
fds[*fdcount].events=POLLIN;
(*fdcount)++;
}
return 0;
}
int
monitor_poll(void) {
int bytes, i, m, s;
socklen_t addrlen;
long long now;
char msg[128];
struct monitor_context *c;
/* tell all monitor clients about status of all calls periodically */
now = overlay_gettime_ms();
long long now = overlay_gettime_ms();
if (monitor_last_update_time > (now + 1000)) {
INFO("Fixed run away monitor_last_update_time");
monitor_last_update_time = now + 1000;
@ -190,25 +158,22 @@ monitor_poll(void) {
/* And let far-end know that call is still alive */
snprintf(msg,sizeof(msg) -1,"\nKEEPALIVE:%06x\n", vomp_call_states[i].local.session);
for(m = 0;m < monitor_socket_count; m++)
WRITE_STR(monitor_sockets[m].socket,msg);
WRITE_STR(monitor_sockets[m].alarm.poll.fd,msg);
}
}
/* Check for new connections */
fcntl(monitor_named_socket, F_SETFL,
fcntl(monitor_named_socket, F_GETFL, NULL) | O_NONBLOCK);
/* We don't care about the peer's address */
addrlen = 0;
ignored_length = 0;
while (
#ifdef HAVE_LINUX_IF_H
(s = accept4(monitor_named_socket, NULL, &addrlen,O_NONBLOCK))
(s = accept4(alarm->poll.fd, NULL, &ignored_length,O_NONBLOCK))
#else
(s = accept(monitor_named_socket,NULL, &addrlen))
(s = accept(alarm->poll.fd,NULL, &ignored_length))
#endif
!= -1
) {
addrlen = 0;
monitor_new_socket(s);
monitor_new_client(s);
}
if (errno != EAGAIN) {
#ifdef HAVE_LINUX_IF_H
@ -217,109 +182,106 @@ monitor_poll(void) {
WHY_perror("accept");
#endif
}
/* Read from any open connections */
for(i = 0;i < monitor_socket_count; i++) {
nextInSameSlot:
c = &monitor_sockets[i];
fcntl(c->socket,F_SETFL,
fcntl(c->socket, F_GETFL, NULL) | O_NONBLOCK);
switch(c->state) {
case MONITOR_STATE_COMMAND:
bytes = 1;
while(bytes == 1) {
if (c->line_length >= MONITOR_LINE_LENGTH) {
/* line too long */
c->line[MONITOR_LINE_LENGTH-1] = 0;
monitor_process_command(i, c->line);
bytes = -1;
break;
}
bytes = read(c->socket, &c->line[c->line_length], 1);
if (bytes < 1) {
switch(errno) {
case EINTR:
case ENOTRECOVERABLE:
/* transient errors */
WHY_perror("read");
break;
case EAGAIN:
break;
default:
WHY_perror("read");
/* all other errors; close socket */
WHYF("Tearing down monitor client #%d due to errno=%d (%s)",
i, errno, strerror(errno));
close(c->socket);
if (i == monitor_socket_count - 1) {
monitor_socket_count--;
continue;
} else {
bcopy(&monitor_sockets[monitor_socket_count-1],
&monitor_sockets[i],
sizeof(struct monitor_context));
monitor_socket_count--;
goto nextInSameSlot;
}
}
}
if (bytes > 0 && (c->line[c->line_length] != '\r')) {
c->line_length += bytes;
if (c->line[c->line_length-1] == '\n') {
/* got command */
c->line[c->line_length-1] = 0; /* trim new line for easier parsing */
monitor_process_command(i, c->line);
break;
}
}
}
break;
case MONITOR_STATE_DATA:
bytes = read(c->socket,
&c->buffer[c->data_offset],
c->data_expected-c->data_offset);
if (bytes < 1) {
switch(errno) {
case EAGAIN: case EINTR:
/* transient errors */
break;
default:
/* all other errors; close socket */
WHYF("Tearing down monitor client #%d due to errno=%d (%s)",
i, errno, strerror(errno));
close(c->socket);
if (i == monitor_socket_count - 1) {
monitor_socket_count--;
continue;
} else {
bcopy(&monitor_sockets[monitor_socket_count - 1],
&monitor_sockets[i],
sizeof(struct monitor_context));
monitor_socket_count--;
goto nextInSameSlot;
}
}
} else {
c->data_offset += bytes;
if (c->data_offset >= c->data_expected)
{
/* we have the binary data we were expecting. */
monitor_process_data(i);
c->state = MONITOR_STATE_COMMAND;
}
}
break;
default:
c->state = MONITOR_STATE_COMMAND;
INFO("fixed monitor connection state");
}
}
return 0;
}
static void
monitor_new_socket(int s) {
void monitor_client_close(struct monitor_context *c){
struct monitor_context *last;
unwatch(&c->alarm);
close(c->alarm.poll.fd);
c->alarm.poll.fd=-1;
monitor_socket_count--;
last = &monitor_sockets[monitor_socket_count];
if (last != c){
unwatch(&last->alarm);
bcopy(last, c,
sizeof(struct monitor_context));
watch(&c->alarm);
}
}
void monitor_client_poll(struct sched_ent *alarm)
{
/* Read from any open connections */
struct monitor_context *c=(struct monitor_context *)alarm;
errno=0;
int bytes;
switch(c->state) {
case MONITOR_STATE_COMMAND:
bytes = 1;
while(bytes == 1) {
if (c->line_length >= MONITOR_LINE_LENGTH) {
/* line too long */
c->line[MONITOR_LINE_LENGTH-1] = 0;
monitor_process_command(c);
bytes = -1;
break;
}
bytes = read(c->alarm.poll.fd, &c->line[c->line_length], 1);
if (bytes < 1) {
switch(errno) {
case EINTR:
case ENOTRECOVERABLE:
/* transient errors */
WHY_perror("read");
break;
case EAGAIN:
break;
default:
WHY_perror("read");
/* all other errors; close socket */
INFO("Tearing down monitor client");
monitor_client_close(c);
return;
}
}
if (bytes > 0 && (c->line[c->line_length] != '\r')) {
c->line_length += bytes;
if (c->line[c->line_length-1] == '\n') {
/* got command */
c->line[c->line_length-1] = 0; /* trim new line for easier parsing */
monitor_process_command(c);
break;
}
}
}
break;
case MONITOR_STATE_DATA:
bytes = read(c->alarm.poll.fd,
&c->buffer[c->data_offset],
c->data_expected-c->data_offset);
if (bytes < 1) {
switch(errno) {
case EAGAIN: case EINTR:
/* transient errors */
break;
default:
/* all other errors; close socket */
WHYF("Tearing down monitor client due to errno=%d",
errno);
monitor_client_close(c);
return;
}
} else {
c->data_offset += bytes;
if (c->data_offset >= c->data_expected)
{
/* we have the binary data we were expecting. */
monitor_process_data(c);
c->state = MONITOR_STATE_COMMAND;
}
}
break;
default:
c->state = MONITOR_STATE_COMMAND;
WHY("fixed monitor connection state");
}
return;
}
static void monitor_new_client(int s) {
#ifdef linux
struct ucred ucred;
socklen_t len;
@ -330,12 +292,7 @@ monitor_new_socket(int s) {
uid_t otheruid;
struct monitor_context *c;
#ifndef HAVE_LINUX_IF_H
if ((res = fcntl(s, F_SETFL, O_NONBLOCK)) == -1) {
WHY_perror("fcntl()");
goto error;
}
#endif
SET_NONBLOCKING(s);
#ifdef linux
len = sizeof(ucred);
@ -360,23 +317,25 @@ monitor_new_socket(int s) {
WHYF("monitor.socket client has wrong uid (%d versus %d)", otheruid,getuid());
WRITE_STR(s, "\nCLOSE:Incorrect UID\n");
goto error;
} else if (monitor_socket_count >= MAX_MONITOR_SOCKETS
}
if (monitor_socket_count >= MAX_MONITOR_SOCKETS
||monitor_socket_count < 0) {
WRITE_STR(s, "\nCLOSE:All sockets busy\n");
goto error;
} else {
c = &monitor_sockets[monitor_socket_count];
c->socket = s;
c->line_length = 0;
c->state = MONITOR_STATE_COMMAND;
monitor_socket_count++;
WRITE_STR(s,"\nMONITOR:You are talking to servald\n");
INFOF("Got %d clients", monitor_socket_count);
}
fcntl(monitor_named_socket,F_SETFL,
fcntl(monitor_named_socket, F_GETFL, NULL)|O_NONBLOCK);
c = &monitor_sockets[monitor_socket_count++];
c->alarm.function = monitor_client_poll;
client_stats.name = "monitor_client_poll";
c->alarm.stats=&client_stats;
c->alarm.poll.fd = s;
c->alarm.poll.events=POLLIN;
c->line_length = 0;
c->state = MONITOR_STATE_COMMAND;
WRITE_STR(s,"\nMONITOR:You are talking to servald\n");
INFOF("Got %d clients", monitor_socket_count);
watch(&c->alarm);
return;
error:
@ -384,23 +343,22 @@ monitor_new_socket(int s) {
return;
}
int monitor_process_command(int index,char *cmd)
int monitor_process_command(struct monitor_context *c)
{
int callSessionToken,sampleType,bytes;
char sid[MONITOR_LINE_LENGTH],localDid[MONITOR_LINE_LENGTH];
char remoteDid[MONITOR_LINE_LENGTH],digits[MONITOR_LINE_LENGTH];
overlay_mdp_frame mdp;
char *cmd = c->line;
IN();
mdp.packetTypeAndFlags=MDP_VOMPEVENT;
struct monitor_context *c=&monitor_sockets[index];
c->line_length=0;
fcntl(c->socket,F_SETFL,
fcntl(c->socket, F_GETFL, NULL)|O_NONBLOCK);
if (strlen(cmd)>MONITOR_LINE_LENGTH) {
WRITE_STR(c->socket,"\nERROR:Command too long\n");
return -1;
WRITE_STR(c->alarm.poll.fd,"\nERROR:Command too long\n");
RETURN(-1);
}
char msg[1024];
@ -423,7 +381,7 @@ int monitor_process_command(int index,char *cmd)
/* Start getting sample */
c->sample_call_session_token=callSessionToken;
c->sample_codec=sampleType;
return 0;
RETURN(0);
}
}
}
@ -469,7 +427,7 @@ int monitor_process_command(int index,char *cmd)
int cn=0,in=0,kp=0;
if(!keyring_next_identity(keyring,&cn,&in,&kp))
{
WRITE_STR(c->socket,"\nERROR:no local identity, so cannot place call\n");
WRITE_STR(c->alarm.poll.fd,"\nERROR:no local identity, so cannot place call\n");
}
else {
bcopy(keyring->contexts[cn]->identities[in]
@ -510,7 +468,7 @@ int monitor_process_command(int index,char *cmd)
int digit=vomp_parse_dtmf_digit(digits[i]);
if (digit<0) {
snprintf(msg,1024,"\nERROR: invalid DTMF digit 0x%02x\n",digit);
WRITE_STR(c->socket,msg);
WRITE_STR(c->alarm.poll.fd,msg);
}
mdp.vompevent.audio_bytes[mdp.vompevent.audio_sample_bytes]
=(digit<<4); /* 80ms standard tone duration, so that it is a multiple
@ -521,19 +479,15 @@ int monitor_process_command(int index,char *cmd)
}
fcntl(c->socket,F_SETFL,
fcntl(c->socket, F_GETFL, NULL)|O_NONBLOCK);
snprintf(msg,1024,"\nMONITORSTATUS:%d\n",c->flags);
WRITE_STR(c->socket,msg);
WRITE_STR(c->alarm.poll.fd,msg);
return 0;
RETURN(0);
}
int monitor_process_data(int index)
int monitor_process_data(struct monitor_context *c)
{
/* Called when we have received an entire data sample */
struct monitor_context *c=&monitor_sockets[index];
c->state=MONITOR_STATE_COMMAND;
if (vomp_sample_size(c->sample_codec)!=c->data_offset) {
@ -542,12 +496,9 @@ int monitor_process_data(int index)
return -1;
}
fcntl(c->socket,F_SETFL,
fcntl(c->socket, F_GETFL, NULL)|O_NONBLOCK);
vomp_call_state *call=vomp_find_call_by_session(c->sample_call_session_token);
if (!call) {
WRITE_STR(c->socket,"\nERROR:No such call\n");
WRITE_STR(c->alarm.poll.fd,"\nERROR:No such call\n");
return -1;
}
@ -581,32 +532,24 @@ int monitor_announce_bundle(rhizome_manifest *m)
sender,
recipient,
m->dataFileName?m->dataFileName:"");
for(i=0;i<monitor_socket_count;i++)
for(i=monitor_socket_count -1;i>=0;i--)
{
if (!(monitor_sockets[i].flags&MONITOR_RHIZOME))
continue;
nextInSameSlot:
errno=0;
fcntl(monitor_sockets[i].socket,F_SETFL,
fcntl(monitor_sockets[i].socket, F_GETFL, NULL)|O_NONBLOCK);
WRITE_STR(monitor_sockets[i].socket,msg);
if (errno&&(errno!=EINTR)&&(errno!=EAGAIN)) {
/* error sending update, so kill monitor socket */
WHY_perror("write");
INFOF("Tearing down monitor client #%d", i);
close(monitor_sockets[i].socket);
if (i==monitor_socket_count-1) {
monitor_socket_count--;
continue;
} else {
bcopy(&monitor_sockets[monitor_socket_count-1],
&monitor_sockets[i],
sizeof(struct monitor_context));
monitor_socket_count--;
goto nextInSameSlot;
}
}
errno=0;
SET_NONBLOCKING(monitor_sockets[i].alarm.poll.fd);
WRITE_STR(monitor_sockets[i].alarm.poll.fd,msg);
SET_BLOCKING(monitor_sockets[i].alarm.poll.fd);
if (errno&&(errno!=EINTR)&&(errno!=EAGAIN)) {
/* error sending update, so kill monitor socket */
WHY_perror("write");
INFO("Tearing down monitor client");
monitor_client_close(&monitor_sockets[i]);
}
}
return 0;
}
@ -615,6 +558,7 @@ int monitor_call_status(vomp_call_state *call)
int i;
char msg[1024];
int show=0;
IN();
if (call->local.state>call->local.last_state) show=1;
if (call->remote.state>call->remote.last_state) show=1;
call->local.last_state=call->local.state;
@ -629,34 +573,23 @@ int monitor_call_status(vomp_call_state *call)
overlay_render_sid(call->remote.sid),
call->local.did,call->remote.did);
msg[1023]=0;
for(i=0;i<monitor_socket_count;i++)
for(i=monitor_socket_count -1;i>=0;i--)
{
if (!(monitor_sockets[i].flags&MONITOR_VOMP))
continue;
nextInSameSlot:
errno=0;
fcntl(monitor_sockets[i].socket,F_SETFL,
fcntl(monitor_sockets[i].socket, F_GETFL, NULL)|O_NONBLOCK);
WRITE_STR(monitor_sockets[i].socket,msg);
SET_NONBLOCKING(monitor_sockets[i].alarm.poll.fd);
WRITE_STR(monitor_sockets[i].alarm.poll.fd,msg);
SET_BLOCKING(monitor_sockets[i].alarm.poll.fd);
if (errno&&(errno!=EINTR)&&(errno!=EAGAIN)) {
/* error sending update, so kill monitor socket */
WHY_perror("write");
INFOF("Tearing down monitor client #%d", i);
close(monitor_sockets[i].socket);
if (i==monitor_socket_count-1) {
monitor_socket_count--;
continue;
} else {
bcopy(&monitor_sockets[monitor_socket_count-1],
&monitor_sockets[i],
sizeof(struct monitor_context));
monitor_socket_count--;
goto nextInSameSlot;
}
monitor_client_close(&monitor_sockets[i]);
}
}
}
return 0;
RETURN(0);
}
int monitor_announce_peer(unsigned char *sid)
@ -687,6 +620,7 @@ int monitor_send_audio(vomp_call_state *call,overlay_mdp_frame *audio)
audio->vompevent.audio_sample_endtime);
bcopy(&audio->vompevent.audio_bytes[0], &msg[msglen], sample_bytes);
msglen+=sample_bytes;
msg[msglen++]='\n';
monitor_tell_clients(msg, msglen, MONITOR_VOMP);
return 0;
}
@ -694,32 +628,22 @@ int monitor_send_audio(vomp_call_state *call,overlay_mdp_frame *audio)
int monitor_tell_clients(char *msg, int msglen, int mask)
{
int i;
for(i=0;i<monitor_socket_count;i++)
IN();
for(i=monitor_socket_count -1;i>=0;i--)
{
if (!(monitor_sockets[i].flags&mask))
continue;
nextInSameSlot:
errno=0;
fcntl(monitor_sockets[i].socket,F_SETFL,
fcntl(monitor_sockets[i].socket, F_GETFL, NULL)|O_NONBLOCK);
WRITE_STR(monitor_sockets[i].socket,msg);
// DEBUGF("Writing AUDIOPACKET to client");
SET_NONBLOCKING(monitor_sockets[i].alarm.poll.fd);
write(monitor_sockets[i].alarm.poll.fd, msg, msglen);
SET_BLOCKING(monitor_sockets[i].alarm.poll.fd);
// WHYF("Writing AUDIOPACKET to client");
if (errno&&(errno!=EINTR)&&(errno!=EAGAIN)) {
/* error sending update, so kill monitor socket */
WHY_perror("write");
INFOF("Tearing down monitor client #%d", i);
close(monitor_sockets[i].socket);
if (i==monitor_socket_count-1) {
monitor_socket_count--;
continue;
} else {
bcopy(&monitor_sockets[monitor_socket_count-1],
&monitor_sockets[i],
sizeof(struct monitor_context));
monitor_socket_count--;
goto nextInSameSlot;
}
monitor_client_close(&monitor_sockets[i]);
}
}
return 0;
RETURN(0);
}

271
overlay.c
View File

@ -71,40 +71,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "strbuf.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
logMessage(LOG_LEVEL_WARN, file, line, func,
"Spent %lldms between %s:%d in %s() and here",
now - last_time, last_file, last_line, last_func);
}
}
last_valid=1;
last_file=file;
last_func=func;
last_line=line;
last_time=now;
}
int overlayMode=0;
overlay_txqueue overlay_tx[OQ_MAX];
@ -131,7 +97,7 @@ int overlayServerMode()
int i;
for(i=0;i<OQ_MAX;i++) {
overlay_tx[i].maxLength=100;
overlay_tx[i].latencyTarget=5000; /* Keep packets in queue for 5 seconds by default */
overlay_tx[i].latencyTarget=1000; /* Keep packets in queue for 1 second by default */
}
/* But expire voice/video call packets much sooner, as they just aren't any use if late */
overlay_tx[OQ_ISOCHRONOUS_VOICE].latencyTarget=500;
@ -144,168 +110,69 @@ int overlayServerMode()
of wifi latency anyway, so we'll live with it. Larger values will affect voice transport,
and smaller values would affect CPU and energy use, and make the simulation less realistic. */
struct pollfd fds[128];
int fdcount;
/* Create structures to use 1MB of RAM for testing */
overlay_route_init(1);
#define SCHEDULE(X, Y) \
struct sched_ent _sched_##X; \
struct profile_total _stats_##X; \
bzero(&_sched_##X, sizeof(struct sched_ent)); \
_sched_##X.stats = &_stats_##X; \
_sched_##X.function=X;\
_stats_##X.name="" #X "";\
_sched_##X.alarm=overlay_gettime_ms()+Y;\
schedule(&_sched_##X);
/* Periodically check for server shut down */
SCHEDULE(server_shutdown_check, 0);
/* Setup up MDP & monitor interface unix domain sockets */
overlay_mdp_setup_sockets();
monitor_setup_sockets();
/* 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_server_poll();
if (rhizome_enabled()) rhizome_http_server_start();
/* Pick next rhizome files to grab every few seconds
from the priority list continuously being built from observed
bundle announcements */
SCHEDULE(rhizome_enqueue_suggestions, 3000);
/* Periodically check for new interfaces */
SCHEDULE(overlay_interface_discover, 1);
/* Start scheduling interface ticks */
SCHEDULE(overlay_check_ticks, 2);
/* Periodically update route table. */
SCHEDULE(overlay_route_tick, 100);
/* Keep an eye on VoMP calls so that we can expire stale ones etc */
SCHEDULE(vomp_tick, 1000);
/* Show CPU usage stats periodically */
SCHEDULE(fd_periodicstats, 3000);
#undef SCHEDULE
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 blocking so that poll() behaves correctly. */
fcntl(overlay_interfaces[i].fd, F_SETFL,
fcntl(overlay_interfaces[i].fd, F_GETFL, NULL)&(~O_NONBLOCK));
if ((!overlay_interfaces[i].fileP)&&(fdcount<128))
{
if (debug&DEBUG_IO) {
DEBUGF("Interface %s is poll() slot #%d (fd %d)",
overlay_interfaces[i].name,
fdcount,
overlay_interfaces[i].fd);
}
fds[fdcount].fd=overlay_interfaces[i].fd;
fds[fdcount].events=POLLRDNORM;
fds[fdcount].revents=0;
fdcount++;
}
if (overlay_interfaces[i].fileP) {
//filesPresent=1;
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
will need to tick in order to keep each tick nice and fast. */
int route_tick_interval=overlay_route_tick();
if (ms>route_tick_interval) ms=route_tick_interval;
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) {
DEBUGF("poll() says %d file descriptors are ready", r);
int i;
for(i=0;i<fdcount;i++)
if (fds[i].revents)
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 */
if (debug&DEBUG_IO) {
DEBUGF("poll() reports %d fds ready", r);
int i;
for(i=0;i<fdcount;i++) {
if (fds[i].revents) {
strbuf b = strbuf_alloca(120);
strbuf_sprintf(b, " #%d (fd %d): %d (",i,fds[i].fd,fds[i].revents);
if ((fds[i].revents&POLL_IN)==POLL_IN) strbuf_puts(b, "POLL_IN,");
if ((fds[i].revents&POLLRDNORM)==POLLRDNORM) strbuf_puts(b, "POLLRDNORM,");
if ((fds[i].revents&POLL_OUT)==POLL_OUT) strbuf_puts(b, "POLL_OUT,");
if ((fds[i].revents&POLL_ERR)==POLL_ERR) strbuf_puts(b, "POLL_ERR,");
if ((fds[i].revents&POLL_HUP)==POLL_HUP) strbuf_puts(b, "POLL_HUP,");
if ((fds[i].revents&POLLNVAL)==POLLNVAL) strbuf_puts(b, "POLL_NVAL,");
strbuf_puts(b, ")");
DEBUG(strbuf_str(b));
}
}
}
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) DEBUGF("poll() timeout");
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();
/* Check for activitiy and respond to it */
fd_poll();
}
return 0;
}
int overlay_frame_process(int interface,overlay_frame *f)
int overlay_frame_process(struct overlay_interface *interface,overlay_frame *f)
{
if (!f) return WHY("f==NULL");
IN();
if (!f) RETURN(WHY("f==NULL"));
long long now=overlay_gettime_ms();
if (f->source_address_status==OA_RESOLVED&&overlay_address_is_local(f->source))
return WHY("Dropping frame claiming to come from myself.");
RETURN(WHY("Dropping frame claiming to come from myself."));
if (debug&DEBUG_OVERLAYFRAMES) DEBUGF(">>> Received frame (type=%02x, bytes=%d)",f->type,f->payload?f->payload->length:-1);
@ -322,25 +189,25 @@ int overlay_frame_process(int interface,overlay_frame *f)
{
case OA_UNINITIALISED:
/* Um? Right. */
return WHY("frame passed with ununitialised nexthop address");
RETURN(WHY("frame passed with ununitialised nexthop address"));
break;
case OA_RESOLVED:
/* Great, we have the address, so we can get on with things */
break;
case OA_PLEASEEXPLAIN:
return -1; // WHY("Address cannot be resolved -- aborting packet processing.");
RETURN(-1); // WHY("Address cannot be resolved -- aborting packet processing.");
/* XXX Should send a please explain to get this address resolved. */
break;
case OA_UNSUPPORTED:
default:
// TODO tell the sender
/* If we don't support the address format, we should probably tell
the sender. Again, we queue this up, and cancel it if someone else
tells them in the meantime to avoid an Opposition Event (like a Hanson
Event, but repeatedly berating any node that holds a different policy
to itself. */
WHY("Packet with unsupported address format");
overlay_interface_repeat_abbreviation_policy[interface]=1;
return -1;
RETURN(-1);
break;
}
@ -359,8 +226,8 @@ int overlay_frame_process(int interface,overlay_frame *f)
if (forMe) {
/* It's for us, so resolve the addresses */
if (overlay_frame_resolve_addresses(interface,f))
return WHY("Failed to resolve destination and sender addresses in frame");
if (overlay_frame_resolve_addresses(f))
RETURN(WHY("Failed to resolve destination and sender addresses in frame"));
broadcast=overlay_address_is_broadcast(f->destination);
if (debug&DEBUG_OVERLAYFRAMES) {
strbuf b = strbuf_alloca(1024);
@ -383,7 +250,7 @@ int overlay_frame_process(int interface,overlay_frame *f)
if (f->source_address_status!=OA_RESOLVED) {
if (debug&DEBUG_OVERLAYFRAMES) WHY("Source address could not be resolved, so dropping frame.");
return -1;
RETURN(-1);
}
if (overlay_address_is_local(f->source))
{
@ -391,7 +258,7 @@ int overlay_frame_process(int interface,overlay_frame *f)
you hear everything you send. */
if (debug&DEBUG_OVERLAYROUTING)
WHY("Dropping frame claiming to come from myself.");
return -1;
RETURN(-1);
}
if (f->destination_address_status==OA_RESOLVED) {
@ -400,7 +267,7 @@ int overlay_frame_process(int interface,overlay_frame *f)
if (overlay_address_is_local(f->destination)) ultimatelyForMe=1;
} else {
if (debug&DEBUG_OVERLAYFRAMES) WHY("Destination address could not be resolved, so dropping frame.");
return WHY("could not resolve destination address");
RETURN(WHY("could not resolve destination address"));
}
}
@ -412,12 +279,12 @@ int overlay_frame_process(int interface,overlay_frame *f)
if (duplicateBroadcast) {
if (0) DEBUG("Packet is duplicate broadcast");
return 0;
RETURN(0);
}
/* Not for us? Then just ignore it */
if (!forMe) {
return 0;
RETURN(0);
}
/* Is this a frame we have to forward on? */
@ -444,7 +311,8 @@ int overlay_frame_process(int interface,overlay_frame *f)
if (!broadcast) {
if (overlay_get_nexthop(f->destination,f->nexthop,&len,
&f->nexthop_interface))
WHY("Could not find next hop for host - dropping frame");
WHYF("Could not find next hop for %s* - dropping frame",
overlay_render_sid_prefix(f->destination,7));
dontForward=1;
}
f->ttl--;
@ -470,7 +338,7 @@ int overlay_frame_process(int interface,overlay_frame *f)
DEBUGF("reject src is %s", overlay_render_sid(f->source));
DEBUGF("reject nexthop is %s", overlay_render_sid(f->nexthop));
DEBUGF("reject destination is %s", overlay_render_sid(f->destination));
return WHY("Not forwarding or reading duplicate broadcast");
RETURN(WHY("Not forwarding or reading duplicate broadcast"));
}
}
@ -502,23 +370,24 @@ int overlay_frame_process(int interface,overlay_frame *f)
/* If the frame was a broadcast frame, then we need to hang around
so that we can process it, since we are one of the recipients.
Otherwise, return triumphant. */
if (!broadcast) return 0;
if (!broadcast) RETURN(0);
}
}
int id = (interface - overlay_interfaces);
switch(f->type)
{
case OF_TYPE_SELFANNOUNCE:
overlay_route_saw_selfannounce(interface,f,now);
overlay_route_saw_selfannounce(f,now);
break;
case OF_TYPE_SELFANNOUNCE_ACK:
overlay_route_saw_selfannounce_ack(interface,f,now);
overlay_route_saw_selfannounce_ack(f,now);
break;
case OF_TYPE_NODEANNOUNCE:
overlay_route_saw_advertisements(interface,f,now);
overlay_route_saw_advertisements(id,f,now);
break;
case OF_TYPE_RHIZOME_ADVERT:
overlay_rhizome_saw_advertisements(interface,f,now);
overlay_rhizome_saw_advertisements(id,f,now);
break;
case OF_TYPE_DATA:
case OF_TYPE_DATA_VOICE:
@ -529,14 +398,14 @@ int overlay_frame_process(int interface,overlay_frame *f)
DEBUGF(" dst = %s\n",overlay_render_sid(f->destination));
dump("payload", f->payload->bytes, f->payload->length);
}
overlay_saw_mdp_containing_frame(interface,f,now);
overlay_saw_mdp_containing_frame(f,now);
break;
default:
DEBUGF("Unsupported f->type=0x%x",f->type);
return WHY("Support for that f->type not yet implemented");
RETURN(WHY("Support for that f->type not yet implemented"));
break;
}
return 0;
RETURN(0);
}

View File

@ -329,10 +329,10 @@ int overlay_abbreviate_address(unsigned char *in,unsigned char *out,int *ofs)
}
int overlay_abbreviate_expand_address(int interface,unsigned char *in,int *inofs,unsigned char *out,int *ofs)
int overlay_abbreviate_expand_address(unsigned char *in,int *inofs,unsigned char *out,int *ofs)
{
int bytes=0,r;
if (debug&DEBUG_OVERLAYABBREVIATIONS) fprintf(stderr,"Address first byte/abbreviation code=%02x (input offset=%d)\n",in[*inofs],*inofs);
if (debug&DEBUG_OVERLAYABBREVIATIONS) DEBUGF("Address first byte/abbreviation code=%02x (input offset=%d)\n",in[*inofs],*inofs);
switch(in[*inofs])
{
case OA_CODE_02: case OA_CODE_04: case OA_CODE_0C:
@ -345,14 +345,14 @@ int overlay_abbreviate_expand_address(int interface,unsigned char *in,int *inofs
selfannounce in this packet. Naturally it cannot be
used to encode the sender's address there ;) */
(*inofs)++;
if (debug&DEBUG_OVERLAYABBREVIATIONS) fprintf(stderr,"Resolving OA_CODE_SELF.\n");
if (debug&DEBUG_OVERLAYABBREVIATIONS) DEBUGF("Resolving OA_CODE_SELF.\n");
if (overlay_abbreviate_current_sender_set) {
bcopy(&overlay_abbreviate_current_sender.b[0],&out[*ofs],SID_SIZE);
overlay_abbreviate_set_most_recent_address(&out[*ofs]);
(*ofs)+=SID_SIZE;
return OA_RESOLVED;
} else {
if (debug&DEBUG_OVERLAYABBREVIATIONS) fprintf(stderr,"Cannot resolve OA_CODE_SELF until we can resolve sender's address.\n");
if (debug&DEBUG_OVERLAYABBREVIATIONS) DEBUGF("Cannot resolve OA_CODE_SELF until we can resolve sender's address.\n");
return OA_UNINITIALISED;
}
case OA_CODE_INDEX: /* single byte index look up */

View File

@ -55,7 +55,7 @@ int overlay_route_please_advertise(overlay_node *n)
else return 1;
}
int overlay_route_add_advertisements(int interface,overlay_buffer *e)
int overlay_route_add_advertisements(overlay_buffer *e)
{
/* Construct a route advertisement frame and append it to e.

View File

@ -42,10 +42,12 @@ struct interface_rules {
struct interface_rules *interface_filter=NULL;
struct profile_total interface_poll_stats;
struct profile_total dummy_poll_stats;
unsigned int overlay_sequence_number=0;
/* Do we need to repeat our abbreviation policy? */
int overlay_interface_repeat_abbreviation_policy[OVERLAY_MAX_INTERFACES]={1};
long long overlay_next_tick();
/* Return milliseconds since server started. First call will always return zero.
Must use long long, not time_t, as time_t can be 32bits, which is too small for
@ -188,27 +190,28 @@ overlay_interface_init_socket(int interface, struct sockaddr_in src_addr, struct
I(broadcast_address) = broadcast;
I(fileP) = 0;
I(fd) = socket(PF_INET,SOCK_DGRAM,0);
if (I(fd) < 0) {
I(alarm.poll.fd) = socket(PF_INET,SOCK_DGRAM,0);
if (I(alarm.poll.fd) < 0) {
WHY_perror("socket");
WHYF("Could not create UDP socket for interface: %s",strerror(errno));
goto error;
} else
INFOF("interface #%d fd=%d",interface, I(fd));
INFOF("interface #%d fd=%d",interface, I(alarm.poll.fd));
int reuseP = 1;
if (setsockopt(I(fd), SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) < 0) {
if (setsockopt(I(alarm.poll.fd), SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) < 0) {
WHY_perror("setsockopt(SO_REUSEADR)");
goto error;
}
#ifdef SO_REUSEPORT
if (setsockopt(I(fd), SOL_SOCKET, SO_REUSEPORT, &reuseP, sizeof(reuseP)) < 0) {
if (setsockopt(I(alarm.poll.fd), SOL_SOCKET, SO_REUSEPORT, &reuseP, sizeof(reuseP)) < 0) {
WHY_perror("setsockopt(SO_REUSEPORT)");
goto error;
}
#endif
int broadcastP = 1;
if (setsockopt(I(fd), SOL_SOCKET, SO_BROADCAST, &broadcastP, sizeof(broadcastP)) < 0) {
if (setsockopt(I(alarm.poll.fd), SOL_SOCKET, SO_BROADCAST, &broadcastP, sizeof(broadcastP)) < 0) {
WHY_perror("setsockopt");
goto error;
}
@ -216,7 +219,7 @@ overlay_interface_init_socket(int interface, struct sockaddr_in src_addr, struct
/* Automatically close socket on calls to exec().
This makes life easier when we restart with an exec after receiving
a bad signal. */
fcntl(I(fd), F_SETFL, fcntl(I(fd), F_GETFL, NULL) | O_CLOEXEC);
fcntl(I(alarm.poll.fd), F_SETFL, fcntl(I(alarm.poll.fd), F_GETFL, NULL) | O_CLOEXEC);
/* @PGS/20120615
Use the broadcast address, so that we can reliably receive broadcast
@ -225,7 +228,7 @@ overlay_interface_init_socket(int interface, struct sockaddr_in src_addr, struct
*/
broadcast.sin_family = AF_INET;
broadcast.sin_port = htons(I(port));
if (bind(I(fd), (struct sockaddr *)&broadcast, sizeof(broadcast))) {
if (bind(I(alarm.poll.fd), (struct sockaddr *)&broadcast, sizeof(broadcast))) {
WHY_perror("bind");
WHY("MP HLR server could not bind to requested UDP port (bind() failed)");
goto error;
@ -233,11 +236,18 @@ overlay_interface_init_socket(int interface, struct sockaddr_in src_addr, struct
assert(inet_ntop(AF_INET, (const void *)&broadcast.sin_addr, srctxt, INET_ADDRSTRLEN) != NULL);
if (debug & (DEBUG_PACKETRX | DEBUG_IO)) DEBUGF("Bound to %s:%d", srctxt, ntohs(broadcast.sin_port));
I(alarm.poll.events)=POLLIN;
I(alarm.function) = overlay_interface_poll;
interface_poll_stats.name="overlay_interface_poll";
I(alarm.stats)=&interface_poll_stats;
watch(&I(alarm));
return 0;
error:
close(I(fd));
I(fd)=-1;
close(I(alarm.poll.fd));
I(alarm.poll.fd)=-1;
return -1;
#undef I
}
@ -255,13 +265,12 @@ int overlay_interface_init(char *name,struct sockaddr_in src_addr,struct sockadd
/* Pick a reasonable default MTU.
This will ultimately get tuned by the bandwidth and other properties of the interface */
I(mtu)=1200;
I(observed)=1;
I(bits_per_second)=speed_in_bits;
I(port)=port;
I(type)=type;
I(last_tick_ms)=0;
I(fd)=0;
I(alarm.poll.fd)=0;
switch (type) {
case OVERLAY_INTERFACE_PACKETRADIO:
I(tick_ms) = confValueGetInt64Range("mdp.packetradio.tick_ms", 15000LL, 1LL, 3600000LL);
@ -290,14 +299,21 @@ int overlay_interface_init(char *name,struct sockaddr_in src_addr,struct sockadd
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) {
if ((I(alarm.poll.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 */
I(offset)=lseek(I(alarm.poll.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
based on closeness */
// schedule an alarm for this interface
I(alarm.function)=overlay_dummy_poll;
I(alarm.alarm)=overlay_gettime_ms()+10;
dummy_poll_stats.name="overlay_dummy_poll";
I(alarm.stats)=&dummy_poll_stats;
schedule(&I(alarm));
} else {
if (overlay_interface_init_socket(overlay_interface_count,src_addr,broadcast))
return WHY("overlay_interface_init_socket() failed");
@ -308,105 +324,93 @@ int overlay_interface_init(char *name,struct sockaddr_in src_addr,struct sockadd
return 0;
}
int overlay_rx_messages()
void overlay_interface_poll(struct sched_ent *alarm)
{
int i;
struct overlay_interface *interface = (overlay_interface *)alarm;
int plen=0;
unsigned char packet[16384];
struct sockaddr src_addr;
unsigned int addrlen=sizeof(src_addr);
/* Read only one UDP packet per call to share resources more fairly, and also
enable stats to accurately count packets received */
int recvttl=1;
plen=recvwithttl(alarm->poll.fd,packet,sizeof(packet),
&recvttl,&src_addr,&addrlen);
if (plen<1) {
return;
} else {
/* We have a frame from this interface */
if (debug&DEBUG_PACKETRX) {
serval_packetvisualise(open_logging(),"Read from real interface",
packet,plen);
}
if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("Received %d bytes on interface %s",plen,interface->name);
if (packetOk(interface,packet,plen,NULL,recvttl,&src_addr,addrlen,1)) {
WHY("Malformed packet");
serval_packetvisualise(open_logging(), "Malformed packet", packet,plen);
}
}
return;
}
void overlay_dummy_poll(struct sched_ent *alarm)
{
overlay_interface *interface = (overlay_interface *)alarm;
/* Grab packets, unpackage and dispatch frames to consumers */
/* XXX Okay, so how are we managing out-of-process consumers?
They need some way to register their interest in listening to a port.
*/
unsigned char packet[16384];
int plen=0;
int c[OVERLAY_MAX_INTERFACES];
int count=0;
/* Look at all interfaces */
for(i=0;i<overlay_interface_count;i++) { c[i]=(overlay_interfaces[i].observed>0); count+=c[i]; }
struct sockaddr src_addr;
unsigned int addrlen=sizeof(src_addr);
unsigned char transaction_id[8];
/* Grab packets from interfaces in round-robin fashion until all have been grabbed,
or until we have spent too long (maybe 10ms?) */
int now = overlay_gettime_ms();
int then = now + 10;
while(count>0)
/* Read from dummy interface file */
long long length=lseek(alarm->poll.fd,0,SEEK_END);
if (interface->offset>=length)
{
for(i=0;i<overlay_interface_count;i++)
{
struct sockaddr src_addr;
unsigned int addrlen=sizeof(src_addr);
unsigned char transaction_id[8];
overlay_last_interface_number=i;
/* Set socket non-blocking before we try to read from it */
fcntl(overlay_interfaces[i].fd, F_SETFL,
fcntl(overlay_interfaces[i].fd, F_GETFL, NULL)|O_NONBLOCK);
if (overlay_interfaces[i].fileP) {
/* Read from dummy interface file */
long long length=lseek(overlay_interfaces[i].fd, (off_t)0, SEEK_END);
if (overlay_interfaces[i].offset > length) {
if (debug&DEBUG_OVERLAYINTERFACES)
DEBUGF("Past end of input on dummy interface #%d",i);
}
else if (overlay_interfaces[i].offset < length)
{
lseek(overlay_interfaces[i].fd, overlay_interfaces[i].offset, SEEK_SET);
if (debug&DEBUG_OVERLAYINTERFACES)
DEBUGF("Reading from interface #%d log at offset %d, end of file at %lld",i,
overlay_interfaces[i].offset,length);
if (read(overlay_interfaces[i].fd,&packet[0],2048)==2048)
{
overlay_interfaces[i].offset+=2048;
plen=2048-128;
plen=packet[110]+(packet[111]<<8);
if (plen>(2048-128)) plen=-1;
if (debug&DEBUG_PACKETRX) {
serval_packetvisualise(open_logging(),
"Read from dummy interface",
&packet[128],plen);
}
bzero(&transaction_id[0],8);
bzero(&src_addr,sizeof(src_addr));
if ((plen>=0)&&(packet[0]==0x01)&&!(packet[1]|packet[2]|packet[3])) {
{ if (packetOk(i,&packet[128],plen,transaction_id,
-1 /* fake TTL */,
&src_addr,addrlen,1))
WHY("Malformed or unsupported packet from dummy interface (packetOK() failed)"); } }
else WHY("Invalid packet version in dummy interface");
}
else {
if (debug&DEBUG_IO) DEBUG("Read NOTHING from dummy interface");
c[i]=0; count--;
}
}
} else {
/* Read from UDP socket */
int recvttl=1;
plen=recvwithttl(overlay_interfaces[i].fd,packet,sizeof(packet),
&recvttl,&src_addr,&addrlen);
if (plen<0) {
c[i]=0; count--;
} else {
/* We have a frame from this interface */
if (debug&DEBUG_PACKETRX) {
serval_packetvisualise(open_logging(),"Read from real interface",
packet,plen);
}
if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("Received %d bytes on interface #%d (%s)",plen,i,overlay_interfaces[i].name);
if (packetOk(i,packet,plen,NULL,recvttl,&src_addr,addrlen,1)) {
WHY("Malformed packet");
serval_packetvisualise(open_logging(),"Malformed packet", packet,plen);
}
}
}
}
/* Don't sit here forever, or else we will never send any packets */
if (overlay_gettime_ms()>then) break;
if (debug&DEBUG_OVERLAYINTERFACES)
DEBUGF("At end of input on dummy interface %s", interface->name);
}
else
{
lseek(alarm->poll.fd,interface->offset,SEEK_SET);
if (debug&DEBUG_OVERLAYINTERFACES)
DEBUGF("Reading from interface %s log at offset %d, end of file at %lld",interface->name,
interface->offset,length);
if (read(alarm->poll.fd,&packet[0],2048)==2048)
{
interface->offset+=2048;
plen=2048-128;
plen=packet[110]+(packet[111]<<8);
if (plen>(2048-128)) plen=-1;
if (debug&DEBUG_PACKETRX) {
serval_packetvisualise(open_logging(),
"Read from dummy interface",
&packet[128],plen);
}
bzero(&transaction_id[0],8);
bzero(&src_addr,sizeof(src_addr));
if ((plen>=0)&&(packet[0]==0x01)&&!(packet[1]|packet[2]|packet[3])) {
{ if (packetOk(interface,&packet[128],plen,transaction_id,
-1 /* fake TTL */,
&src_addr,addrlen,1))
WHY("Malformed or unsupported packet from dummy interface (packetOK() failed)"); } }
else WHY("Invalid packet version in dummy interface");
}
else {
if (debug&DEBUG_IO) DEBUG("Read NOTHING from dummy interface");
}
}
alarm->alarm = overlay_gettime_ms()+10;
schedule(alarm);
return 0;
return ;
}
int overlay_tx_messages()
@ -488,7 +492,7 @@ int overlay_broadcast_ensemble(int interface_number,
bzero(&buf[128+len],2048-(128+len));
bcopy(bytes,&buf[128],len);
if (write(overlay_interfaces[interface_number].fd,buf,2048)!=2048)
if (write(overlay_interfaces[interface_number].alarm.poll.fd,buf,2048)!=2048)
{
WHY_perror("write");
return WHY("write() failed");
@ -498,7 +502,8 @@ int overlay_broadcast_ensemble(int interface_number,
}
else
{
if(sendto(overlay_interfaces[interface_number].fd, bytes, len, 0, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) != len)
if(sendto(overlay_interfaces[interface_number].alarm.poll.fd,
bytes, len, 0, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) != len)
{
/* Failed to send */
WHY_perror("sendto(c)");
@ -572,8 +577,9 @@ overlay_interface_register(char *name,
overlay_interfaces[i].broadcast_address.sin_addr.s_addr,
local.sin_addr.s_addr,
broadcast.sin_addr.s_addr);
close(overlay_interfaces[i].fd);
overlay_interfaces[i].fd = -1;
unwatch(&overlay_interfaces[i].alarm);
close(overlay_interfaces[i].alarm.poll.fd);
overlay_interfaces[i].alarm.poll.fd = -1;
if (overlay_interface_init_socket(i, local, broadcast))
INFOF("Could not reinitialise changed interface %s", name);
}
@ -589,25 +595,11 @@ overlay_interface_register(char *name,
return 0;
}
static time_t overlay_last_interface_discover_time = 0;
int
overlay_interface_discover(void) {
void overlay_interface_discover(struct sched_ent *alarm){
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;
if ((now - overlay_last_interface_discover_time) < 2)
return 0;
overlay_last_interface_discover_time = now;
/* Mark all interfaces as not observed, so that we know if we need to cull any */
for(i = 0; i < overlay_interface_count; i++)
overlay_interfaces[i].observed = 0;
@ -625,7 +617,7 @@ overlay_interface_discover(void) {
/* We already know about this interface, so just update it */
overlay_interfaces[i].observed = 1;
else {
/* New interface, so register it */
/* New interface, so register it */
if (overlay_interface_init(r->namespec,dummyaddr,dummyaddr,
1000000,PORT_DNA,OVERLAY_INTERFACE_WIFI)) {
if (debug & DEBUG_OVERLAYINTERFACES) DEBUGF("Could not initialise newly seen interface %s", r->namespec);
@ -657,7 +649,9 @@ overlay_interface_discover(void) {
FATAL("Unable to get any interface information");
}
return 0;
alarm->alarm = overlay_gettime_ms()+5000;
schedule(alarm);
return;
}
int overlay_stuff_packet_from_queue(int i,overlay_buffer *e,int q,long long now,overlay_frame *pax[],int *frame_pax,int frame_max_pax)
@ -812,15 +806,13 @@ int overlay_tick_interface(int i, long long now)
#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;
}
if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("Ticking interface #%d",i);
/* 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. */
@ -850,7 +842,6 @@ 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
@ -859,30 +850,23 @@ TIMING_CHECK();
#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);
overlay_route_add_advertisements(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)
@ -934,8 +918,11 @@ TIMING_CHECK();
{
if ((*p)->dequeue) {
{
if (0) DEBUGF("dequeuing %p%s NOW",
*p,(*p)->isBroadcast?" (broadcast)":" (unicast)");
if (debug&DEBUG_QUEUES)
DEBUGF("dequeuing %s* -> %s* NOW (queue length=%d)",
overlay_render_sid_prefix((*p)->source,7),
overlay_render_sid_prefix((*p)->destination,7),
overlay_tx[q].length);
t=*p;
*p=t->next;
if (overlay_tx[q].last==t) overlay_tx[q].last=t->prev;
@ -968,70 +955,69 @@ TIMING_CHECK();
if (e) ob_free(e); e=NULL;
return WHY("overlay_broadcast_ensemble() failed");
}
TIMING_CHECK();
}
int
overlay_check_ticks(void) {
void overlay_check_ticks(struct sched_ent *alarm) {
/* 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) DEBUGF("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) DEBUGF("Interface %s ticks every %dms, last at %lld.",
overlay_interfaces[i].name,
overlay_interfaces[i].tick_ms,
overlay_interfaces[i].last_tick_ms);
overlay_interfaces[i].last_tick_ms);
if (now >= overlay_interfaces[i].last_tick_ms + overlay_interfaces[i].tick_ms) {
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) DEBUGF("Interface %s is awol.", overlay_interfaces[i].name);
TIMING_CHECK();
}
return 0;
/* Update interval until next tick */
alarm->alarm = overlay_next_tick();
schedule(alarm);
return;
}
long long overlay_time_until_next_tick()
long long overlay_next_tick()
{
/* By default only tick once per day */
long long nexttick=86400*1000;
long long now=overlay_gettime_ms();
long long nexttick=86400*1000;
int i;
if (debug&DEBUG_VERBOSE_IO) DEBUGF("Tick-check on %d interfaces at %lldms",overlay_interface_count,now);
for(i=0;i<overlay_interface_count;i++)
if (overlay_interfaces[i].observed>0)
{
if (debug&DEBUG_VERBOSE_IO) DEBUGF("Interface %s ticks every %dms, last at T-%lldms",overlay_interfaces[i].name,
overlay_interfaces[i].tick_ms,now-overlay_interfaces[i].last_tick_ms);
long long thistick=
overlay_interfaces[i].tick_ms
-(now-overlay_interfaces[i].last_tick_ms);
if (0)
DEBUGF("Interface %s ticks every %dms, last at T-%lldms, next needed in %lldms",
overlay_interfaces[i].name,
overlay_interfaces[i].tick_ms,now-overlay_interfaces[i].last_tick_ms,
thistick);
long long thistick=(overlay_interfaces[i].last_tick_ms+overlay_interfaces[i].tick_ms)-now;
if (thistick<0) thistick=0;
if (thistick<nexttick) nexttick=thistick;
if (0) WHYF("nexttick is now %lldms",nexttick);
}
return nexttick;
if (0) WHYF("Next tick required in %lldms",nexttick);
return now + nexttick;
}
long long parse_quantity(char *q)

View File

@ -19,8 +19,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include <sys/stat.h>
int mdp_abstract_socket=-1;
int mdp_named_socket=-1;
struct sched_ent mdp_abstract;
struct sched_ent mdp_named;
struct profile_total mdp_stats;
int overlay_mdp_setup_sockets()
{
struct sockaddr_un name;
@ -31,9 +33,9 @@ int overlay_mdp_setup_sockets()
#ifndef HAVE_LINUX_IF_H
/* Abstrack name space (i.e., non-file represented) unix domain sockets are a
linux-only thing. */
mdp_abstract_socket = -1;
mdp_abstract.poll.fd = -1;
#else
if (mdp_abstract_socket==-1) {
if (mdp_abstract.function==NULL) {
/* Abstract name space unix sockets is a special Linux thing, which is
convenient for us because Android is Linux, but does not have a shared
writable path that is on a UFS partition, so we cannot use traditional
@ -46,17 +48,17 @@ int overlay_mdp_setup_sockets()
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);
if (mdp_abstract_socket>-1) {
mdp_abstract.poll.fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (mdp_abstract.poll.fd>-1) {
int dud=0;
int reuseP=1;
if(setsockopt( mdp_abstract_socket, SOL_SOCKET, SO_REUSEADDR,
if(setsockopt( mdp_abstract.poll.fd, SOL_SOCKET, SO_REUSEADDR,
&reuseP, sizeof(reuseP)) < 0)
{
WARN_perror("setsockopt");
WARN("Could not indicate reuse addresses. Not necessarily a problem (yet)");
}
int r=bind(mdp_abstract_socket, (struct sockaddr *)&name, len);
int r=bind(mdp_abstract.poll.fd, (struct sockaddr *)&name, len);
if (r) {
WARN_perror("bind");
dud=1;
@ -64,46 +66,57 @@ int overlay_mdp_setup_sockets()
WARN("bind() of abstract name space socket failed (not an error on non-linux systems");
}
if (dud) {
close(mdp_abstract_socket);
mdp_abstract_socket=-1;
close(mdp_abstract.poll.fd);
mdp_abstract.poll.fd=-1;
WHY("Could not open abstract name-space socket (only a problem on Linux).");
}
int send_buffer_size=64*1024;
int res = setsockopt(mdp_abstract_socket, SOL_SOCKET, SO_SNDBUF,
int res = setsockopt(mdp_abstract.poll.fd, SOL_SOCKET, SO_SNDBUF,
&send_buffer_size, sizeof(send_buffer_size));
mdp_abstract.function = overlay_mdp_poll;
mdp_abstract.stats.name = "overlay_mdp_poll";
mdp_abstract.poll.events = POLLIN;
watch(&mdp_abstract);
}
}
#endif
if (mdp_named_socket==-1) {
if (mdp_named.function==NULL) {
if (!form_serval_instance_path(&name.sun_path[0], 100, "mdp.socket")) {
return WHY("Cannot construct name of unix domain socket.");
}
unlink(&name.sun_path[0]);
len = 0+strlen(&name.sun_path[0]) + sizeof(name.sun_family)+1;
mdp_named_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
if (mdp_named_socket>-1) {
mdp_named.poll.fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (mdp_named.poll.fd>-1) {
int dud=0;
int reuseP=1;
if(setsockopt( mdp_named_socket, SOL_SOCKET, SO_REUSEADDR,
if(setsockopt( mdp_named.poll.fd, SOL_SOCKET, SO_REUSEADDR,
&reuseP, sizeof(reuseP)) < 0)
{
WARN_perror("setsockopt");
WARN("Could not indicate reuse addresses. Not necessarily a problem (yet)");
}
int r=bind(mdp_named_socket, (struct sockaddr *)&name, len);
int r=bind(mdp_named.poll.fd, (struct sockaddr *)&name, len);
if (r) { dud=1; r=0; WHY("bind() of named unix domain socket failed"); }
if (dud) {
close(mdp_named_socket);
mdp_named_socket=-1;
close(mdp_named.poll.fd);
mdp_named.poll.fd=-1;
WHY("Could not open named unix domain socket.");
}
int send_buffer_size=64*1024;
int res = setsockopt(mdp_named_socket, SOL_SOCKET, SO_RCVBUF,
int res = setsockopt(mdp_named.poll.fd, SOL_SOCKET, SO_RCVBUF,
&send_buffer_size, sizeof(send_buffer_size));
if (res)
WHY_perror("setsockopt");
mdp_named.function = overlay_mdp_poll;
mdp_stats.name="overlay_mdp_poll";
mdp_named.stats = &mdp_stats;
mdp_named.poll.events = POLLIN;
watch(&mdp_named);
}
}
@ -111,38 +124,6 @@ int overlay_mdp_setup_sockets()
}
int overlay_mdp_get_fds(struct pollfd *fds,int *fdcount,int fdmax)
{
/* Make sure sockets are open */
overlay_mdp_setup_sockets();
if ((*fdcount)>=fdmax) return -1;
if (mdp_abstract_socket>-1)
{
if (debug&DEBUG_IO) {
fprintf(stderr,"MDP abstract name space socket is poll() slot #%d (fd %d)\n",
*fdcount,mdp_abstract_socket);
}
fds[*fdcount].fd=mdp_abstract_socket;
fds[*fdcount].events=POLLIN;
(*fdcount)++;
}
if ((*fdcount)>=fdmax) return -1;
if (mdp_named_socket>-1)
{
if (debug&DEBUG_IO) {
fprintf(stderr,"MDP named unix domain socket is poll() slot #%d (fd %d)\n",
*fdcount,mdp_named_socket);
}
fds[*fdcount].fd=mdp_named_socket;
fds[*fdcount].events=POLLIN;
(*fdcount)++;
}
return 0;
}
#define MDP_MAX_BINDINGS 100
#define MDP_MAX_SOCKET_NAME_LEN 110
int mdp_bindings_initialised=0;
@ -302,58 +283,49 @@ int overlay_mdp_process_bind_request(int sock,overlay_mdp_frame *mdp,
return overlay_mdp_reply_ok(sock,recvaddr,recvaddrlen,"Port bound");
}
int overlay_saw_mdp_containing_frame(int interface,overlay_frame *f,long long now)
unsigned char *overlay_mdp_decrypt(overlay_frame *f,overlay_mdp_frame *mdp,
int *len)
{
/* Take frame source and destination and use them to populate mdp->in->{src,dst}
SIDs.
Take ports from mdp frame itself.
Take payload from mdp frame itself.
*/
overlay_mdp_frame mdp;
IN();
/* Get source and destination addresses */
bcopy(&f->destination[0],&mdp.in.dst.sid[0],SID_SIZE);
bcopy(&f->source[0],&mdp.in.src.sid[0],SID_SIZE);
int len=f->payload->length;
*len=f->payload->length;
unsigned char *b = NULL;
unsigned char plain_block[len+16];
unsigned char plain_block[(*len)+16];
if (len<10) return WHY("Invalid MDP frame");
/* copy crypto flags from frame so that we know if we need to decrypt or verify it */
switch(f->modifiers&OF_CRYPTO_BITS) {
case 0:
/* get payload */
b=&f->payload->bytes[0];
len=f->payload->length;
mdp.packetTypeAndFlags|=MDP_NOCRYPT|MDP_NOSIGN; break;
*len=f->payload->length;
mdp->packetTypeAndFlags|=MDP_NOCRYPT|MDP_NOSIGN; break;
case OF_CRYPTO_CIPHERED:
return WHY("decryption not implemented");
mdp.packetTypeAndFlags|=MDP_NOSIGN; break;
WHY("decryption not implemented");
RETURN(NULL);
mdp->packetTypeAndFlags|=MDP_NOSIGN; break;
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. */
unsigned char *key=keyring_find_sas_public(keyring,mdp.out.src.sid);
if (!key) return WHY("SAS key not currently on record, so cannot verify");
unsigned char *key=keyring_find_sas_public(keyring,mdp->out.src.sid);
if (!key) { WHY("SAS key not currently on record, so cannot verify");
RETURN(NULL); }
/* get payload and following compacted signature */
b=&f->payload->bytes[0];
len=f->payload->length-crypto_sign_edwards25519sha512batch_BYTES;
*len=f->payload->length-crypto_sign_edwards25519sha512batch_BYTES;
/* get hash */
unsigned char hash[crypto_hash_sha512_BYTES];
crypto_hash_sha512(hash,b,len);
crypto_hash_sha512(hash,b,*len);
/* reconstitute signature by putting hash between two halves of signature */
unsigned char signature[crypto_hash_sha512_BYTES
+crypto_sign_edwards25519sha512batch_BYTES];
bcopy(&b[len],&signature[0],32);
crypto_hash_sha512(&signature[32],b,len);
bcopy(&b[*len],&signature[0],32);
crypto_hash_sha512(&signature[32],b,*len);
if (0) dump("hash for verification",hash,crypto_hash_sha512_BYTES);
bcopy(&b[len+32],&signature[32+crypto_hash_sha512_BYTES],32);
bcopy(&b[(*len)+32],&signature[32+crypto_hash_sha512_BYTES],32);
/* verify signature */
unsigned char m[crypto_hash_sha512_BYTES];
@ -362,24 +334,27 @@ int overlay_saw_mdp_containing_frame(int interface,overlay_frame *f,long long no
=crypto_sign_edwards25519sha512batch_open(m,&mlen,
signature,sizeof(signature),
key);
if (result) return WHY("Signature verification failed: incorrect signature");
else if (0) DEBUG("signature check passed");
if (result) {
WHY("Signature verification failed: incorrect signature");
RETURN(NULL);
} else if (0) DEBUG("signature check passed");
}
mdp.packetTypeAndFlags|=MDP_NOCRYPT; break;
mdp->packetTypeAndFlags|=MDP_NOCRYPT; break;
case OF_CRYPTO_CIPHERED|OF_CRYPTO_SIGNED:
{
if (0) {
fflush(stderr);
printf("crypted MDP frame for %s\n",
overlay_render_sid(mdp.out.dst.sid));
overlay_render_sid(mdp->out.dst.sid));
fflush(stdout);
}
unsigned char *k=keyring_get_nm_bytes(&mdp.out.dst,&mdp.out.src);
unsigned char *k=keyring_get_nm_bytes(&mdp->out.dst,&mdp->out.src);
unsigned char *nonce=&f->payload->bytes[0];
int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES;
int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
if (!k) return WHY("I don't have the private key required to decrypt that");
if (!k) { WHY("I don't have the private key required to decrypt that");
RETURN(NULL); }
bzero(&plain_block[0],crypto_box_curve25519xsalsa20poly1305_ZEROBYTES-16);
int cipher_len=f->payload->length-nb;
bcopy(&f->payload->bytes[nb],&plain_block[16],cipher_len);
@ -389,17 +364,42 @@ int overlay_saw_mdp_containing_frame(int interface,overlay_frame *f,long long no
dump("cipher block",&plain_block[16],cipher_len);
}
if (crypto_box_curve25519xsalsa20poly1305_open_afternm
(plain_block,plain_block,cipher_len+16,nonce,k))
return WHYF("crypto_box_open_afternm() failed (forged or corrupted packet of %d bytes)",cipher_len+16);
(plain_block,plain_block,cipher_len+16,nonce,k)) {
WHYF("crypto_box_open_afternm() failed (forged or corrupted packet of %d bytes)",cipher_len+16);
RETURN(NULL);
}
if (0) dump("plain block",&plain_block[zb],cipher_len-16);
b=&plain_block[zb];
len=cipher_len-16;
*len=cipher_len-16;
break;
}
}
RETURN(b);
}
int overlay_saw_mdp_containing_frame(overlay_frame *f,long long now)
{
IN();
/* Take frame source and destination and use them to populate mdp->in->{src,dst}
SIDs.
Take ports from mdp frame itself.
Take payload from mdp frame itself.
*/
overlay_mdp_frame mdp;
int len=f->payload->length;
/* Get source and destination addresses */
bcopy(&f->destination[0],&mdp.in.dst.sid[0],SID_SIZE);
bcopy(&f->source[0],&mdp.in.src.sid[0],SID_SIZE);
if (len<10) RETURN(WHY("Invalid MDP frame"));
/* copy crypto flags from frame so that we know if we need to decrypt or verify it */
unsigned char *b = overlay_mdp_decrypt(f,&mdp,&len);
if (!b) RETURN(-1);
int version=(b[0]<<8)+b[1];
if (version!=0x0101) return WHY("Saw unsupported MDP frame version");
if (version!=0x0101) RETURN(WHY("Saw unsupported MDP frame version"));
/* Indicate MDP message type */
mdp.packetTypeAndFlags=MDP_TX;
@ -414,7 +414,7 @@ int overlay_saw_mdp_containing_frame(int interface,overlay_frame *f,long long no
bcopy(&b[10],&mdp.in.payload[0],mdp.in.payload_length);
/* and do something with it! */
return overlay_saw_mdp_frame(interface,&mdp,now);
RETURN(overlay_saw_mdp_frame(&mdp,now));
}
int overlay_mdp_swap_src_dst(overlay_mdp_frame *mdp)
@ -426,8 +426,9 @@ int overlay_mdp_swap_src_dst(overlay_mdp_frame *mdp)
return 0;
}
int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
int overlay_saw_mdp_frame(overlay_mdp_frame *mdp,long long now)
{
IN();
int i;
int match=-1;
@ -438,10 +439,17 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
send back a connection refused type message? Silence is probably the
more prudent path.
*/
if (0)
WHYF("Received packet with listener (MDP ports: src=%s*:%d, dst=%d)",
overlay_render_sid_prefix(mdp->out.src.sid,7),
mdp->out.src.port,mdp->out.dst.port);
if ((!overlay_address_is_local(mdp->out.dst.sid))
&&(!overlay_address_is_broadcast(mdp->out.dst.sid)))
{
return WHY("Asked to process an MDP packet that was not addressed to this node.");
RETURN(WHY("Asked to process an MDP packet that was not addressed to this node."));
}
for(i=0;i<MDP_MAX_BINDINGS;i++)
@ -477,32 +485,33 @@ 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;
errno=0;
int len=overlay_mdp_relevant_bytes(mdp);
int r=sendto(mdp_named_socket,mdp,len,0,(struct sockaddr*)&addr,sizeof(addr));
int r=sendto(mdp_named.poll.fd,mdp,len,0,(struct sockaddr*)&addr,sizeof(addr));
if (r==overlay_mdp_relevant_bytes(mdp)) {
return 0;
RETURN(0);
}
WHY("didn't send mdp packet");
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");
RETURN(WHY("Failed to pass received MDP frame to client"));
} else {
/* No socket is bound, ignore the packet ... except for magic sockets */
switch(mdp->out.dst.port) {
case MDP_PORT_VOMP:
return vomp_mdp_received(mdp);
RETURN(vomp_mdp_received(mdp));
case MDP_PORT_KEYMAPREQUEST:
/* Either respond with the appropriate SAS, or record this one if it
verfies out okay. */
DEBUG("key mapping request");
return keyring_mapping_request(keyring,mdp);
RETURN(keyring_mapping_request(keyring,mdp));
case MDP_PORT_DNALOOKUP: /* attempt to resolve DID to SID */
{
int cn=0,in=0,kp=0;
@ -510,8 +519,8 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
int pll=mdp->out.payload_length;
if (pll>64) pll=64;
/* get did from the packet */
if (mdp->out.payload_length<1)
return WHY("Empty DID in DNA resolution request");
if (mdp->out.payload_length<1) {
RETURN(WHY("Empty DID in DNA resolution request")); }
bcopy(&mdp->out.payload[0],&did[0],pll);
/* make sure it is null terminated */
did[pll]=0;
@ -575,7 +584,8 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
*/
dna_helper_enqueue(did,mdp->out.src.sid);
}
return 0;
RETURN(0);
DEBUG("Got here");
}
break;
case MDP_PORT_ECHO: /* well known ECHO port for TCP/UDP and now MDP */
@ -586,7 +596,9 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
/* Swap addresses */
overlay_mdp_swap_src_dst(mdp);
if (mdp->out.dst.port==MDP_PORT_ECHO) return WHY("echo loop averted");
if (mdp->out.dst.port==MDP_PORT_ECHO) {
RETURN(WHY("echo loop averted"));
}
/* If the packet was sent to broadcast, then replace broadcast address
with our local address. For now just responds with first local address */
if (overlay_address_is_broadcast(mdp->out.src.sid))
@ -611,23 +623,23 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
and the frame needs sending on, as happens with broadcasts. MDP ping
is a simple application where this occurs). */
overlay_mdp_swap_src_dst(mdp);
}
break;
default:
/* Unbound socket. We won't be sending ICMP style connection refused
messages, partly because they are a waste of bandwidth. */
return WHYF("Received packet for which no listening process exists (MDP ports: src=%d, dst=%d",
mdp->out.src.port,mdp->out.dst.port);
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;
default:
return WHYF("We should only see MDP_TX frames here (MDP message type = 0x%x)",
mdp->packetTypeAndFlags);
RETURN(WHYF("We should only see MDP_TX frames here (MDP message type = 0x%x)",
mdp->packetTypeAndFlags));
}
return WHY("Not implemented");
RETURN(0);
}
int overlay_mdp_sanitytest_sourceaddr(sockaddr_mdp *src,int userGeneratedFrameP,
@ -704,29 +716,29 @@ int overlay_mdp_sanitytest_sourceaddr(sockaddr_mdp *src,int userGeneratedFrameP,
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
struct sockaddr_un *recvaddr,int recvaddrlen)
{
IN();
/* Work out if destination is broadcast or not */
int broadcast=1;
if (overlay_mdp_sanitytest_sourceaddr(&mdp->out.src,userGeneratedFrameP,
recvaddr,recvaddrlen))
return overlay_mdp_reply_error
(mdp_named_socket,
(struct sockaddr_un *)recvaddr,
recvaddrlen,8,
"Source address is invalid (you must bind to a source address before"
" you can send packets");
RETURN(overlay_mdp_reply_error
(mdp_named.poll.fd,
(struct sockaddr_un *)recvaddr,
recvaddrlen,8,
"Source address is invalid (you must bind to a source address before"
" you can send packets"));
if (!overlay_address_is_broadcast(mdp->out.dst.sid)) broadcast=0;
if (overlay_address_is_local(mdp->out.dst.sid)||broadcast)
{
/* Packet is addressed such that we should process it. */
overlay_saw_mdp_frame(-1 /* not received on a network interface */,
mdp,overlay_gettime_ms());
overlay_saw_mdp_frame(mdp,overlay_gettime_ms());
if (!broadcast) {
/* Is local, and is not broadcast, so shouldn't get sent out
on the wire. */
return 0;
RETURN(0);
}
}
@ -735,14 +747,14 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
NaCl cryptobox keys can be used for signing. */
if (broadcast) {
if (!(mdp->packetTypeAndFlags&MDP_NOCRYPT))
return overlay_mdp_reply_error(mdp_named_socket,
RETURN(overlay_mdp_reply_error(mdp_named.poll.fd,
recvaddr,recvaddrlen,5,
"Broadcast packets cannot be encrypted "); }
"Broadcast packets cannot be encrypted ")); }
/* Prepare the overlay frame for dispatch */
struct overlay_frame *frame;
frame=calloc(sizeof(overlay_frame),1);
if (!frame) return WHY_perror("calloc");
if (!frame) RETURN(WHY_perror("calloc"));
/* give voice packets priority */
if (mdp->out.dst.port==MDP_PORT_VOMP) frame->type=OF_TYPE_DATA_VOICE;
else frame->type=OF_TYPE_DATA;
@ -771,7 +783,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
unsigned char nonce[crypto_box_curve25519xsalsa20poly1305_NONCEBYTES];
if (urandombytes(nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES)) {
op_free(frame);
return WHY("urandombytes() failed to generate nonce");
RETURN(WHY("urandombytes() failed to generate nonce"));
}
fe|= ob_append_bytes(frame->payload,nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES);
/* generate plain message with zero bytes and get ready to cipher it */
@ -799,16 +811,16 @@ 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,&mdp->out.dst);
if (!k) { op_free(frame); return WHY("could not compute Curve25519(NxM)"); }
if (!k) { op_free(frame); RETURN(WHY("could not compute Curve25519(NxM)")); }
/* Get pointer to place in frame where the ciphered text needs to go */
int cipher_offset=frame->payload->length;
unsigned char *cipher_text=ob_append_space(frame->payload,cipher_len);
if (fe||(!cipher_text))
{ op_free(frame); return WHY("could not make space for ciphered text"); }
{ op_free(frame); RETURN(WHY("could not make space for ciphered text")); }
/* Actually authcrypt the payload */
if (crypto_box_curve25519xsalsa20poly1305_afternm
(cipher_text,plain,cipher_len,nonce,k))
{ op_free(frame); return WHY("crypto_box_afternm() failed"); }
{ op_free(frame); RETURN(WHY("crypto_box_afternm() failed")); }
/* now shuffle down 16 bytes to get rid of the temporary space that crypto_box
uses. */
bcopy(&cipher_text[16],&cipher_text[0],cipher_len-16);
@ -833,7 +845,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
*/
frame->modifiers=OF_CRYPTO_CIPHERED;
op_free(frame);
return WHY("ciphered MDP packets not implemented");
RETURN(WHY("ciphered MDP packets not implemented"));
break;
case MDP_NOCRYPT:
/* Payload is sent unencrypted, but signed.
@ -856,7 +868,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
+mdp->out.payload_length);
{
unsigned char *key=keyring_find_sas_private(keyring,mdp->out.src.sid,NULL);
if (!key) { op_free(frame); return WHY("could not find signing key"); }
if (!key) { op_free(frame); RETURN(WHY("could not find signing key")); }
/* Build plain-text that includes header and hash it so that
we can sign that hash. */
@ -886,7 +898,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
crypto_sign_edwards25519sha512batch(signature,&sig_len,
hash,crypto_hash_sha512_BYTES,
key);
if (!sig_len) { op_free(frame); return WHY("Signing MDP frame failed"); }
if (!sig_len) { op_free(frame); RETURN(WHY("Signing MDP frame failed")); }
/* chop hash out of middle of signature since it has to be recomputed
at the far end, anyway, as described above. */
bcopy(&signature[32+64],&signature[32],32);
@ -940,15 +952,15 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
if (overlay_payload_enqueue(q,frame,0))
{
if (frame) op_free(frame);
return WHY("Error enqueuing frame");
RETURN(WHY("Error enqueuing frame"));
}
else {
if (debug&DEBUG_OVERLAYINTERFACES) DEBUG("queued frame");
return 0;
RETURN(0);
}
}
int overlay_mdp_poll()
void overlay_mdp_poll(struct sched_ent *alarm)
{
unsigned char buffer[16384];
int ttl;
@ -957,116 +969,115 @@ int overlay_mdp_poll()
socklen_t recvaddrlen=sizeof(recvaddrbuffer);
struct sockaddr_un *recvaddr_un=NULL;
if (mdp_named_socket>-1) {
ttl=-1;
bzero((void *)recvaddrbuffer,sizeof(recvaddrbuffer));
fcntl(mdp_named_socket, F_SETFL,
fcntl(mdp_named_socket, F_GETFL, NULL)|O_NONBLOCK);
int len = recvwithttl(mdp_named_socket,buffer,sizeof(buffer),&ttl,
recvaddr,&recvaddrlen);
recvaddr_un=(struct sockaddr_un *)recvaddr;
ttl=-1;
bzero((void *)recvaddrbuffer,sizeof(recvaddrbuffer));
int len = recvwithttl(alarm->poll.fd,buffer,sizeof(buffer),&ttl,
recvaddr,&recvaddrlen);
recvaddr_un=(struct sockaddr_un *)recvaddr;
if (len>0) {
/* Look at overlay_mdp_frame we have received */
overlay_mdp_frame *mdp=(overlay_mdp_frame *)&buffer[0];
if (len>0) {
/* Look at overlay_mdp_frame we have received */
overlay_mdp_frame *mdp=(overlay_mdp_frame *)&buffer[0];
switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK) {
case MDP_GOODBYE:
return overlay_mdp_releasebindings(recvaddr_un,recvaddrlen);
case MDP_VOMPEVENT:
return vomp_mdp_event(mdp,recvaddr_un,recvaddrlen);
case MDP_NODEINFO:
return overlay_route_node_info(mdp,recvaddr_un,recvaddrlen);
case MDP_GETADDRS:
{
overlay_mdp_frame mdpreply;
/* Work out which SIDs to get ... */
int sid_num=mdp->addrlist.first_sid;
int max_sid=mdp->addrlist.last_sid;
int max_sids=mdp->addrlist.frame_sid_count;
/* ... and constrain list for sanity */
if (sid_num<0) sid_num=0;
if (max_sids>MDP_MAX_SID_REQUEST) max_sids=MDP_MAX_SID_REQUEST;
if (max_sids<0) max_sids=0;
/* Prepare reply packet */
mdpreply.packetTypeAndFlags=MDP_ADDRLIST;
mdpreply.addrlist.first_sid=sid_num;
mdpreply.addrlist.last_sid=max_sid;
mdpreply.addrlist.frame_sid_count=max_sids;
/* Populate with SIDs */
int i=0;
int count=0;
if (mdp->addrlist.selfP) {
/* from self */
int cn=0,in=0,kp=0;
while(keyring_next_identity(keyring,&cn,&in,&kp)) {
if (count>=sid_num&&(i<max_sids))
bcopy(keyring->contexts[cn]->identities[in]
->keypairs[kp]->public_key,
mdpreply.addrlist.sids[i++],SID_SIZE);
in++; kp=0;
count++;
if (i>=max_sids) break;
}
} else {
/* from peer list */
int bin,slot;
i=0;
count=0;
for(bin=0;bin<overlay_bin_count;bin++)
for(slot=0;slot<overlay_bin_size;slot++)
{
if ((!overlay_nodes[bin][slot].sid[0])
||(overlay_nodes[bin][slot].best_link_score<1))
{
continue; }
if ((count>=sid_num)&&(i<max_sids)) {
bcopy(overlay_nodes[bin][slot].sid,
mdpreply.addrlist.sids[i++],SID_SIZE);
}
count++;
}
switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK) {
case MDP_GOODBYE:
overlay_mdp_releasebindings(recvaddr_un,recvaddrlen);
return;
case MDP_VOMPEVENT:
vomp_mdp_event(mdp,recvaddr_un,recvaddrlen);
return;
case MDP_NODEINFO:
overlay_route_node_info(mdp,recvaddr_un,recvaddrlen);
return;
case MDP_GETADDRS:
{
overlay_mdp_frame mdpreply;
/* Work out which SIDs to get ... */
int sid_num=mdp->addrlist.first_sid;
int max_sid=mdp->addrlist.last_sid;
int max_sids=mdp->addrlist.frame_sid_count;
/* ... and constrain list for sanity */
if (sid_num<0) sid_num=0;
if (max_sids>MDP_MAX_SID_REQUEST) max_sids=MDP_MAX_SID_REQUEST;
if (max_sids<0) max_sids=0;
/* Prepare reply packet */
mdpreply.packetTypeAndFlags=MDP_ADDRLIST;
mdpreply.addrlist.first_sid=sid_num;
mdpreply.addrlist.last_sid=max_sid;
mdpreply.addrlist.frame_sid_count=max_sids;
/* Populate with SIDs */
int i=0;
int count=0;
if (mdp->addrlist.selfP) {
/* from self */
int cn=0,in=0,kp=0;
while(keyring_next_identity(keyring,&cn,&in,&kp)) {
if (count>=sid_num&&(i<max_sids))
bcopy(keyring->contexts[cn]->identities[in]
->keypairs[kp]->public_key,
mdpreply.addrlist.sids[i++],SID_SIZE);
in++; kp=0;
count++;
if (i>=max_sids) break;
}
mdpreply.addrlist.frame_sid_count=i;
mdpreply.addrlist.last_sid=sid_num+i-1;
mdpreply.addrlist.server_sid_count=count;
/* Send back to caller */
return overlay_mdp_reply(mdp_named_socket,
(struct sockaddr_un *)recvaddr,recvaddrlen,
&mdpreply);
} else {
/* from peer list */
int bin,slot;
i=0;
count=0;
for(bin=0;bin<overlay_bin_count;bin++)
for(slot=0;slot<overlay_bin_size;slot++)
{
if ((!overlay_nodes[bin][slot].sid[0])
||(overlay_nodes[bin][slot].best_link_score<1))
{
continue; }
if ((count>=sid_num)&&(i<max_sids)) {
bcopy(overlay_nodes[bin][slot].sid,
mdpreply.addrlist.sids[i++],SID_SIZE);
}
count++;
}
}
break;
case MDP_TX: /* Send payload (and don't treat it as system privileged) */
return overlay_mdp_dispatch(mdp,1,(struct sockaddr_un*)recvaddr,recvaddrlen);
break;
case MDP_BIND: /* Bind to port */
return overlay_mdp_process_bind_request(mdp_named_socket,mdp,
recvaddr_un,recvaddrlen);
break;
default:
/* Client is not allowed to send any other frame type */
WHY("Illegal frame type.");
mdp->packetTypeAndFlags=MDP_ERROR;
mdp->error.error=2;
snprintf(mdp->error.message,128,"Illegal request type. Clients may use only MDP_TX or MDP_BIND.");
int len=4+4+strlen(mdp->error.message)+1;
errno=0;
/* We ignore the result of the following, because it is just sending an
error message back to the client. If this fails, where would we report
the error to? My point exactly. */
sendto(mdp_named_socket,mdp,len,0,(struct sockaddr *)recvaddr,recvaddrlen);
mdpreply.addrlist.frame_sid_count=i;
mdpreply.addrlist.last_sid=sid_num+i-1;
mdpreply.addrlist.server_sid_count=count;
/* Send back to caller */
overlay_mdp_reply(alarm->poll.fd,
(struct sockaddr_un *)recvaddr,recvaddrlen,
&mdpreply);
return;
}
break;
case MDP_TX: /* Send payload (and don't treat it as system privileged) */
overlay_mdp_dispatch(mdp,1,(struct sockaddr_un*)recvaddr,recvaddrlen);
return;
break;
case MDP_BIND: /* Bind to port */
overlay_mdp_process_bind_request(alarm->poll.fd,mdp,
recvaddr_un,recvaddrlen);
return;
break;
default:
/* Client is not allowed to send any other frame type */
WHY("Illegal frame type.");
mdp->packetTypeAndFlags=MDP_ERROR;
mdp->error.error=2;
snprintf(mdp->error.message,128,"Illegal request type. Clients may use only MDP_TX or MDP_BIND.");
int len=4+4+strlen(mdp->error.message)+1;
errno=0;
/* We ignore the result of the following, because it is just sending an
error message back to the client. If this fails, where would we report
the error to? My point exactly. */
sendto(alarm->poll.fd,mdp,len,0,(struct sockaddr *)recvaddr,recvaddrlen);
}
fcntl(mdp_named_socket, F_SETFL,
fcntl(mdp_named_socket, F_GETFL, NULL)&(~O_NONBLOCK));
}
return 0;
return;
}
int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp)
@ -1133,10 +1144,10 @@ int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms)
if (!FORM_SERVAL_INSTANCE_PATH(name.sun_path, "mdp.socket"))
return -1;
fcntl(mdp_client_socket, F_SETFL,
fcntl(mdp_client_socket, F_GETFL, NULL)|O_NONBLOCK);
SET_NONBLOCKING(mdp_client_socket);
int result=sendto(mdp_client_socket, mdp, len, 0,
(struct sockaddr *)&name, sizeof(struct sockaddr_un));
SET_BLOCKING(mdp_client_socket);
if (result<0) {
mdp->packetTypeAndFlags=MDP_ERROR;
mdp->error.error=1;
@ -1148,12 +1159,7 @@ int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms)
}
}
/* Wait for a reply until timeout */
struct pollfd fds[1];
int fdcount=1;
fds[0].fd=mdp_client_socket; fds[0].events=POLLIN;
result = poll(fds,fdcount,timeout_ms);
if (result==0) {
if (overlay_mdp_client_poll(timeout_ms)<=0){
/* Timeout */
mdp->packetTypeAndFlags=MDP_ERROR;
mdp->error.error=1;
@ -1161,7 +1167,6 @@ int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms)
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 */
@ -1267,17 +1272,21 @@ int overlay_mdp_client_poll(long long timeout_ms)
int overlay_mdp_recv(overlay_mdp_frame *mdp,int *ttl)
{
char mdp_socket_name[101];
if (!FORM_SERVAL_INSTANCE_PATH(mdp_socket_name, "mdp.socket"))
return WHY("Could not find mdp socket");
/* Check if reply available */
fcntl(mdp_client_socket, F_SETFL, fcntl(mdp_client_socket, F_GETFL, NULL)|O_NONBLOCK);
unsigned char recvaddrbuffer[1024];
struct sockaddr *recvaddr=(struct sockaddr *)recvaddrbuffer;
unsigned int recvaddrlen=sizeof(recvaddrbuffer);
struct sockaddr_un *recvaddr_un;
if (!FORM_SERVAL_INSTANCE_PATH(mdp_socket_name, "mdp.socket"))
return WHY("Could not find mdp socket");
mdp->packetTypeAndFlags=0;
/* Check if reply available */
SET_NONBLOCKING(mdp_client_socket);
int len = recvwithttl(mdp_client_socket,(unsigned char *)mdp,
sizeof(overlay_mdp_frame),ttl,recvaddr,&recvaddrlen);
SET_BLOCKING(mdp_client_socket);
recvaddr_un=(struct sockaddr_un *)recvaddr;
/* Null terminate received address so that the stat() call below can succeed */
if (recvaddrlen<1024) recvaddrbuffer[recvaddrlen]=0;

View File

@ -26,7 +26,7 @@ struct sockaddr_in loopback = {
.sin_addr.s_addr=0x0100007f
};
int packetOkOverlay(int interface,unsigned char *packet,int len,
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet,int len,
unsigned char *transaction_id,int recvttl,
struct sockaddr *recvaddr,int recvaddrlen,int parseP)
{
@ -106,7 +106,7 @@ int packetOkOverlay(int interface,unsigned char *packet,int len,
if (recvaddr->sa_family==AF_INET)
f.recvaddr=recvaddr;
else {
if (overlay_interfaces[interface].fileP) {
if (interface->fileP) {
/* dummy interface, so tell to use 0.0.0.0 */
f.recvaddr=(struct sockaddr *)&loopback;
} else
@ -177,7 +177,7 @@ int packetOkOverlay(int interface,unsigned char *packet,int len,
/* Now extract the next hop address */
int alen=0;
int offset=ofs;
f.nexthop_address_status=overlay_abbreviate_expand_address(interface,packet,&offset,f.nexthop,&alen);
f.nexthop_address_status=overlay_abbreviate_expand_address(packet,&offset,f.nexthop,&alen);
if (debug&DEBUG_PACKETFORMATS) {
if (f.nexthop_address_status==OA_RESOLVED)
DEBUGF("next hop address is %s", overlay_render_sid(f.nexthop));
@ -196,27 +196,32 @@ int packetOkOverlay(int interface,unsigned char *packet,int len,
}
/* Finally process the frame */
long long now=overlay_gettime_ms();
overlay_frame_process(interface,&f);
long long elapsed=overlay_gettime_ms()-now;
if (0) INFOF("overlay_frame_process (type=%d, len=%d) took %lldms",
f.type,f.bytecount,elapsed);
/* Skip the rest of the bytes in this frame so that we can examine the next one in this
ensemble */
if (debug&DEBUG_PACKETFORMATS) DEBUGF("next ofs=%d, f.rfs=%d, len=%d", ofs, f.rfs, len);
ofs+=f.rfs;
}
if (0) INFOF("Finished processing overlay packet");
return 0;
}
int overlay_frame_resolve_addresses(int interface,overlay_frame *f)
int overlay_frame_resolve_addresses(overlay_frame *f)
{
/* Get destination and source addresses and set pointers to payload appropriately */
int alen=0;
int offset=0;
overlay_abbreviate_set_most_recent_address(f->nexthop);
f->destination_address_status=overlay_abbreviate_expand_address(interface,f->bytes,&offset,f->destination,&alen);
f->destination_address_status=overlay_abbreviate_expand_address(f->bytes,&offset,f->destination,&alen);
alen=0;
f->source_address_status=overlay_abbreviate_expand_address(interface,f->bytes,&offset,f->source,&alen);
f->source_address_status=overlay_abbreviate_expand_address(f->bytes,&offset,f->source,&alen);
if (debug&DEBUG_OVERLAYABBREVIATIONS)
DEBUGF("Wrote %d bytes into source address: %s", alen, alloca_tohex(f->source, alen));
@ -307,14 +312,14 @@ int overlay_add_selfannouncement(int interface,overlay_buffer *b)
*/
if (send_prefix) {
if (ob_append_byte(b, OA_CODE_PREFIX7)) return WHY("Could not add address format code.");
if (ob_append_bytes(b,sid,7)) return WHY("Could not append SID prefix to self-announcement");
if (ob_append_bytes(b,sid,7)) return WHY("Could not append SID prefix to self-announcement");
}
else {
if (ob_append_bytes(b,sid,SID_SIZE)) return WHY("Could not append SID to self-announcement");
if (ob_append_bytes(b,sid,SID_SIZE)) return WHY("Could not append SID to self-announcement");
}
/* Make note that this is the most recent address we have set */
overlay_abbreviate_set_most_recent_address(sid);
/* Sequence number range. Based on one tick per milli-second. */
overlay_update_sequence_number();
if (ob_append_int(b,overlay_interfaces[interface].last_tick_ms))

View File

@ -244,6 +244,10 @@ int overlay_payload_enqueue(int q,overlay_frame *p,int forceBroadcastP)
Complain if there are too many frames in the queue.
*/
if (0)
WHYF("Enqueuing packet for %s* (q[%d]length = %d)",
overlay_render_sid_prefix(p->destination,7),
q,overlay_tx[q].length);
if (q==OQ_ISOCHRONOUS_VOICE&&(!forceBroadcastP)) {
/* Dispatch voice data immediately.
Also tell Rhizome to back off a bit, so that voice traffic
@ -253,7 +257,7 @@ int overlay_payload_enqueue(int q,overlay_frame *p,int forceBroadcastP)
int broadcast=overlay_address_is_broadcast(p->destination);
rhizome_saw_voice_traffic();
overlay_abbreviate_clear_most_recent_address();
if (broadcast) {
@ -311,7 +315,8 @@ int overlay_payload_enqueue(int q,overlay_frame *p,int forceBroadcastP)
if (0) dump_payload(p,"queued for delivery");
if (overlay_tx[q].length>=overlay_tx[q].maxLength) return WHY("Queue congested");
if (overlay_tx[q].length>=overlay_tx[q].maxLength)
return WHYF("Queue #%d congested (size = %d)",q,overlay_tx[q].maxLength);
if (0) dump_queue("before",q);

View File

@ -694,7 +694,7 @@ overlay_neighbour *overlay_route_get_neighbour_structure(unsigned char *packed_s
int overlay_route_i_can_hear_node(unsigned char *who,int sender_interface,
unsigned int s1,unsigned int s2,
int receiver_interface,long long now)
long long now)
{
if (0) WHYF("I can hear node %s (but I really only care who can hear me)",
overlay_render_sid(who));
@ -789,7 +789,7 @@ int overlay_print_address(FILE *f,char *prefix,unsigned char *s,char *suffix)
}
int overlay_route_saw_selfannounce(int interface,overlay_frame *f,long long now)
int overlay_route_saw_selfannounce(overlay_frame *f,long long now)
{
if (overlay_address_is_local(f->source)) return 0;
@ -818,7 +818,7 @@ int overlay_route_saw_selfannounce(int interface,overlay_frame *f,long long now)
dump("Payload",&f->payload->bytes[0],f->payload->length);
}
overlay_route_i_can_hear_node(f->source,sender_interface,s1,s2,interface,now);
overlay_route_i_can_hear_node(f->source,sender_interface,s1,s2,now);
/* Ignore self-announcements from ourself. */
if (overlay_address_is_local(&f->source[0]))
@ -1059,7 +1059,7 @@ char *overlay_render_sid_prefix(unsigned char *sid,int l)
These link scores should get stored in our node list as compared to our neighbour list,
with the node itself listed as the nexthop that the score is associated with.
*/
int overlay_route_saw_selfannounce_ack(int interface,overlay_frame *f,long long now)
int overlay_route_saw_selfannounce_ack(overlay_frame *f,long long now)
{
if (0) WHYF("processing selfannounce ack (payload length=%d)",f->payload->length);
if (!overlay_neighbours) {
@ -1259,14 +1259,14 @@ int overlay_route_tick_next_neighbour_id=0;
int overlay_route_tick_neighbour_bundle_size=1;
int overlay_route_tick_next_node_bin_id=0;
int overlay_route_tick_node_bundle_size=1;
int overlay_route_tick()
void overlay_route_tick(struct sched_ent *alarm)
{
int n;
long long start_time=overlay_gettime_ms();
if (debug&DEBUG_OVERLAYROUTING)
fprintf(stderr,"Neighbours: %d@%d, Nodes: %d@%d\n",
DEBUGF("Neighbours: %d@%d, Nodes: %d@%d\n",
overlay_route_tick_neighbour_bundle_size,overlay_route_tick_next_neighbour_id,
overlay_route_tick_node_bundle_size,overlay_route_tick_next_node_bin_id);
@ -1326,7 +1326,11 @@ int overlay_route_tick()
int interval=5000/ticks;
if (debug&DEBUG_OVERLAYROUTING) fprintf(stderr,"route tick interval = %dms (%d ticks per 5sec, neigh=%lldms, node=%lldms)\n",interval,ticks,neighbour_time,node_time);
return interval;
/* Update callback interval based on how much work we have to do */
alarm->alarm = overlay_gettime_ms()+interval;
schedule(alarm);
return;
}
/* Ticking neighbours is easy; we just pretend we have heard from them again,
@ -1498,7 +1502,5 @@ int overlay_route_node_info(overlay_mdp_frame *mdp,
}
}
return overlay_mdp_reply(mdp_named_socket,addr,addrlen,mdp);
return 0;
return overlay_mdp_reply(mdp_named.poll.fd,addr,addrlen,mdp);
}

View File

@ -59,7 +59,7 @@ int process_packet(unsigned char *packet,int len,
return 0;
}
int packetOk(int interface,unsigned char *packet,int len,
int packetOk(struct overlay_interface *interface, unsigned char *packet,int len,
unsigned char *transaction_id,int ttl,
struct sockaddr *recvaddr,int recvaddrlen,int parseP)
{
@ -72,7 +72,7 @@ int packetOk(int interface,unsigned char *packet,int len,
if (packet[0]==0x4F&&packet[1]==0x10)
{
if (interface>-1)
if (interface!=NULL)
{
return packetOkOverlay(interface,packet,len,transaction_id,ttl,
recvaddr,recvaddrlen,parseP);

208
performance_timing.c Normal file
View File

@ -0,0 +1,208 @@
/*
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"
struct profile_total *stats_head=NULL;
struct call_stats *current_call=NULL;
void fd_clearstat(struct profile_total *s){
s->max_time = 0;
s->total_time = 0;
s->calls = 0;
}
void fd_update_stats(struct profile_total *s,long long elapsed)
{
s->total_time+=elapsed;
if (elapsed>s->max_time) s->max_time=elapsed;
s->calls++;
}
int fd_tallystats(struct profile_total *total,struct profile_total *a)
{
total->total_time+=a->total_time;
total->calls+=a->calls;
if (a->max_time>total->max_time) total->max_time=a->max_time;
return 0;
}
int fd_showstat(struct profile_total *total, struct profile_total *a)
{
INFOF("%lldms (%2.1f%%) in %d calls (max %lldms, avg %.1fms) : %s",
a->total_time,a->total_time*100.0/total->total_time,
a->calls,
a->max_time,a->total_time*1.00/a->calls,
a->name);
return 0;
}
// sort the list of call times
struct profile_total *sort(struct profile_total *list){
struct profile_total *first = list;
// the left hand list will contain all items that took longer than the first item
struct profile_total *left_head = NULL;
struct profile_total *left_tail = NULL;
// the right hand list will contain all items that took less time than the first item
struct profile_total *right_head = NULL;
struct profile_total *right_tail = NULL;
// most of the cpu time is likely to be the same offenders
// don't sort a list that's already sorted
int left_already_sorted = 1;
int right_already_sorted = 1;
if (!list)
return NULL;
list = list->_next;
first->_next = NULL;
// split the list into two sub-lists based on the time of the first entry
while(list){
if (list->total_time > first->total_time){
if (left_tail){
left_tail->_next = list;
if (list->total_time > left_tail->total_time)
left_already_sorted = 0;
}else
left_head=list;
left_tail=list;
}else{
if (right_tail){
right_tail->_next = list;
if (list->total_time > right_tail->total_time)
right_already_sorted = 0;
}else
right_head=list;
right_tail=list;
}
list = list->_next;
}
// sort the left sub-list
if (left_tail){
left_tail->_next=NULL;
if (!left_already_sorted){
left_head = sort(left_head);
// find the tail again
left_tail = left_head;
while(left_tail->_next)
left_tail = left_tail->_next;
}
// add the first item after the left list
left_tail->_next = first;
}else
left_head = first;
left_tail = first;
// sort the right sub-list
if (right_tail){
right_tail->_next=NULL;
if (!right_already_sorted)
right_head = sort(right_head);
left_tail->_next = right_head;
}
return left_head;
}
int fd_clearstats()
{
struct profile_total *stats = stats_head;
while(stats!=NULL){
fd_clearstat(stats);
stats = stats->_next;
}
return 0;
}
int fd_showstats()
{
struct profile_total total={NULL, 0, "Total", 0,0,0};
stats_head = sort(stats_head);
struct profile_total *stats = stats_head;
while(stats!=NULL){
/* Get total time spent doing everything */
fd_tallystats(&total,stats);
stats = stats->_next;
}
INFOF("servald time usage stats:");
stats = stats_head;
while(stats!=NULL){
/* Get total time spent doing everything */
if (stats->calls)
fd_showstat(&total,stats);
stats = stats->_next;
}
fd_showstat(&total,&total);
return 0;
}
void fd_periodicstats(struct sched_ent *alarm)
{
fd_showstats();
fd_clearstats();
alarm->alarm = overlay_gettime_ms()+3000;
schedule(alarm);
}
int fd_func_enter(struct call_stats *this_call)
{
this_call->enter_time=overlay_gettime_ms();
this_call->child_time=0;
this_call->prev = current_call;
current_call = this_call;
return 0;
}
int fd_func_exit(struct call_stats *this_call, struct profile_total *aggregate_stats)
{
if (current_call != this_call)
WHYF("stack mismatch, exited through %s()",aggregate_stats->name);
long long now = overlay_gettime_ms();
long long elapsed=now - this_call->enter_time;
current_call = this_call->prev;
if (!aggregate_stats->_initialised){
aggregate_stats->_initialised=1;
aggregate_stats->_next = stats_head;
fd_clearstat(aggregate_stats);
stats_head = aggregate_stats;
}
if (current_call)
current_call->child_time+=elapsed;
fd_update_stats(aggregate_stats, (elapsed - this_call->child_time));
return 0;
}

View File

@ -38,58 +38,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
extern long long rhizome_voice_timeout;
typedef struct rhizome_http_request {
int socket;
long long last_activity; /* time of last activity in ms */
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;
char *blob_table;
char *blob_column;
unsigned long long blob_rowid;
/* source_index used for offset in blob */
unsigned long long blob_end;
} rhizome_http_request;
#define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32
#define RHIZOME_PRIORITY_HIGHEST RHIZOME_PRIORITY_SERVAL_CORE
#define RHIZOME_PRIORITY_SERVAL_CORE 5
#define RHIZOME_PRIORITY_SUBSCRIBED 4
@ -98,6 +46,8 @@ typedef struct rhizome_http_request {
#define RHIZOME_PRIORITY_SERVAL_BULK 1
#define RHIZOME_PRIORITY_NOTINTERESTED 0
#define RHIZOME_IDLE_TIMEOUT 10000
typedef struct rhizome_signature {
unsigned char signature[crypto_sign_edwards25519sha512batch_BYTES
+crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES+1];
@ -243,11 +193,6 @@ int rhizome_add_manifest(rhizome_manifest *m_in,int ttl);
void rhizome_bytes_to_hex_upper(unsigned const char *in, char *out, int byteCount);
int rhizome_find_privatekey(rhizome_manifest *m);
rhizome_signature *rhizome_sign_hash(rhizome_manifest *m, const unsigned char *authorSid);
int rhizome_server_free_http_request(rhizome_http_request *r);
int rhizome_server_close_http_request(int i);
int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r);
int rhizome_server_parse_http_request(int rn,rhizome_http_request *r);
int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char *response);
int sqlite_prepare(sqlite3_stmt **statement, const strbuf stmt);
int sqlite_prepare_loglevel(int log_level, sqlite3_stmt **statement, const strbuf stmt);
int sqlite_exec_void(const char *sqlformat,...);
@ -255,9 +200,6 @@ int sqlite_exec_void_loglevel(int log_level, const char *sqlformat, ...);
int sqlite_exec_void_strbuf_loglevel(int log_level, const strbuf stmt);
int sqlite_exec_int64(long long *result, const char *sqlformat,...);
int sqlite_exec_strbuf(strbuf sb, const char *sqlformat,...);
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
char *mime_type,unsigned long long bytes);
int rhizome_server_sql_query_fill_buffer(int rn,rhizome_http_request *r);
double rhizome_manifest_get_double(rhizome_manifest *m,char *var,double default_value);
int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs);
int rhizome_update_file_priority(const char *fileid);
@ -298,4 +240,4 @@ int rhizome_ignore_manifest_check(rhizome_manifest *m,
int rhizome_suggest_queue_manifest_import(rhizome_manifest *m,
struct sockaddr_in *peerip);
int rhizome_enqueue_suggestions();

View File

@ -42,6 +42,7 @@ int rhizome_manifest_verify(rhizome_manifest *m)
}
if (m->sig_count==0) {
WHYF("Manifest has zero valid signatures");
m->errors++;
}

View File

@ -87,21 +87,22 @@ int rhizome_bk_xor(const unsigned char *authorSid, // binary
unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES],
unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES])
{
IN();
if (crypto_sign_edwards25519sha512batch_SECRETKEYBYTES > crypto_hash_sha512_BYTES)
return WHY("BK needs to be longer than it can be");
{ RETURN(WHY("BK needs to be longer than it can be")); }
int cn=0,in=0,kp=0;
if (!keyring_find_sid(keyring,&cn,&in,&kp,authorSid)) {
if (debug & DEBUG_RHIZOME) DEBUG("identity not in keyring");
return 1;
{ RETURN(1); }
}
kp = keyring_identity_find_keytype(keyring, cn, in, KEYTYPE_RHIZOME);
if (kp == -1) {
if (debug & DEBUG_RHIZOME) DEBUG("identity has no Rhizome Secret");
return 2;
RETURN(2);
}
int rs_len=keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key_len;
if (rs_len<16||rs_len>1024)
return WHYF("invalid Rhizome Secret: length=%d", rs_len);
{ RETURN(WHYF("invalid Rhizome Secret: length=%d", rs_len)); }
unsigned char *rs=keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key;
int combined_len=rs_len+crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES;
unsigned char buffer[combined_len];
@ -114,7 +115,7 @@ int rhizome_bk_xor(const unsigned char *authorSid, // binary
bkout[i]=bkin[i]^hash[i];
bzero(&buffer[0],combined_len);
bzero(&hash[0],crypto_hash_sha512_BYTES);
return 0;
RETURN(0);
}
/* See if the manifest has a BK entry, and if so, use it to obtain the
@ -131,18 +132,19 @@ int rhizome_bk_xor(const unsigned char *authorSid, // binary
*/
int rhizome_extract_privatekey(rhizome_manifest *m, const unsigned char *authorSid)
{
IN();
char *bk = rhizome_manifest_get(m, "BK", NULL, 0);
if (!bk) return WHY("missing BK field");
if (!bk) { RETURN(WHY("missing BK field")); }
unsigned char bkBytes[RHIZOME_BUNDLE_KEY_BYTES];
if (fromhexstr(bkBytes, bk, RHIZOME_BUNDLE_KEY_BYTES) == -1)
return WHYF("invalid BK field: %s", bk);
{ RETURN(WHYF("invalid BK field: %s", bk)); }
switch (rhizome_bk_xor(authorSid, m->cryptoSignPublic, bkBytes, m->cryptoSignSecret)) {
case -1:
return WHY("rhizome_bk_xor() failed");
RETURN(WHY("rhizome_bk_xor() failed"));
case 0:
return rhizome_verify_bundle_privatekey(m);
RETURN(rhizome_verify_bundle_privatekey(m));
}
return WHYF("Rhizome secret for %s not found. (Have you unlocked the identity?)", alloca_tohex_sid(authorSid));
RETURN(WHYF("Rhizome secret for %s not found. (Have you unlocked the identity?)", alloca_tohex_sid(authorSid)));
}
/*
@ -155,14 +157,15 @@ int rhizome_extract_privatekey(rhizome_manifest *m, const unsigned char *authorS
*/
int rhizome_is_self_signed(rhizome_manifest *m)
{
IN();
char *bk = rhizome_manifest_get(m, "BK", NULL, 0);
if (!bk) {
if (debug & DEBUG_RHIZOME) DEBUGF("missing BK field");
return 1;
RETURN(1);
}
unsigned char bkBytes[RHIZOME_BUNDLE_KEY_BYTES];
if (fromhexstr(bkBytes, bk, RHIZOME_BUNDLE_KEY_BYTES) == -1)
return WHYF("invalid BK field: %s", bk);
{ RETURN(WHYF("invalid BK field: %s", bk)); }
int cn = 0, in = 0, kp = 0;
for (; keyring_next_identity(keyring, &cn, &in, &kp); ++kp) {
const unsigned char *authorSid = keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key;
@ -171,15 +174,15 @@ int rhizome_is_self_signed(rhizome_manifest *m)
if (rkp != -1) {
switch (rhizome_bk_xor(authorSid, m->cryptoSignPublic, bkBytes, m->cryptoSignSecret)) {
case -1:
return WHY("rhizome_bk_xor() failed");
RETURN(WHY("rhizome_bk_xor() failed"));
case 0:
if (rhizome_verify_bundle_privatekey(m) == 0)
return 0; // bingo
RETURN(0); // bingo
break;
}
}
}
return 2; // not self signed
RETURN(2); // not self signed
}
/* Verify the validity of the manifest's sccret key.
@ -189,6 +192,7 @@ int rhizome_is_self_signed(rhizome_manifest *m)
*/
int rhizome_verify_bundle_privatekey(rhizome_manifest *m)
{
IN();
#ifdef HAVE_CRYPTO_SIGN_NACL_GE25519_H
# include "crypto_sign_edwards25519sha512batch_ref/ge25519.h"
#else
@ -207,31 +211,32 @@ int rhizome_verify_bundle_privatekey(rhizome_manifest *m)
bzero(&scsk,sizeof(scsk));
if (memcmp(pk, m->cryptoSignPublic, crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES) == 0) {
m->haveSecret = 1;
return 0; // valid
RETURN(0); // valid
}
m->haveSecret = 0;
if (debug & DEBUG_RHIZOME) {
DEBUGF(" stored public key = %s*", alloca_tohex(m->cryptoSignPublic, 8));
DEBUGF("computed public key = %s*", alloca_tohex(pk, 8));
}
return 1; // invalid
RETURN(1); // invalid
#else //!ge25519
/* XXX Need to test key by signing and testing signature validity. */
/* For the time being barf so that the caller does not think we have a validated BK
when in fact we do not. */
m->haveSecret=0;
return WHY("ge25519 function not available");
RETURN(WHY("ge25519 function not available"));
#endif //!ge25519
}
rhizome_signature *rhizome_sign_hash(rhizome_manifest *m, const unsigned char *authorSid)
{
IN();
unsigned char *hash=m->manifesthash;
unsigned char *publicKeyBytes=m->cryptoSignPublic;
if (!m->haveSecret && rhizome_extract_privatekey(m, authorSid)) {
WHY("Cannot find secret key to sign manifest data.");
return NULL;
RETURN(NULL);
}
/* Signature is formed by running crypto_sign_edwards25519sha512batch() on the
@ -245,7 +250,7 @@ rhizome_signature *rhizome_sign_hash(rhizome_manifest *m, const unsigned char *a
&hash[0],mLen,m->cryptoSignSecret);
if (r) {
WHY("crypto_sign() failed.");
return NULL;
RETURN(NULL);
}
rhizome_signature *out=calloc(sizeof(rhizome_signature),1);
@ -261,33 +266,100 @@ rhizome_signature *rhizome_sign_hash(rhizome_manifest *m, const unsigned char *a
out->signature[0]=out->signatureLength;
return out;
RETURN(out);
}
typedef struct manifest_signature_block_cache {
unsigned char manifest_hash[crypto_hash_sha512_BYTES];
unsigned char signature_bytes[256];
int signature_length;
int signature_valid;
} manifest_signature_block_cache;
#define SIG_CACHE_SIZE 1024
manifest_signature_block_cache sig_cache[SIG_CACHE_SIZE];
int rhizome_manifest_lookup_signature_validity(unsigned char *hash,unsigned char *sig,int sig_len)
{
IN();
unsigned int slot=0;
int i;
for(i=0;i<crypto_hash_sha512_BYTES;i++) {
slot=(slot<<1)+(slot&0x80000000?1:0);
slot+=hash[i];
}
for(i=0;i<sig_len;i++) {
slot=(slot<<1)+(slot&0x80000000?1:0);
slot+=sig[i];
}
slot%=SIG_CACHE_SIZE;
int replace=0;
if (sig_cache[slot].signature_length!=sig_len) replace=1;
for(i=0;i<crypto_hash_sha512_BYTES;i++)
if (hash[i]!=sig_cache[i].manifest_hash[i]) { replace=1; break; }
for(i=0;i<sig_len;i++)
if (sig[i]!=sig_cache[i].signature_bytes[i]) { replace=1; break; }
if (replace) {
for(i=0;i<crypto_hash_sha512_BYTES;i++)
sig_cache[i].manifest_hash[i]=hash[i];
for(i=0;i<sig_len;i++)
sig_cache[i].signature_bytes[i]=sig[i];
sig_cache[i].signature_length=sig_len;
unsigned char sigBuf[256];
unsigned char verifyBuf[256];
unsigned char publicKey[256];
/* Reconstitute signature by putting manifest hash between the two
32-byte halves */
bcopy(&sig[0],&sigBuf[0],32);
bcopy(hash,&sigBuf[32],crypto_hash_sha512_BYTES);
bcopy(&sig[32],&sigBuf[96],32);
/* Get public key of signatory */
bcopy(&sig[64],&publicKey[0],crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES);
unsigned long long mlen=0;
sig_cache[i].signature_valid=
crypto_sign_edwards25519sha512batch_open(verifyBuf,&mlen,&sigBuf[0],128,
publicKey)
? -1 : 0;
}
RETURN(sig_cache[i].signature_valid);
}
int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs)
{
unsigned char sigBuf[256];
unsigned char verifyBuf[256];
unsigned char publicKey[256];
if (!m) return WHY("NULL pointer passed in as manifest");
IN();
if (!m) { RETURN(WHY("NULL pointer passed in as manifest")); }
if ((*ofs)>=m->manifest_all_bytes) return 0;
if ((*ofs)>=m->manifest_all_bytes) { RETURN(0); }
int len=m->manifestdata[*ofs];
if (!len) {
(*ofs)=m->manifest_bytes;
m->errors++;
return WHY("Zero byte signature blocks are not allowed, assuming signature section corrupt.");
RETURN(WHY("Zero byte signature blocks are not allowed, assuming signature section corrupt."));
}
/* Each signature type is required to have a different length to detect it.
At present only crypto_sign_edwards25519sha512batch() signatures are
supported. */
int r;
if (m->sig_count<MAX_MANIFEST_VARS)
switch(len)
{
case 0x61: /* crypto_sign_edwards25519sha512batch() */
/* Reconstitute signature block */
r=rhizome_manifest_lookup_signature_validity
(m->manifesthash,&m->manifestdata[(*ofs)+1],96);
#ifdef DEPRECATED
unsigned char sigBuf[256];
unsigned char verifyBuf[256];
unsigned char publicKey[256];
bcopy(&m->manifestdata[(*ofs)+1],&sigBuf[0],32);
bcopy(&m->manifesthash[0],&sigBuf[32],crypto_hash_sha512_BYTES);
bcopy(&m->manifestdata[(*ofs)+1+32],&sigBuf[96],32);
@ -298,10 +370,11 @@ int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs)
int r=crypto_sign_edwards25519sha512batch_open(verifyBuf,&mlen,&sigBuf[0],128,
publicKey);
fflush(stdout); fflush(stderr);
#endif
if (r) {
(*ofs)+=len;
m->errors++;
return WHY("Error in signature block (verification failed).");
RETURN(WHY("Error in signature block (verification failed)."));
} else {
/* Signature block passes, so add to list of signatures */
m->signatureTypes[m->sig_count]=len;
@ -309,9 +382,9 @@ int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs)
=malloc(crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES);
if(!m->signatories[m->sig_count]) {
(*ofs)+=len;
return WHY("malloc() failed when reading signature block");
RETURN(WHY("malloc() failed when reading signature block"));
}
bcopy(&publicKey[0],m->signatories[m->sig_count],
bcopy(&m->manifestdata[(*ofs)+1+64],m->signatories[m->sig_count],
crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES);
m->sig_count++;
if (debug&DEBUG_RHIZOME) DEBUG("Signature passed.");
@ -320,7 +393,7 @@ int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs)
default:
(*ofs)+=len;
m->errors++;
return WHY("Encountered illegal or malformed signature block");
RETURN(WHY("Encountered illegal or malformed signature block"));
}
else
{
@ -330,5 +403,5 @@ int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs)
}
(*ofs)+=len;
return 0;
RETURN(0);
}

View File

@ -130,14 +130,19 @@ int rhizome_opendb()
{
if (rhizome_db) return 0;
if (create_rhizome_datastore_dir() == -1)
return WHY("No Directory");
IN();
if (create_rhizome_datastore_dir() == -1){
RETURN(WHY("No Directory"));
}
char dbpath[1024];
if (!FORM_RHIZOME_DATASTORE_PATH(dbpath, "rhizome.db"))
return WHY("Invalid path");
if (!FORM_RHIZOME_DATASTORE_PATH(dbpath, "rhizome.db")){
RETURN(WHY("Invalid path"));
}
if (sqlite3_open(dbpath,&rhizome_db))
return WHYF("SQLite could not open database %s: %s", dbpath, sqlite3_errmsg(rhizome_db));
if (sqlite3_open(dbpath,&rhizome_db)){
RETURN(WHYF("SQLite could not open database %s: %s", dbpath, sqlite3_errmsg(rhizome_db)));
}
int loglevel = (debug & DEBUG_RHIZOME) ? LOG_LEVEL_DEBUG : LOG_LEVEL_SILENT;
/* Read Rhizome configuration */
@ -156,7 +161,7 @@ int rhizome_opendb()
|| 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");
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.
@ -168,7 +173,7 @@ int rhizome_opendb()
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 NOT EXISTS( SELECT 1 FROM FILES WHERE MANIFESTS.filehash = FILES.id);");
return 0;
RETURN(0);
}
/*

View File

@ -26,27 +26,29 @@ extern int sigIoFlag;
typedef struct rhizome_file_fetch_record {
int socket; /* if non-zero this is the socket to read from */
struct sched_ent alarm;
rhizome_manifest *manifest;
char fileid[RHIZOME_FILEHASH_STRLEN + 1];
FILE *file;
int close;
char request[1024];
int request_len;
int request_ofs;
int file_len;
int file_ofs;
long long file_len;
long long file_ofs;
int state;
int last_action;
#define RHIZOME_FETCH_SENDINGHTTPREQUEST 1
#define RHIZOME_FETCH_RXHTTPHEADERS 2
#define RHIZOME_FETCH_RXFILE 3
#define RHIZOME_FETCH_CONNECTING 1
#define RHIZOME_FETCH_SENDINGHTTPREQUEST 2
#define RHIZOME_FETCH_RXHTTPHEADERS 3
#define RHIZOME_FETCH_RXFILE 4
} rhizome_file_fetch_record;
struct profile_total fetch_stats;
/* List of queued transfers */
#define MAX_QUEUED_FILES 4
int rhizome_file_fetch_queue_count=0;
@ -150,8 +152,10 @@ int rhizome_manifest_version_cache_lookup(rhizome_manifest *m)
long long dbVersion = -1;
if (sqlite_exec_int64(&dbVersion, "SELECT version FROM MANIFESTS WHERE id='%s';", id) == -1)
return WHY("Select failure");
if (dbVersion >= m->version)
return WHYF("We already have %s (%lld vs %lld)", id, dbVersion, m->version);
if (dbVersion >= m->version) {
if (0) WHYF("We already have %s (%lld vs %lld)", id, dbVersion, m->version);
return -1;
}
return 0;
/* Work out bin number in cache */
@ -377,9 +381,11 @@ int rhizome_position_candidate(int position)
return 0;
}
/* Verifies manifests as late as possible to avoid wasting time. */
int rhizome_suggest_queue_manifest_import(rhizome_manifest *m,
struct sockaddr_in *peerip)
{
IN();
/* must free manifest when done with it */
char *id=rhizome_manifest_get(m,"id",NULL,0);
long long filesize=rhizome_manifest_get_ll(m,"filesize");
@ -399,7 +405,7 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m,
DEBUG("We already have that manifest or newer.");
}
rhizome_manifest_free(m);
return -1;
RETURN(-1);
} else {
if (1||debug&DEBUG_RHIZOMESYNC) {
long long stored_version;
@ -411,7 +417,6 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m,
}
}
/* work out where to put it in the list */
for(i=0;i<candidate_count;i++)
{
@ -430,14 +435,22 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m,
/* this version is older than the one in the list,
so don't list this one */
rhizome_manifest_free(m);
return 0;
RETURN(0);
} else {
/* replace listed version with this newer version */
if (rhizome_manifest_verify(m)) {
WHY("Error verifying manifest when considering queuing for import");
/* Don't waste time looking at this manifest again for a while */
rhizome_queue_ignore_manifest(m,peerip,60000);
rhizome_manifest_free(m);
RETURN(-1);
}
rhizome_manifest_free(candidates[i].manifest);
candidates[i].manifest=m;
/* update position in list */
rhizome_position_candidate(i);
return 0;
RETURN(0);
}
}
@ -452,8 +465,17 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m,
if (i>=MAX_CANDIDATES) {
/* our list is already full of higher-priority items */
rhizome_manifest_free(m);
return -1;
RETURN(-1);
}
if (rhizome_manifest_verify(m)) {
WHY("Error verifying manifest when considering queuing for import");
/* Don't waste time looking at this manifest again for a while */
rhizome_queue_ignore_manifest(m,peerip,60000);
rhizome_manifest_free(m);
RETURN(-1);
}
if (candidate_count==MAX_CANDIDATES) {
/* release manifest structure for whoever we are bumping from the list */
rhizome_manifest_free(candidates[MAX_CANDIDATES-1].manifest);
@ -482,10 +504,10 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m,
candidates[j].size,candidates[j].priority);
}
return 0;
RETURN(0);
}
int rhizome_enqueue_suggestions()
void rhizome_enqueue_suggestions(struct sched_ent *alarm)
{
int i;
for(i=0;i<candidate_count;i++)
@ -507,8 +529,9 @@ int rhizome_enqueue_suggestions()
bcopy(&candidates[i],&candidates[0],bytes);
candidate_count-=i;
}
return 0;
alarm->alarm = overlay_gettime_ms() + 3000;
schedule(alarm);
return;
}
int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peerip, int *manifest_kept)
@ -613,15 +636,16 @@ int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peeri
{
/* Transfer via HTTP over IPv4 */
int sock = socket(AF_INET,SOCK_STREAM,0);
fcntl(sock,F_SETFL, O_NONBLOCK);
SET_NONBLOCKING(sock);
struct sockaddr_in peeraddr;
bcopy(peerip,&peeraddr,sizeof(peeraddr));
//peeraddr.sin_port=htons(RHIZOME_HTTP_PORT);
DEBUG("Initiating HTTP connection for transfer");
int r=connect(sock,(struct sockaddr*)&peeraddr,sizeof(peeraddr));
if ((errno!=EINPROGRESS)&&(r!=0)) {
WHY("Failed to open socket to peer's rhizome web server");
WHY_perror("connect");
close (sock);
if (debug&DEBUG_RHIZOME) DEBUG("Failed to open socket to peer's rhizome web server");
return -1;
}
@ -629,19 +653,17 @@ int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peeri
*q=&file_fetch_queue[rhizome_file_fetch_queue_count];
q->manifest = m;
*manifest_kept = 1;
q->socket=sock;
q->alarm.poll.fd=sock;
strncpy(q->fileid, m->fileHexHash, RHIZOME_FILEHASH_STRLEN + 1);
snprintf(q->request,1024,"GET /rhizome/file/%s HTTP/1.0\r\n\r\n",
q->fileid);
q->request_len=strlen(q->request);
q->request_ofs=0;
q->state=RHIZOME_FETCH_SENDINGHTTPREQUEST;
q->state=RHIZOME_FETCH_CONNECTING;
q->file_len=-1;
q->file_ofs=0;
q->close=0;
q->last_action=time(0);
/* XXX Don't forget to implement resume */
#define RHIZOME_IDLE_TIMEOUT 10
/* XXX We should stream file straight into the database */
const char *id = rhizome_manifest_get(q->manifest, "id", NULL, 0);
if (id == NULL) {
@ -664,6 +686,17 @@ int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peeri
close(sock);
return -1;
}
/* 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=overlay_gettime_ms() + RHIZOME_IDLE_TIMEOUT;
schedule(&q->alarm);
rhizome_file_fetch_queue_count++;
if (1||debug&DEBUG_RHIZOME) DEBUGF("Queued file for fetching into %s (%d in queue)",
q->manifest->dataFileName, rhizome_file_fetch_queue_count);
@ -693,304 +726,251 @@ int rhizome_queue_manifest_import(rhizome_manifest *m, struct sockaddr_in *peeri
return 0;
}
long long rhizome_last_fetch=0;
int rhizome_poll_fetchP=0;
int rhizome_fetching_get_fds(struct pollfd *fds,int *fdcount,int fdmax)
{
/* Don't fetch quickly during voice calls */
rhizome_poll_fetchP=0;
long long now=overlay_gettime_ms();
if (now<rhizome_voice_timeout)
{
/* only fetch data once per 500ms during calls */
if ((rhizome_last_fetch+500)>now)
return 0;
}
rhizome_last_fetch=now;
rhizome_poll_fetchP=1;
int i;
if ((*fdcount)>=fdmax) return -1;
for(i=0;i<rhizome_file_fetch_queue_count;i++)
{
if ((*fdcount)>=fdmax) return -1;
if (debug&DEBUG_RHIZOMESYNC) {
DEBUGF("rhizome file fetch request #%d is poll() slot #%d (fd %d)",
i,*fdcount,file_fetch_queue[i].socket); }
fds[*fdcount].fd=file_fetch_queue[i].socket;
switch(file_fetch_queue[i].state) {
case RHIZOME_FETCH_SENDINGHTTPREQUEST:
fds[*fdcount].events=POLLOUT; break;
case RHIZOME_FETCH_RXHTTPHEADERS:
case RHIZOME_FETCH_RXFILE:
default:
fds[*fdcount].events=POLLIN; break;
}
(*fdcount)++;
}
return 0;
}
long long rhizome_last_fetch_enqueue_time=0;
int rhizome_fetch_poll()
{
int rn;
if (!rhizome_poll_fetchP) return 0;
if (rhizome_last_fetch_enqueue_time<overlay_gettime_ms())
{
rhizome_enqueue_suggestions();
rhizome_last_fetch_enqueue_time=overlay_gettime_ms();
}
if (0&&debug&DEBUG_RHIZOME) DEBUGF("Checking %d active fetch requests",
rhizome_file_fetch_queue_count);
for(rn=0;rn<rhizome_file_fetch_queue_count;rn++)
{
rhizome_file_fetch_record *q=&file_fetch_queue[rn];
int action=0;
int bytes;
/* Make socket non-blocking */
fcntl(q->socket,F_SETFL,fcntl(q->socket, F_GETFL, NULL)|O_NONBLOCK);
switch(q->state)
{
case RHIZOME_FETCH_SENDINGHTTPREQUEST:
DEBUGF("sending http request (%d of %d bytes sent): %s",
q->request_ofs,q->request_len,q->request);
bytes=write(q->socket,&q->request[q->request_ofs],
q->request_len-q->request_ofs);
if (bytes>0) {
action=1;
q->request_ofs+=bytes;
if (q->request_ofs>=q->request_len) {
/* Sent all of request. Switch to listening for HTTP response headers.
*/
if (debug&DEBUG_RHIZOME) {
DEBUGF("Sent http request to fetch file. (%d of %d bytes)",q->request_ofs,q->request_len);
DEBUGF("sent [%s]",q->request);
}
q->request_len=0; q->request_ofs=0;
q->state=RHIZOME_FETCH_RXHTTPHEADERS;
}
} else if (errno!=EAGAIN) {
WHY("Got error while sending HTTP request. Closing.");
q->close=1;
}
break;
case RHIZOME_FETCH_RXFILE:
/* Keep reading until we have the promised amount of data */
if (debug&DEBUG_RHIZOME)
DEBUGF("receiving rhizome fetch file body (current offset=%d of %d)",
q->file_ofs,q->file_len);
sigPipeFlag=0;
errno=0;
char buffer[8192];
int bytes=read(q->socket,buffer,8192);
/* If we got some data, see if we have found the end of the HTTP request */
if (bytes>0) {
action=1;
if (debug&DEBUG_RHIZOME)
DEBUGF("Read %d bytes; we now have %d of %d bytes.",
bytes,q->file_ofs+bytes,q->file_len);
if (bytes>(q->file_len-q->file_ofs))
bytes=q->file_len-q->file_ofs;
if (fwrite(buffer,bytes,1,q->file)!=1)
{
if (debug&DEBUG_RHIZOME) DEBUGF("Failed writing %d bytes to file. @ offset %d",bytes,q->file_ofs);
q->close=1;
continue;
}
q->file_ofs+=bytes;
} else if (bytes==0) {
WHY("Got zero bytes, assume socket dead.");
q->close=1;
continue;
}
if (q->file_ofs>=q->file_len)
{
/* got all of file */
q->close=1;
if (debug&DEBUG_RHIZOME) DEBUGF("Received all of file via rhizome -- now to import it");
{
fclose(q->file); q->file=NULL;
const char *id = rhizome_manifest_get(q->manifest, "id", NULL, 0);
if (id == NULL)
return WHY("Manifest missing ID");
if (create_rhizome_import_dir() == -1)
return -1;
char filename[1024];
if (!FORM_RHIZOME_IMPORT_PATH(filename,"manifest.%s", id))
return -1;
/* Do really write the manifest unchanged */
if (debug&DEBUG_RHIZOME) {
DEBUGF("manifest has %d signatories",q->manifest->sig_count);
DEBUGF("manifest id = %s, len=%d",
rhizome_manifest_get(q->manifest,"id",NULL,0),
q->manifest->manifest_bytes);
dump("manifest",&q->manifest->manifestdata[0],
q->manifest->manifest_all_bytes);
}
q->manifest->finalised=1;
q->manifest->manifest_bytes=q->manifest->manifest_all_bytes;
if (rhizome_write_manifest_file(q->manifest,filename) != -1) {
rhizome_bundle_import(q->manifest, NULL, id,
q->manifest->ttl - 1 /* TTL */);
}
rhizome_manifest_free(q->manifest);
q->manifest=NULL;
}
}
break;
case RHIZOME_FETCH_RXHTTPHEADERS:
/* Keep reading until we have two CR/LFs in a row */
if (debug&DEBUG_RHIZOME) DEBUG("receiving rhizome fetch http headers");
sigPipeFlag=0;
errno=0;
bytes=read(q->socket,&q->request[q->request_len],
1024-q->request_len-1);
/* If we got some data, see if we have found the end of the HTTP request */
if (bytes>0) {
action=1;
int lfcount=0;
int i=q->request_len-160;
if (i<0) i=0;
q->request_len+=bytes;
if (q->request_len<1024)
q->request[q->request_len]=0;
if (debug&DEBUG_RHIZOME)
dump("http reply headers",(unsigned char *)q->request,q->request_len);
for(;i<(q->request_len+bytes);i++)
{
switch(q->request[i]) {
case '\n': lfcount++; break;
case '\r': /* ignore CR */ break;
case 0: /* ignore NUL (telnet inserts them) */ break;
default: lfcount=0; break;
}
if (lfcount==2) break;
}
if (lfcount==2) {
/* We have the response headers, so parse.
(we may also have some extra bytes, so we need to be a little
careful) */
/* Terminate string at end of headers */
q->request[i]=0;
/* Get HTTP result code */
char *s=strstr(q->request,"HTTP/1.0 ");
if (!s) {
if (debug&DEBUG_RHIZOME) DEBUGF("HTTP response lacked HTTP/1.0 response code.");
q->close=1; continue; }
int http_response_code=strtoll(&s[9],NULL,10);
if (http_response_code!=200) {
if (debug&DEBUG_RHIZOME) DEBUGF("Rhizome web server returned %d != 200 OK",http_response_code);
q->close=1; continue;
}
/* Get content length */
s=strstr(q->request,"Content-length: ");
if (!s) {
if (debug&DEBUG_RHIZOME)
DEBUGF("Missing Content-Length: header.");
q->close=1; continue; }
q->file_len=strtoll(&s[16],NULL,10);
if (q->file_len<0) {
if (debug&DEBUG_RHIZOME)
DEBUGF("Illegal file size (%d).",q->file_len);
q->close=1; continue; }
/* Okay, we have both, and are all set.
File is already open, so just write out any initial bytes of the
file we read, and update state flag.
*/
int fileRxBytes=q->request_len-(i+1);
if (fileRxBytes>0)
if (fwrite(&q->request[i+1],fileRxBytes,1,q->file)!=1)
{
if (debug&DEBUG_RHIZOME)
DEBUGF("Failed writing initial %d bytes to file.",
fileRxBytes);
q->close=1;
continue;
}
q->file_ofs=fileRxBytes;
if (debug&DEBUG_RHIZOME)
DEBUGF("Read %d initial bytes of %d total",
q->file_ofs,q->file_len);
q->state=RHIZOME_FETCH_RXFILE;
}
q->request_len+=bytes;
}
/* Give up fairly quickly if there is no action, because the peer may
have moved out of range. */
if (!action) {
if (time(0)-q->last_action>RHIZOME_IDLE_TIMEOUT) {
if (debug&DEBUG_RHIZOME)
DEBUG("Closing connection due to inactivity timeout.");
q->close=1;
continue;
}
} else q->last_action=time(0);
if (sigPipeFlag||((bytes==0)&&(errno==0))) {
/* broken pipe, so close connection */
if (debug&DEBUG_RHIZOME)
DEBUG("Closing rhizome fetch connection due to sigpipe");
q->close=1;
continue;
}
break;
default:
if (debug&DEBUG_RHIZOME)
DEBUG("Closing rhizome fetch connection due to illegal/unimplemented state.");
q->close=1;
break;
}
/* Make socket blocking again for poll()/select() */
fcntl(q->socket,F_SETFL,fcntl(q->socket, F_GETFL, NULL)&(~O_NONBLOCK));
}
int rhizome_fetch_close(rhizome_file_fetch_record *q){
/* Free ephemeral data */
if (q->file) fclose(q->file);
q->file=NULL;
if (q->manifest)
rhizome_manifest_free(q->manifest);
q->manifest=NULL;
int i;
for(i=rhizome_file_fetch_queue_count-1;i>=0;i--)
{
if (file_fetch_queue[i].close) {
/* Free ephemeral data */
if (file_fetch_queue[i].file) fclose(file_fetch_queue[i].file);
file_fetch_queue[i].file=NULL;
if (file_fetch_queue[i].manifest)
rhizome_manifest_free(file_fetch_queue[i].manifest);
file_fetch_queue[i].manifest=NULL;
/* reshuffle higher numbered slot down if required */
if (i<(rhizome_file_fetch_queue_count-1))
bcopy(&file_fetch_queue[rhizome_file_fetch_queue_count-1],
&file_fetch_queue[i],sizeof(rhizome_file_fetch_record));
/* Reduce count of open connections */
rhizome_file_fetch_queue_count--;
if (debug&DEBUG_RHIZOME)
DEBUGF("Released rhizome fetch slot (%d remaining)",
rhizome_file_fetch_queue_count);
}
}
/* close socket and stop watching it */
unwatch(&q->alarm);
unschedule(&q->alarm);
close(q->alarm.poll.fd);
q->alarm.poll.fd=-1;
/* Reduce count of open connections */
rhizome_file_fetch_queue_count--;
if (debug&DEBUG_RHIZOME)
DEBUGF("Released rhizome fetch slot (%d used)",
rhizome_file_fetch_queue_count);
return 0;
}
void rhizome_fetch_write(rhizome_file_fetch_record *q){
int bytes;
bytes=write(q->alarm.poll.fd,&q->request[q->request_ofs],
q->request_len-q->request_ofs);
if (bytes>0) {
// reset timeout
unschedule(&q->alarm);
q->alarm.alarm=overlay_gettime_ms() + RHIZOME_IDLE_TIMEOUT;
schedule(&q->alarm);
q->request_ofs+=bytes;
if (q->request_ofs>=q->request_len) {
/* Sent all of request. Switch to listening for HTTP response headers.
*/
q->request_len=0; q->request_ofs=0;
q->state=RHIZOME_FETCH_RXHTTPHEADERS;
q->alarm.poll.events=POLLIN;
watch(&q->alarm);
}else if(q->state==RHIZOME_FETCH_CONNECTING)
q->state = RHIZOME_FETCH_SENDINGHTTPREQUEST;
} else if (errno!=EAGAIN) {
WHY("Got error while sending HTTP request. Closing.");
rhizome_fetch_close(q);
}
}
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;
}
switch(q->state)
{
case RHIZOME_FETCH_CONNECTING:
case RHIZOME_FETCH_SENDINGHTTPREQUEST:
rhizome_fetch_write(q);
break;
case RHIZOME_FETCH_RXFILE:
/* Keep reading until we have the promised amount of data */
sigPipeFlag=0;
errno=0;
char buffer[8192];
int bytes=read(q->alarm.poll.fd,buffer,8192);
/* If we got some data, see if we have found the end of the HTTP request */
if (bytes>0) {
// reset timeout
unschedule(&q->alarm);
q->alarm.alarm=overlay_gettime_ms() + RHIZOME_IDLE_TIMEOUT;
schedule(&q->alarm);
if (bytes>(q->file_len-q->file_ofs))
bytes=q->file_len-q->file_ofs;
if (fwrite(buffer,bytes,1,q->file)!=1)
{
if (debug&DEBUG_RHIZOME) DEBUGF("Failed writing %d bytes to file. @ offset %d",bytes,q->file_ofs);
rhizome_fetch_close(q);
return;
}
q->file_ofs+=bytes;
} else if (bytes==0) {
WHY("Got zero bytes, assume socket dead.");
rhizome_fetch_close(q);
return;
}
if (q->file_ofs>=q->file_len)
{
/* got all of file */
if (debug&DEBUG_RHIZOME) DEBUGF("Received all of file via rhizome -- now to import it");
{
fclose(q->file); q->file=NULL;
const char *id = rhizome_manifest_get(q->manifest, "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 */
if (debug&DEBUG_RHIZOME) {
DEBUGF("manifest has %d signatories",q->manifest->sig_count);
DEBUGF("manifest id = %s, len=%d",
rhizome_manifest_get(q->manifest,"id",NULL,0),
q->manifest->manifest_bytes);
dump("manifest",&q->manifest->manifestdata[0],
q->manifest->manifest_all_bytes);
}
q->manifest->finalised=1;
q->manifest->manifest_bytes=q->manifest->manifest_all_bytes;
if (rhizome_write_manifest_file(q->manifest,filename) != -1) {
rhizome_bundle_import(q->manifest, NULL, id,
q->manifest->ttl - 1 /* TTL */);
}
rhizome_manifest_free(q->manifest);
q->manifest=NULL;
}
rhizome_fetch_close(q);
return;
}
break;
case RHIZOME_FETCH_RXHTTPHEADERS:
/* Keep reading until we have two CR/LFs in a row */
sigPipeFlag=0;
errno=0;
bytes=read(q->alarm.poll.fd,&q->request[q->request_len],
1024-q->request_len-1);
/* If we got some data, see if we have found the end of the HTTP request */
if (bytes>0) {
int lfcount=0;
int i=q->request_len-160;
// reset timeout
unschedule(&q->alarm);
q->alarm.alarm=overlay_gettime_ms() + RHIZOME_IDLE_TIMEOUT;
schedule(&q->alarm);
if (i<0) i=0;
q->request_len+=bytes;
if (q->request_len<1024)
q->request[q->request_len]=0;
for(;i<(q->request_len+bytes);i++)
{
switch(q->request[i]) {
case '\n': lfcount++; break;
case '\r': /* ignore CR */ break;
case 0: /* ignore NUL (telnet inserts them) */ break;
default: lfcount=0; break;
}
if (lfcount==2) break;
}
if (debug&DEBUG_RHIZOME)
dump("http reply headers",(unsigned char *)q->request,lfcount==2?i:q->request_len);
if (lfcount==2) {
/* We have the response headers, so parse.
(we may also have some bytes of content, so we need to be a little
careful) */
/* Terminate string at end of headers */
q->request[i]=0;
/* Get HTTP result code */
char *s=strstr(q->request,"HTTP/1.0 ");
if (!s) {
if (debug&DEBUG_RHIZOME) DEBUGF("HTTP response lacked HTTP/1.0 response code.");
rhizome_fetch_close(q);
return;
}
int http_response_code=strtoll(&s[9],NULL,10);
if (http_response_code!=200) {
if (debug&DEBUG_RHIZOME) DEBUGF("Rhizome web server returned %d != 200 OK",http_response_code);
rhizome_fetch_close(q);
return;
}
/* Get content length */
s=strstr(q->request,"Content-length: ");
if (!s) {
if (debug&DEBUG_RHIZOME)
DEBUGF("Missing Content-Length: header.");
rhizome_fetch_close(q);
return;
}
q->file_len=strtoll(&s[16],NULL,10);
if (q->file_len<0) {
if (debug&DEBUG_RHIZOME)
DEBUGF("Illegal file size (%d).",q->file_len);
rhizome_fetch_close(q);
return;
}
/* Okay, we have both, and are all set.
File is already open, so just write out any initial bytes of the
file we read, and update state flag.
*/
int fileRxBytes=q->request_len-(i+1);
if (fileRxBytes>0)
if (fwrite(&q->request[i+1],fileRxBytes,1,q->file)!=1)
{
if (debug&DEBUG_RHIZOME)
DEBUGF("Failed writing initial %d bytes to file.",
fileRxBytes);
rhizome_fetch_close(q);
return;
}
q->file_ofs=fileRxBytes;
DEBUGF("Transferred (%lld of %lld)",
q->file_ofs,q->file_len);
q->state=RHIZOME_FETCH_RXFILE;
}
}
if (sigPipeFlag||((bytes==0)&&(errno==0))) {
/* broken pipe, so close connection */
if (debug&DEBUG_RHIZOME)
DEBUG("Closing rhizome fetch connection due to sigpipe");
rhizome_fetch_close(q);
return;
}
break;
default:
if (debug&DEBUG_RHIZOME)
DEBUG("Closing rhizome fetch connection due to illegal/unimplemented state.");
rhizome_fetch_close(q);
return;
}
return;
}

View File

@ -25,6 +25,68 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.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;
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, char *response);
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
char *mime_type,unsigned long long bytes);
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;
struct profile_total server_stats;
struct profile_total connection_stats;
/*
HTTP server and client code for rhizome transfers.
@ -33,9 +95,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
static int rhizome_server_socket = -1;
static long long rhizome_server_last_start_attempt = -1;
rhizome_http_request *rhizome_live_http_requests[RHIZOME_SERVER_MAX_LIVE_REQUESTS];
int rhizome_server_live_request_count=0;
// Format icon data using:
// od -vt u1 ~/Downloads/favicon.ico | cut -c9- | sed 's/ */,/g'
unsigned char favicon_bytes[]={
@ -69,7 +128,7 @@ int favicon_len=318;
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.
*/
static int rhizome_http_server_start()
int rhizome_http_server_start()
{
if (rhizome_server_socket != -1)
return 1;
@ -129,183 +188,125 @@ static int rhizome_http_server_start()
}
INFOF("Started Rhizome HTTP server on port %d", port);
/* Add Rhizome HTTPd server to list of file descriptors to watch */
server_alarm.function = rhizome_server_poll;
server_stats.name="rhizome_server_poll";
server_alarm.stats=&server_stats;
server_alarm.poll.fd = rhizome_server_socket;
server_alarm.poll.events = POLLIN;
watch(&server_alarm);
return 0;
}
int rhizome_poll_httpP=0;
void rhizome_client_poll(struct sched_ent *alarm)
{
rhizome_http_request *r=(rhizome_http_request *)alarm;
if (alarm->poll.revents==0){
rhizome_server_free_http_request(r);
return;
}
switch(r->request_type)
{
case RHIZOME_HTTP_REQUEST_RECEIVING:
/* Keep reading until we have two CR/LFs in a row */
r->request[r->request_length]=0;
sigPipeFlag=0;
errno=0;
int bytes=read(r->alarm.poll.fd,&r->request[r->request_length],
RHIZOME_HTTP_REQUEST_MAXLEN-r->request_length-1);
/* 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 = overlay_gettime_ms()+RHIZOME_IDLE_TIMEOUT;
unschedule(&r->alarm);
schedule(&r->alarm);
int i=r->request_length-160;
int lfcount=0;
if (i<0) i=0;
r->request_length+=bytes;
if (r->request_length<RHIZOME_HTTP_REQUEST_MAXLEN)
r->request[r->request_length]=0;
if (0)
dump("request",(unsigned char *)r->request,r->request_length);
for(;i<(r->request_length+bytes);i++)
{
switch(r->request[i]) {
case '\n': lfcount++; break;
case '\r': /* ignore CR */ break;
case 0: /* ignore NUL (telnet inserts them) */ break;
default: lfcount=0; break;
}
if (lfcount==2) break;
}
if (lfcount==2) {
/* We have the request. Now parse it to see if we can respond to it */
rhizome_server_parse_http_request(r);
}
}
int rhizome_server_poll()
if (sigPipeFlag||((bytes==0)&&(errno==0))) {
/* broken pipe, so close connection */
WHY("Closing connection due to sigpipe");
rhizome_server_free_http_request(r);
return;
}
break;
default:
/* Socket already has request -- so just try to send some data. */
rhizome_server_http_send_bytes(r);
break;
}
return;
}
void rhizome_server_poll(struct sched_ent *alarm)
{
struct sockaddr addr;
unsigned int addr_len=0;
int sock;
int rn;
if (!rhizome_poll_httpP) return 0;
/* Having the starting of the server here is helpful in that
if the port is taken by someone else, we will grab it fairly
swiftly once it becomes available. */
if (rhizome_server_socket == -1 && rhizome_http_server_start())
return 0;
/* Process the existing requests.
XXX - should use poll or select here */
if (0&&debug&DEBUG_RHIZOME) WHYF("Checking %d active connections",
rhizome_server_live_request_count);
for(rn=0;rn<rhizome_server_live_request_count;rn++)
{
rhizome_http_request *r=rhizome_live_http_requests[rn];
switch(r->request_type)
{
case RHIZOME_HTTP_REQUEST_RECEIVING:
/* Keep reading until we have two CR/LFs in a row */
r->request[r->request_length]=0;
WHYF("http request so far: [%s]",r->request);
sigPipeFlag=0;
/* Make socket non-blocking */
fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)|O_NONBLOCK);
errno=0;
int bytes=read(r->socket,&r->request[r->request_length],
RHIZOME_HTTP_REQUEST_MAXLEN-r->request_length-1);
/* If we got some data, see if we have found the end of the HTTP request */
if (bytes>0) {
int i=r->request_length-160;
int lfcount=0;
if (i<0) i=0;
r->request_length+=bytes;
if (r->request_length<RHIZOME_HTTP_REQUEST_MAXLEN)
r->request[r->request_length]=0;
dump("request",(unsigned char *)r->request,r->request_length);
for(;i<(r->request_length+bytes);i++)
{
switch(r->request[i]) {
case '\n': lfcount++; break;
case '\r': /* ignore CR */ break;
case 0: /* ignore NUL (telnet inserts them) */ break;
default: lfcount=0; break;
}
if (lfcount==2) break;
}
if (lfcount==2) {
/* We have the request. Now parse it to see if we can respond to it */
rhizome_server_parse_http_request(rn,r);
}
r->request_length+=bytes;
}
/* Make socket blocking again for poll()/select() */
fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)&(~O_NONBLOCK));
if (sigPipeFlag||((bytes==0)&&(errno==0))) {
/* broken pipe, so close connection */
WHY("Closing connection due to sigpipe");
rhizome_server_close_http_request(rn);
continue;
}
break;
default:
/* Socket already has request -- so just try to send some data. */
rhizome_server_http_send_bytes(rn,r);
break;
}
}
/* Deal with any new requests */
/* Make socket non-blocking */
fcntl(rhizome_server_socket,F_SETFL,
fcntl(rhizome_server_socket, F_GETFL, NULL)|O_NONBLOCK);
while ((rhizome_server_live_request_count<RHIZOME_SERVER_MAX_LIVE_REQUESTS)
&&((sock=accept(rhizome_server_socket,&addr,&addr_len))>-1))
while ((sock=accept(rhizome_server_socket,&addr,&addr_len))>-1)
{
rhizome_http_request *request = calloc(sizeof(rhizome_http_request),1);
request->socket=sock;
/* We are now trying to read the HTTP request */
request->request_type=RHIZOME_HTTP_REQUEST_RECEIVING;
rhizome_live_http_requests[rhizome_server_live_request_count++]=request;
request->alarm.function = rhizome_client_poll;
connection_stats.name="rhizome_client_poll";
request->alarm.stats=&connection_stats;
request->alarm.poll.fd=sock;
request->alarm.poll.events=POLLIN;
request->alarm.alarm = overlay_gettime_ms()+RHIZOME_IDLE_TIMEOUT;
// watch for the incoming http request
watch(&request->alarm);
// set an inactivity timeout to close the connection
schedule(&request->alarm);
}
fcntl(rhizome_server_socket,F_SETFL,
fcntl(rhizome_server_socket, F_GETFL, NULL)&(~O_NONBLOCK));
return 0;
}
int rhizome_server_close_http_request(int i)
{
close(rhizome_live_http_requests[i]->socket);
rhizome_server_free_http_request(rhizome_live_http_requests[i]);
/* Make it null, so that if we are the list in the list, the following
assignment still yields the correct behaviour */
rhizome_live_http_requests[i]=NULL;
rhizome_live_http_requests[i]=
rhizome_live_http_requests[rhizome_server_live_request_count-1];
rhizome_server_live_request_count--;
return 0;
}
int rhizome_server_free_http_request(rhizome_http_request *r)
{
unwatch(&r->alarm);
unschedule(&r->alarm);
close(r->alarm.poll.fd);
if (r->buffer&&r->buffer_size) free(r->buffer);
if (r->blob_table) free(r->blob_table);
if (r->blob_column) free(r->blob_column);
if (r->blob) sqlite3_blob_close(r->blob);
free(r);
return 0;
}
long long rhizome_last_http_send=0;
int rhizome_server_get_fds(struct pollfd *fds,int *fdcount,int fdmax)
{
int i;
if ((*fdcount)>=fdmax) return -1;
rhizome_poll_httpP=0;
/* Don't send quickly during voice calls */
long long now=overlay_gettime_ms();
if (now<rhizome_voice_timeout)
{
/* only send data once per 500ms during calls */
if ((rhizome_last_http_send+500)>now)
return 0;
}
rhizome_last_http_send=now;
rhizome_poll_httpP=1;
if (rhizome_server_socket>-1)
{
if (debug&DEBUG_IO) {
WHYF("rhizome http server is poll() slot #%d (fd %d)",
*fdcount,rhizome_server_socket);
}
fds[*fdcount].fd=rhizome_server_socket;
fds[*fdcount].events=POLLIN;
(*fdcount)++;
}
for(i=0;i<rhizome_server_live_request_count;i++)
{
if ((*fdcount)>=fdmax) return -1;
if (debug&DEBUG_IO) {
WHYF("rhizome http request #%d is poll() slot #%d (fd %d)",
i,*fdcount,rhizome_live_http_requests[i]->socket); }
fds[*fdcount].fd=rhizome_live_http_requests[i]->socket;
switch(rhizome_live_http_requests[i]->request_type) {
case RHIZOME_HTTP_REQUEST_RECEIVING:
fds[*fdcount].events=POLLIN; break;
default:
fds[*fdcount].events=POLLOUT; break;
}
(*fdcount)++;
}
return 0;
}
void hexFilter(char *s)
{
char *t;
@ -315,7 +316,7 @@ void hexFilter(char *s)
*t = '\0';
}
int rhizome_server_sql_query_http_response(int rn,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)
{
@ -369,16 +370,14 @@ int rhizome_server_sql_query_http_response(int rn,rhizome_http_request *r,
WHYF("SQL query overrun: %s", strbuf_str(b));
r->source_index=0;
r->source_flags=dehexP;
r->blob_column=strdup(column);
r->blob_table=strdup(table);
DEBUGF("buffer_length=%d",r->buffer_length);
/* Populate spare space in buffer with rows of data */
return rhizome_server_sql_query_fill_buffer(rn,r);
return rhizome_server_sql_query_fill_buffer(r, table, column);
}
int rhizome_server_sql_query_fill_buffer(int rn,rhizome_http_request *r)
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];
@ -429,9 +428,9 @@ int rhizome_server_sql_query_fill_buffer(int rn,rhizome_http_request *r)
case SQLITE_TEXT: value=sqlite3_column_text(statement, 0); break;
case SQLITE_BLOB:
WHYF("table='%s',col='%s',rowid=%lld",
r->blob_table,r->blob_column,
table, column,
sqlite3_column_int64(statement,1));
if (sqlite3_blob_open(rhizome_db,"main",r->blob_table,r->blob_column,
if (sqlite3_blob_open(rhizome_db,"main",table,column,
sqlite3_column_int64(statement,1) /* rowid */,
0 /* read only */,&blob)!=SQLITE_OK)
{
@ -469,8 +468,6 @@ int rhizome_server_sql_query_fill_buffer(int rn,rhizome_http_request *r)
bcopy(value,&r->buffer[r->buffer_length],r->source_record_size);
r->buffer_length+=r->source_record_size;
WHYF("wrote row %lld, buffer_length=%d",
r->source_index,r->buffer_length);
}
sqlite3_finalize(statement);
@ -478,9 +475,13 @@ int rhizome_server_sql_query_fill_buffer(int rn,rhizome_http_request *r)
}
int rhizome_server_parse_http_request(int rn,rhizome_http_request *r)
int rhizome_server_parse_http_request(rhizome_http_request *r)
{
char id[1024];
/* Switching to writing, so update the call-back */
r->alarm.poll.events=POLLOUT;
watch(&r->alarm);
/* Clear request type flags */
r->request_type=0;
@ -498,55 +499,52 @@ int rhizome_server_parse_http_request(int rn,rhizome_http_request *r)
{
/* Return the list of known groups */
WHYF("get /rhizome/groups (list of groups)");
rhizome_server_sql_query_http_response(rn,r,"id","groups","from groups",32,1);
rhizome_server_sql_query_http_response(r,"id","groups","from groups",32,1);
}
else if (!strncasecmp(r->request,"GET /rhizome/files HTTP/1.",
strlen("GET /rhizome/files HTTP/1.")))
{
/* Return the list of known files */
WHYF("get /rhizome/files (list of files)");
rhizome_server_sql_query_http_response(rn,r,"id","files","from files",32,1);
rhizome_server_sql_query_http_response(r,"id","files","from files",32,1);
}
else if (!strncasecmp(r->request,"GET /rhizome/bars HTTP/1.",
strlen("GET /rhizome/bars HTTP/1.")))
{
/* Return the list of known files */
WHYF("get /rhizome/bars (list of BARs)");
rhizome_server_sql_query_http_response(rn,r,"bar","manifests","from manifests",32,0);
rhizome_server_sql_query_http_response(r,"bar","manifests","from manifests",32,0);
}
else if (sscanf(r->request,"GET /rhizome/file/%s HTTP/1.", id)==1)
{
/* Stream the specified file */
int dud=0;
int i;
hexFilter(id);
WHYF("get /rhizome/file/ [%s]",id);
WHY("Check for range: header, and return 206 if returning partial content");
// Check for range: header, and return 206 if returning partial content
for(i=0;i<strlen(id);i++) if (!isxdigit(id[i])) dud++;
if (dud) rhizome_server_simple_http_response(r,400,"<html><h1>That doesn't look like hex to me.</h1></html>\r\n");
else {
str_toupper_inplace(id);
long long rowid = -1;
sqlite_exec_int64(&rowid, "select rowid from files where id='%s';", id);
sqlite3_blob *blob;
if (rowid>=0)
if (sqlite3_blob_open(rhizome_db,"main","files","data",rowid,0,&blob) !=SQLITE_OK)
if (sqlite3_blob_open(rhizome_db,"main","files","data",rowid,0,&r->blob) !=SQLITE_OK)
rowid=-1;
if (rowid<0) {
rhizome_server_simple_http_response(r,404,"<html><h1>Sorry, can't find that here.</h1></html>\r\n");
WHY("File not found / blob not opened");
}
else {
r->blob_table=strdup("files");
r->blob_column=strdup("data");
r->blob_rowid=rowid;
r->source_index=0;
r->blob_end=sqlite3_blob_bytes(blob);
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->blob_end - r->source_index);
r->request_type|=RHIZOME_HTTP_REQUEST_BLOB;
sqlite3_blob_close(blob);
WHY("opened blob and file -- but still need to send file body.");
}
}
}
@ -564,7 +562,7 @@ int rhizome_server_parse_http_request(int rn,rhizome_http_request *r)
rhizome_server_simple_http_response(r,400,"<html><h1>Sorry, your request was too long.</h1></html>\r\n");
/* Try sending data immediately. */
rhizome_server_http_send_bytes(rn,r);
rhizome_server_http_send_bytes(r);
return 0;
}
@ -588,7 +586,7 @@ char *httpResultString(int id) {
int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char *response)
{
if (r->buffer) free(r->buffer);
r->buffer_size=strlen(response)+strlen("HTTP/1.0 000 \r\n\r\n")+strlen(httpResultString(A_VALUE_GREATER_THAN_FOUR))+100;
r->buffer_size=strlen(response)+strlen("HTTP/1.0 000 \r\n\r\nContent-type: text/html\r\nContent-length: 0000\r\n\r\n")+strlen(httpResultString(result))+strlen(response)+100;
r->buffer=(unsigned char *)malloc(r->buffer_size);
snprintf((char *)r->buffer,r->buffer_size,"HTTP/1.0 %03d %s\r\nContent-type: text/html\r\nContent-length: %d\r\n\r\n%s",result,httpResultString(result),(int)strlen(response),response);
@ -607,122 +605,132 @@ int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char
0: connection finished.
<0: an error occurred.
*/
int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r)
int rhizome_server_http_send_bytes(rhizome_http_request *r)
{
sqlite3_blob *blob;
int bytes;
fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)|O_NONBLOCK);
if (debug&DEBUG_RHIZOME) WHYF("Request #%d, type=0x%x\n",rn,r->request_type);
/* Flush anything out of the buffer if present, before doing any further
processing */
if (r->request_type&RHIZOME_HTTP_REQUEST_FROMBUFFER)
{
bytes=r->buffer_length-r->buffer_offset;
bytes=write(r->socket,&r->buffer[r->buffer_offset],bytes);
if (bytes>0) {
WHYF("wrote %d bytes\n",bytes);
dump("bytes written",&r->buffer[r->buffer_offset],bytes);
r->buffer_offset+=bytes;
if (r->buffer_offset>=r->buffer_length) {
/* Our work is done. close socket and go home */
r->request_type&=~RHIZOME_HTTP_REQUEST_FROMBUFFER;
r->buffer_offset=0; r->buffer_length=0;
if (!r->request_type) {
WHY("Finished sending data");
return rhizome_server_close_http_request(rn);
} else {
if (debug&DEBUG_RHIZOME) { WHYF("request type = 0x%x after sending buffer.",
r->request_type);
}
}
} else {
/* Still more stuff in the buffer, so return now */
// keep writing until the write would block or we run out of data
while(r->request_type){
/* Flush anything out of the buffer if present, before doing any further
processing */
if (r->request_type&RHIZOME_HTTP_REQUEST_FROMBUFFER)
{
int bytes=r->buffer_length-r->buffer_offset;
bytes=write(r->alarm.poll.fd,&r->buffer[r->buffer_offset],bytes);
if (bytes<=0){
// stop writing when the tcp buffer is full
// TODO errors?
return 1;
}
if (0)
dump("bytes written",&r->buffer[r->buffer_offset],bytes);
r->buffer_offset+=bytes;
// reset inactivity timer
r->alarm.alarm = overlay_gettime_ms()+RHIZOME_IDLE_TIMEOUT;
unschedule(&r->alarm);
schedule(&r->alarm);
if (r->buffer_offset>=r->buffer_length) {
/* Buffer's cleared */
r->request_type&=~RHIZOME_HTTP_REQUEST_FROMBUFFER;
r->buffer_offset=0; r->buffer_length=0;
}
// go around the loop again to work out what we should do next
continue;
}
}
switch(r->request_type&(~RHIZOME_HTTP_REQUEST_FROMBUFFER))
{
case RHIZOME_HTTP_REQUEST_FAVICON:
if (r->buffer_size<favicon_len) {
free(r->buffer);
r->buffer_size=0;
r->buffer=malloc(favicon_len);
if (!r->buffer) r->request_type=0;
}
if (r->buffer)
switch(r->request_type&(~RHIZOME_HTTP_REQUEST_FROMBUFFER))
{
int i;
for(i=0;i<favicon_len;i++)
r->buffer[i]=favicon_bytes[i];
r->buffer_length=i;
printf("buffer_length for favicon is %d\n",r->buffer_length);
r->request_type=RHIZOME_HTTP_REQUEST_FROMBUFFER;
}
break;
case RHIZOME_HTTP_REQUEST_BLOB:
/* Get more data from the file and put it in the buffer */
r->buffer_length=r->blob_end-r->source_index;
if (r->buffer_length<=0) {
/* end of blob reached */
r->request_type=0; break;
}
if (r->buffer_size<65536) {
free(r->buffer); r->buffer=malloc(65536);
if (!r->buffer) {
if (debug&DEBUG_RHIZOME) WHY("malloc() failed");
r->request_type=0; break;
case RHIZOME_HTTP_REQUEST_FAVICON:
if (r->buffer_size<favicon_len) {
free(r->buffer);
r->buffer_size=0;
r->buffer=malloc(favicon_len);
if (!r->buffer) r->request_type=0;
}
r->buffer_size=65536;
}
if (r->buffer_length>r->buffer_size) r->buffer_length=r->buffer_size;
if (sqlite3_blob_open(rhizome_db,"main",r->blob_table,r->blob_column,
r->blob_rowid,0,&blob)==SQLITE_OK)
if (r->buffer)
{
if(sqlite3_blob_read(blob,&r->buffer[0],r->buffer_length,r->source_index)
==SQLITE_OK)
{
r->request_type|=RHIZOME_HTTP_REQUEST_FROMBUFFER;
r->source_index+=r->buffer_length;
}
else
r->request_type=0;
sqlite3_blob_close(blob);
int i;
for(i=0;i<favicon_len;i++)
r->buffer[i]=favicon_bytes[i];
r->buffer_length=i;
printf("buffer_length for favicon is %d\n",r->buffer_length);
r->request_type=RHIZOME_HTTP_REQUEST_FROMBUFFER;
}
else
break;
case RHIZOME_HTTP_REQUEST_BLOB:
{
if (debug&DEBUG_RHIZOME) WHY("could not open blob to send more data");
/* Get more data from the file and put it in the buffer */
int read_size = 65536;
if (r->blob_end-r->source_index < read_size)
read_size = r->blob_end-r->source_index;
r->request_type=0;
if (read_size>0){
if (r->buffer_size < read_size) {
if (r->buffer)
free(r->buffer);
r->buffer=malloc(read_size);
if (!r->buffer) {
if (debug&DEBUG_RHIZOME) WHY("malloc() failed");
r->request_type=0; break;
}
r->buffer_size=read_size;
}
if(sqlite3_blob_read(r->blob,&r->buffer[0],read_size,r->source_index)
==SQLITE_OK)
{
r->buffer_length = read_size;
r->source_index+=read_size;
r->request_type|=RHIZOME_HTTP_REQUEST_FROMBUFFER;
}
}
if (r->source_index >= r->blob_end){
sqlite3_blob_close(r->blob);
r->blob=0;
}else
r->request_type|=RHIZOME_HTTP_REQUEST_BLOB;
}
break;
case RHIZOME_HTTP_REQUEST_FROMBUFFER:
/* This really shouldn't happen! */
return WHY("Something impossible happened.");
break;
default:
WHY("sending data from this type of HTTP request not implemented");
break;
}
if (!r->request_type) return rhizome_server_close_http_request(rn);
fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)&(~O_NONBLOCK));
break;
default:
WHY("sending data from this type of HTTP request not implemented");
r->request_type=0;
break;
}
}
if (!r->request_type) return rhizome_server_free_http_request(r);
return 1;
}
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
char *mime_type,unsigned long long bytes)
{
if (!r->buffer) {
r->buffer_size=bytes+strlen("HTTP/1.0 000 \r\n\r\n")+strlen(httpResultString(A_VALUE_GREATER_THAN_FOUR))+100;
r->buffer=(unsigned char *)malloc(r->buffer_size);
int min_buff = strlen("HTTP/1.0 000 \r\nContent-type: \r\nContent-length: \r\n\r\n")
+strlen(httpResultString(result))
+strlen(mime_type)+20;
if (min_buff+bytes > 65536){
min_buff = 65536;
}else{
min_buff += bytes;
}
snprintf((char *)r->buffer,r->buffer_size,"HTTP/1.0 %03d \r\nContent-type: %s\r\nContent-length: %lld\r\n\r\n",result,mime_type,bytes);
if (r->buffer_size < min_buff) {
if (r->buffer)
free(r->buffer);
r->buffer=(unsigned char *)malloc(min_buff);
r->buffer_size=min_buff;
}
snprintf((char *)r->buffer,r->buffer_size,"HTTP/1.0 %03d %s\r\nContent-type: %s\r\nContent-length: %lld\r\n\r\n",result,httpResultString(result),mime_type,bytes);
r->buffer_length=strlen((char *)r->buffer);
r->buffer_offset=0;

View File

@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar)
{
IN();
/* BAR = Bundle Advertisement Record.
Basically a 32byte precis of a given manifest, that includes version, time-to-live
and geographic bounding box information that is used to help manage flooding of
@ -38,7 +39,7 @@ int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar)
16 bits - max longitude (-180 - +180).
*/
if (!m) return WHY("null manifest passed in");
if (!m) { RETURN(WHY("null manifest passed in")); }
int i;
@ -66,13 +67,14 @@ int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar)
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;
return 0;
RETURN(0);
}
int bundles_available=-1;
int bundle_offset[2]={0,0};
int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e)
{
IN();
int voice_mode=0;
unsigned short int http_port = RHIZOME_HTTP_PORT;
@ -88,7 +90,7 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e)
*/
long long now=overlay_gettime_ms();
if (now<rhizome_voice_timeout) voice_mode=1;
if (voice_mode) if (random()&3) return 0;
if (voice_mode) if (random()&3) { RETURN(0); }
int pass;
int bytes=e->sizeLimit-e->length;
@ -100,12 +102,12 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e)
int bytes_available=bytes-overhead-1 /* one byte held for expanding RFS */;
int bundles_advertised=0;
if (slots<1) return WHY("No room for node advertisements");
if (slots<1) { RETURN(WHY("No room for node advertisements")); }
if (!rhizome_db) return WHY("Rhizome not enabled");
if (!rhizome_db) { RETURN(WHY("Rhizome not enabled")); }
if (ob_append_byte(e,OF_TYPE_RHIZOME_ADVERT))
return WHY("could not add rhizome bundle advertisement header");
RETURN(WHY("could not add rhizome bundle advertisement header"));
ob_append_byte(e, 1); /* TTL (1 byte) */
int rfs_offset=e->length; /* remember where the RFS byte gets stored
@ -148,7 +150,7 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e)
/* Get number of bundles available if required */
long long tmp = 0;
if (sqlite_exec_int64(&tmp, "SELECT COUNT(BAR) FROM MANIFESTS;") != 1)
return WHY("Could not count BARs for advertisement");
{ RETURN(WHY("Could not count BARs for advertisement")); }
bundles_available = (int) tmp;
if (bundles_available==-1||(bundle_offset[0]>=bundles_available))
bundle_offset[0]=0;
@ -184,7 +186,7 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e)
sqlite3_close(rhizome_db); rhizome_db=NULL;
WHY(query);
WHY(sqlite3_errmsg(rhizome_db));
return WHY("Could not prepare sql statement for fetching BARs for advertisement.");
RETURN(WHY("Could not prepare sql statement for fetching BARs for advertisement."));
}
while((bytes_used<bytes_available)&&(sqlite3_step(statement)==SQLITE_ROW)&&
(e->length+RHIZOME_BAR_BYTES<=e->sizeLimit))
@ -323,12 +325,13 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e)
e->length++;
}
return 0;
RETURN(0);
}
int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now)
{
if (!f) return -1;
IN();
if (!f) { RETURN(-1); }
int ofs=0;
int ad_frame_type=f->payload->bytes[ofs++];
struct sockaddr_in httpaddr = *(struct sockaddr_in *)f->recvaddr;
@ -368,19 +371,19 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now)
m = rhizome_new_manifest();
if (!m) {
WHY("Out of manifests");
return 0;
RETURN(0);
}
if (rhizome_read_manifest_file(m, (char *)&f->payload->bytes[ofs],
manifest_length) == -1) {
WHY("Error importing manifest body");
rhizome_manifest_free(m);
return 0;
RETURN(0);
}
char manifest_id_prefix[RHIZOME_MANIFEST_ID_STRLEN + 1];
if (rhizome_manifest_get(m, "id", manifest_id_prefix, sizeof manifest_id_prefix) == NULL) {
WHY("Manifest does not contain 'id' field");
rhizome_manifest_free(m);
return 0;
RETURN(0);
}
/* trim manifest ID to a prefix for ease of debugging
(that is the only use of this */
@ -399,7 +402,7 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now)
offering the same manifest */
WARN("Ignoring manifest announcment with no signature");
rhizome_manifest_free(m);
return 0;
RETURN(0);
}
int importManifest=0;
if (rhizome_ignore_manifest_check(m, &httpaddr))
@ -438,10 +441,12 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now)
WHY("Error importing manifest body");
rhizome_manifest_free(m);
m = NULL;
} else if (rhizome_manifest_verify(m)) {
WHY("Error verifying manifest body when importing");
rhizome_manifest_free(m);
m = NULL;
/* PGS @20120626 - Used to verify manifest here, which is before
checking if we already have the bundle or newer. Trouble is
that signature verification is VERY expensive (~400ms on the ideos
phones), so we now defer it to inside
rhizome_suggest_queue_manifest_import(), where it only gets called
after checking that it is worth adding to the queue. */
} else if (m->errors) {
if (debug&DEBUG_RHIZOME) DEBUGF("Verifying manifest %s* revealed errors -- not storing.", manifest_id_prefix);
rhizome_queue_ignore_manifest(m, &httpaddr, 60000);
@ -463,6 +468,5 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now)
}
break;
}
return 0;
RETURN(0);
}

598
serval.h
View File

@ -114,15 +114,6 @@ struct in_addr {
/* bzero(3) is deprecated in favour of memset(3). */
#define bzero(addr,len) memset((addr), 0, (len))
/* @PGS/20120615 */
#ifdef DO_TIMING_CHECKS
#define TIMING_CHECK() _TIMING_CHECK(__FILE__,__FUNCTION__,__LINE__)
void _TIMING_CHECK(const char *file,const char *func,int line);
void TIMING_PAUSE();
#else
#define TIMING_CHECK()
#endif
/* UDP Port numbers for various Serval services.
The overlay mesh works over DNA */
#define PORT_DNA 4110
@ -400,6 +391,276 @@ extern struct mphlr_variable vars[];
extern int sock;
#define OVERLAY_MAX_INTERFACES 16
typedef struct overlay_address_table {
unsigned char epoch;
char sids[256][SID_SIZE];
/* 0x00 = not set, which thus limits us to using only 255 (0x01-0xff) of the indexes for
storing addresses.
By spending an extra 256 bytes we reduce, but not eliminate the problem of collisions.
Will think about a complete solution later.
*/
unsigned char byfirstbyte[256][2];
/* next free entry in sid[] */
unsigned char next_free;
} overlay_address_table;
typedef struct sid {
unsigned char b[SID_SIZE];
} sid;
typedef struct overlay_address_cache {
int size;
int shift; /* Used to calculat lookup function, which is (b[0].b[1].b[2]>>shift) */
sid *sids; /* one entry per bucket, to keep things simple. */
/* XXX Should have a means of changing the hash function so that naughty people can't try
to force our cache to flush with duplicate addresses?
But we must use only the first 24 bits of the address due to abbreviation policies,
so our options are limited.
For now the hash will be the first k bits.
*/
} overlay_address_cache;
extern sid overlay_abbreviate_current_sender;
typedef struct overlay_frame {
struct overlay_frame *prev;
struct overlay_frame *next;
unsigned int type;
unsigned int modifiers;
unsigned char ttl;
unsigned char dequeue;
/* Mark which interfaces the frame has been sent on,
so that we can ensure that broadcast frames get sent
exactly once on each interface */
int isBroadcast;
unsigned char broadcast_sent_via[OVERLAY_MAX_INTERFACES];
unsigned char nexthop[32];
int nexthop_address_status;
int nexthop_interface; /* which interface the next hop should be attempted on */
unsigned char destination[32];
int destination_address_status;
unsigned char source[32];
int source_address_status;
/* IPv4 node frame was received from (if applicable) */
struct sockaddr *recvaddr;
/* Frame content from destination address onwards */
int bytecount;
unsigned char *bytes;
/* Actual payload */
struct overlay_buffer *payload;
int rfs; /* remainder of frame size */
long long enqueued_at;
} overlay_frame;
#define CRYPT_CIPHERED 1
#define CRYPT_SIGNED 2
#define CRYPT_PUBLIC 4
struct call_stats{
long long enter_time;
long long child_time;
struct call_stats *prev;
};
struct profile_total {
struct profile_total *_next;
int _initialised;
const char *name;
long long max_time;
long long total_time;
int calls;
};
struct sched_ent;
typedef void (*ALARM_FUNCP) (struct sched_ent *alarm);
struct sched_ent{
struct sched_ent *_next;
struct sched_ent *_prev;
ALARM_FUNCP function;
void *context;
struct pollfd poll;
long long alarm;
struct profile_total *stats;
int _poll_index;
};
extern int overlayMode;
#define OVERLAY_INTERFACE_UNKNOWN 0
#define OVERLAY_INTERFACE_ETHERNET 1
#define OVERLAY_INTERFACE_WIFI 2
#define OVERLAY_INTERFACE_PACKETRADIO 3
typedef struct overlay_interface {
struct sched_ent alarm;
char name[80];
int offset;
int fileP;
int bits_per_second;
int port;
int type;
/* Number of milli-seconds per tick for this interface, which is basically related to the
the typical TX range divided by the maximum expected speed of nodes in the network.
This means that short-range communications has a higher bandwidth requirement than
long-range communications because the tick interval has to be shorter to still allow
fast-convergence time to allow for mobility.
For wifi (nominal range 100m) it is usually 500ms.
For ~100K ISM915MHz (nominal range 1000m) it will probably be about 5000ms.
For ~10K ISM915MHz (nominal range ~3000m) it will probably be about 15000ms.
These figures will be refined over time, and we will allow people to set them per-interface.
*/
int tick_ms; /* milliseconds per tick */
/* The time of the last tick on this interface in milli seconds */
long long last_tick_ms;
/* How many times have we abbreviated our address since we last announced it in full? */
int ticks_since_sent_full_address;
/* sequence number of last packet sent on this interface.
Used to allow NACKs that can request retransmission of recent packets.
*/
int sequence_number;
/* XXX need recent packet buffers to support the above */
/* Broadcast address and netmask, if known
We really only case about distinct broadcast addresses on interfaces.
Also simplifies aliases on interfaces. */
struct sockaddr_in broadcast_address;
/* Not necessarily the real MTU, but the largest frame size we are willing to TX on this interface.
For radio links the actual maximum and the maximum that is likely to be delivered reliably are
potentially two quite different values. */
int mtu;
/* If the interface still exists on the local machine.
If not, it we keep track of it for a few seconds before purging it, incase of flapping, e.g.,
due to DHCP renewal */
int observed;
} overlay_interface;
/* Maximum interface count is rather arbitrary.
Memory consumption is O(n) with respect to this parameter, so let's not make it too big for now.
*/
extern overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES];
extern int overlay_last_interface_number; // used to remember where a packet came from
extern unsigned int overlay_sequence_number;
/*
For each peer we need to keep track of the routes that we know to reach it.
We want to use static sized data structures as much as we can to keep things efficient by
allowing computed memory address lookups instead of following linked lists and other
non-deterministic means.
The tricky part of doing all this is that each interface may have a different maximum number
of peers based on the bandwidth of the link, as we do not want mesh traffic to consume all
available bandwidth. In particular, we need to reserve at least enough bandwidth for one
call.
Related to this, if we are in a mesh larger than the per-interface limit allows, then we need to
only track the highest-scoring peers. This sounds simple, but how to we tell when to replace a
low-scoring peer with another one which has a better reachability score, if we are not tracking
the reachability score of that node?
The answer to this is that we track as many nodes as we can, but only announce the highest
scoring nodes on each interface as bandwidth allows.
This also keeps our memory usage fixed.
XXX - At present we are setting OVERLAY_MAX_PEERS at compile time.
With a bit of work we can change this to be a run-time option.
Memory consumption of OVERLAY_MAX_PEERS=n is O(n^2).
XXX We could and should improve this down the track by only monitoring the top k routes, and replacing the worst route
option when a better one comes along. This would get the memory usage down to O(n).
*/
#define OVERLAY_MAX_PEERS 500
typedef struct overlay_peer {
unsigned char address[SIDDIDFIELD_LEN];
/* Scores and score update times for reaching this node via various interfaces */
int known_routes[OVERLAY_MAX_INTERFACES];
unsigned short scores[OVERLAY_MAX_INTERFACES][OVERLAY_MAX_PEERS];
/* last_regeneration is the time that this peer was created/replaced with another peer.
lastupdate[] indicates the time that another peer's reachability report
caused us to update our score to reach via that peer.
If lastupdate[x][y] is older than last_regeneration[y], then we must
ignore the entry, because the lastupdate[x][y] entry references a previous
generation of that peer, i.e., not to the peer we think it does.
This slight convolution allows us to replace peers without having to touch the
records of every other peer in our list.
*/
int last_regeneration;
unsigned int lastupdate[OVERLAY_MAX_INTERFACES][OVERLAY_MAX_PEERS];
} overlay_peer;
extern overlay_peer overlay_peers[OVERLAY_MAX_PEERS];
typedef struct overlay_buffer {
unsigned char *bytes;
int length;
int allocSize;
int checkpointLength;
int sizeLimit;
int var_length_offset;
int var_length_bytes;
} overlay_buffer;
int ob_unlimitsize(overlay_buffer *b);
typedef struct overlay_txqueue {
struct overlay_frame *first;
struct overlay_frame *last;
int length; /* # frames in queue */
int maxLength; /* max # frames in queue before we consider ourselves congested */
/* Latency target in ms for this traffic class.
Frames older than the latency target will get dropped. */
int latencyTarget;
/* XXX Need to initialise these:
Real-time queue for voice (<200ms ?)
Real-time queue for video (<200ms ?) (lower priority than voice)
Ordinary service queue (<3 sec ?)
Rhizome opportunistic queue (infinity)
(Mesh management doesn't need a queue, as each overlay packet is tagged with some mesh management information)
*/
} overlay_txqueue;
#define OQ_ISOCHRONOUS_VOICE 0
#define OQ_MESH_MANAGEMENT 1
#define OQ_ISOCHRONOUS_VIDEO 2
#define OQ_ORDINARY 3
#define OQ_OPPORTUNISTIC 4
#define OQ_MAX 5
extern overlay_txqueue overlay_tx[OQ_MAX];
const char *confValueGet(const char *var, const char *defaultValue);
int confValueGetBoolean(const char *var, int defaultValue);
int64_t confValueGetInt64(const char *var, int64_t defaultValue);
@ -431,7 +692,6 @@ long long gettime_ms();
int server_pid();
void server_save_argv(int argc, const char *const *argv);
int server(char *backing_file);
void server_shutdown_check();
int server_create_stopfile();
int server_remove_stopfile();
int server_check_stopfile();
@ -439,7 +699,7 @@ void serverCleanUp();
int isTransactionInCache(unsigned char *transaction_id);
void insertTransactionInCache(unsigned char *transaction_id);
int packetOk(int interface,unsigned char *packet,int len,
int packetOk(struct overlay_interface *interface,unsigned char *packet,int len,
unsigned char *transaction_id, int recvttl,
struct sockaddr *recvaddr,int recvaddrlen,int parseP);
int process_packet(unsigned char *packet,int len,
@ -500,7 +760,7 @@ int runCommand(char *cmd);
int asteriskObtainGateway(char *requestor_sid,char *did,char *uri_out);
int packetOkDNA(unsigned char *packet,int len,unsigned char *transaction_id,
int recvttl,struct sockaddr *recvaddr,int recvaddrlen,int parseP);
int packetOkOverlay(int interface,unsigned char *packet,int len,
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet,int len,
unsigned char *transaction_id,int recvttl,
struct sockaddr *recvaddr,int recvaddrlen,int parseP);
int prepareGateway(char *gatewayspec);
@ -509,254 +769,8 @@ int packetSendRequest(int method,unsigned char *packet,int packet_len,int batchP
struct response_set *responses);
int readArpTable(struct in_addr peers[],int *peer_count,int peer_max);
#define OVERLAY_MAX_INTERFACES 16
typedef struct overlay_address_table {
unsigned char epoch;
char sids[256][SID_SIZE];
/* 0x00 = not set, which thus limits us to using only 255 (0x01-0xff) of the indexes for
storing addresses.
By spending an extra 256 bytes we reduce, but not eliminate the problem of collisions.
Will think about a complete solution later.
*/
unsigned char byfirstbyte[256][2];
/* next free entry in sid[] */
unsigned char next_free;
} overlay_address_table;
typedef struct sid {
unsigned char b[SID_SIZE];
} sid;
typedef struct overlay_address_cache {
int size;
int shift; /* Used to calculat lookup function, which is (b[0].b[1].b[2]>>shift) */
sid *sids; /* one entry per bucket, to keep things simple. */
/* XXX Should have a means of changing the hash function so that naughty people can't try
to force our cache to flush with duplicate addresses?
But we must use only the first 24 bits of the address due to abbreviation policies,
so our options are limited.
For now the hash will be the first k bits.
*/
} overlay_address_cache;
extern sid overlay_abbreviate_current_sender;
typedef struct overlay_frame {
struct overlay_frame *prev;
struct overlay_frame *next;
unsigned int type;
unsigned int modifiers;
unsigned char ttl;
unsigned char dequeue;
/* Mark which interfaces the frame has been sent on,
so that we can ensure that broadcast frames get sent
exactly once on each interface */
int isBroadcast;
unsigned char broadcast_sent_via[OVERLAY_MAX_INTERFACES];
unsigned char nexthop[32];
int nexthop_address_status;
int nexthop_interface; /* which interface the next hop should be attempted on */
unsigned char destination[32];
int destination_address_status;
unsigned char source[32];
int source_address_status;
/* IPv4 node frame was received from (if applicable) */
struct sockaddr *recvaddr;
/* Frame content from destination address onwards */
int bytecount;
unsigned char *bytes;
/* Actual payload */
struct overlay_buffer *payload;
int rfs; /* remainder of frame size */
long long enqueued_at;
} overlay_frame;
int overlay_frame_process(int interface,overlay_frame *f);
int overlay_frame_resolve_addresses(int interface,overlay_frame *f);
#define CRYPT_CIPHERED 1
#define CRYPT_SIGNED 2
#define CRYPT_PUBLIC 4
extern int overlayMode;
#define OVERLAY_INTERFACE_UNKNOWN 0
#define OVERLAY_INTERFACE_ETHERNET 1
#define OVERLAY_INTERFACE_WIFI 2
#define OVERLAY_INTERFACE_PACKETRADIO 3
typedef struct overlay_interface {
char name[80];
int fd;
int offset;
int fileP;
int bits_per_second;
int port;
int type;
/* Number of milli-seconds per tick for this interface, which is basically related to the
the typical TX range divided by the maximum expected speed of nodes in the network.
This means that short-range communications has a higher bandwidth requirement than
long-range communications because the tick interval has to be shorter to still allow
fast-convergence time to allow for mobility.
For wifi (nominal range 100m) it is usually 500ms.
For ~100K ISM915MHz (nominal range 1000m) it will probably be about 5000ms.
For ~10K ISM915MHz (nominal range ~3000m) it will probably be about 15000ms.
These figures will be refined over time, and we will allow people to set them per-interface.
*/
int tick_ms; /* milliseconds per tick */
/* The time of the last tick on this interface in milli seconds */
long long last_tick_ms;
/* How many times have we abbreviated our address since we last announced it in full? */
int ticks_since_sent_full_address;
/* sequence number of last packet sent on this interface.
Used to allow NACKs that can request retransmission of recent packets.
*/
int sequence_number;
/* XXX need recent packet buffers to support the above */
/* Broadcast address and netmask, if known
We really only case about distinct broadcast addresses on interfaces.
Also simplifies aliases on interfaces. */
struct sockaddr_in broadcast_address;
/* Not necessarily the real MTU, but the largest frame size we are willing to TX on this interface.
For radio links the actual maximum and the maximum that is likely to be delivered reliably are
potentially two quite different values. */
int mtu;
/* If the interface still exists on the local machine.
If not, it we keep track of it for a few seconds before purging it, incase of flapping, e.g.,
due to DHCP renewal */
int observed;
} overlay_interface;
/* Maximum interface count is rather arbitrary.
Memory consumption is O(n) with respect to this parameter, so let's not make it too big for now.
*/
extern overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES];
extern int overlay_last_interface_number; // used to remember where a packet came from
extern unsigned int overlay_sequence_number;
/* Has someone sent us an abbreviation of an unknown type recently? If so remind them
that we don't accept these.
XXX - This method assumes bidirectional links. We should consider sending direct
to the perpetuator. We will deal with that in time, the main thing is that we have
a message type that can be used for the purpose.
*/
extern int overlay_interface_repeat_abbreviation_policy[OVERLAY_MAX_INTERFACES];
/*
For each peer we need to keep track of the routes that we know to reach it.
We want to use static sized data structures as much as we can to keep things efficient by
allowing computed memory address lookups instead of following linked lists and other
non-deterministic means.
The tricky part of doing all this is that each interface may have a different maximum number
of peers based on the bandwidth of the link, as we do not want mesh traffic to consume all
available bandwidth. In particular, we need to reserve at least enough bandwidth for one
call.
Related to this, if we are in a mesh larger than the per-interface limit allows, then we need to
only track the highest-scoring peers. This sounds simple, but how to we tell when to replace a
low-scoring peer with another one which has a better reachability score, if we are not tracking
the reachability score of that node?
The answer to this is that we track as many nodes as we can, but only announce the highest
scoring nodes on each interface as bandwidth allows.
This also keeps our memory usage fixed.
XXX - At present we are setting OVERLAY_MAX_PEERS at compile time.
With a bit of work we can change this to be a run-time option.
Memory consumption of OVERLAY_MAX_PEERS=n is O(n^2).
XXX We could and should improve this down the track by only monitoring the top k routes, and replacing the worst route
option when a better one comes along. This would get the memory usage down to O(n).
*/
#define OVERLAY_MAX_PEERS 500
typedef struct overlay_peer {
unsigned char address[SIDDIDFIELD_LEN];
/* Scores and score update times for reaching this node via various interfaces */
int known_routes[OVERLAY_MAX_INTERFACES];
unsigned short scores[OVERLAY_MAX_INTERFACES][OVERLAY_MAX_PEERS];
/* last_regeneration is the time that this peer was created/replaced with another peer.
lastupdate[] indicates the time that another peer's reachability report
caused us to update our score to reach via that peer.
If lastupdate[x][y] is older than last_regeneration[y], then we must
ignore the entry, because the lastupdate[x][y] entry references a previous
generation of that peer, i.e., not to the peer we think it does.
This slight convolution allows us to replace peers without having to touch the
records of every other peer in our list.
*/
int last_regeneration;
unsigned int lastupdate[OVERLAY_MAX_INTERFACES][OVERLAY_MAX_PEERS];
} overlay_peer;
extern overlay_peer overlay_peers[OVERLAY_MAX_PEERS];
typedef struct overlay_buffer {
unsigned char *bytes;
int length;
int allocSize;
int checkpointLength;
int sizeLimit;
int var_length_offset;
int var_length_bytes;
} overlay_buffer;
int ob_unlimitsize(overlay_buffer *b);
typedef struct overlay_txqueue {
struct overlay_frame *first;
struct overlay_frame *last;
int length; /* # frames in queue */
int maxLength; /* max # frames in queue before we consider ourselves congested */
/* Latency target in ms for this traffic class.
Frames older than the latency target will get dropped. */
int latencyTarget;
/* XXX Need to initialise these:
Real-time queue for voice (<200ms ?)
Real-time queue for video (<200ms ?) (lower priority than voice)
Ordinary service queue (<3 sec ?)
Rhizome opportunistic queue (infinity)
(Mesh management doesn't need a queue, as each overlay packet is tagged with some mesh management information)
*/
} overlay_txqueue;
#define OQ_ISOCHRONOUS_VOICE 0
#define OQ_MESH_MANAGEMENT 1
#define OQ_ISOCHRONOUS_VIDEO 2
#define OQ_ORDINARY 3
#define OQ_OPPORTUNISTIC 4
#define OQ_MAX 5
extern overlay_txqueue overlay_tx[OQ_MAX];
int overlay_frame_process(struct overlay_interface *interface,overlay_frame *f);
int overlay_frame_resolve_addresses(overlay_frame *f);
#define LOG_LEVEL_SILENT (-1)
#define LOG_LEVEL_DEBUG (0)
@ -826,11 +840,9 @@ long long parse_quantity(char *q);
int overlay_interface_init(char *name,struct sockaddr_in src_addr,struct sockaddr_in broadcast,
int speed_in_bits,int port,int type);
int overlay_interface_init_socket(int i,struct sockaddr_in src_addr,struct sockaddr_in broadcast);
int overlay_interface_discover();
int overlay_interface_discover();
long long overlay_time_until_next_tick();
int overlay_rx_messages();
int overlay_check_ticks();
int overlay_add_selfannouncement();
int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b);
int overlay_interface_args(const char *arg);
@ -900,7 +912,7 @@ extern unsigned char *overlay_local_identities[OVERLAY_MAX_LOCAL_IDENTITIES];
int overlay_abbreviate_address(unsigned char *in,unsigned char *out,int *ofs);
int overlay_abbreviate_append_address(overlay_buffer *b,unsigned char *a);
int overlay_abbreviate_expand_address(int interface,unsigned char *in,int *inofs,unsigned char *out,int *ofs);
int overlay_abbreviate_expand_address(unsigned char *in,int *inofs,unsigned char *out,int *ofs);
int overlay_abbreviate_cache_address(unsigned char *sid);
int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *ofs,
int prefix_bytes,int index_bytes);
@ -1012,10 +1024,10 @@ extern overlay_neighbour *overlay_neighbours;
long long overlay_gettime_ms();
int overlay_route_init(int mb_ram);
int overlay_route_saw_selfannounce_ack(int interface,overlay_frame *f,long long now);
int overlay_route_saw_selfannounce_ack(overlay_frame *f,long long now);
int overlay_route_recalc_node_metrics(overlay_node *n,long long now);
int overlay_route_recalc_neighbour_metrics(overlay_neighbour *n,long long now);
int overlay_route_saw_selfannounce(int interface,overlay_frame *f,long long now);
int overlay_route_saw_selfannounce(overlay_frame *f,long long now);
overlay_node *overlay_route_find_node(unsigned char *sid,int prefixLen,int createP);
unsigned int overlay_route_hash_sid(unsigned char *sid);
int overlay_route_init(int mb_ram);
@ -1040,10 +1052,9 @@ int overlay_route_record_link(long long now,unsigned char *to,
unsigned char *via,int sender_interface,
unsigned int s1,unsigned int s2,int score,int gateways_en_route);
int overlay_route_dump();
int overlay_route_tick();
int overlay_route_tick_neighbour(int neighbour_id,long long now);
int overlay_route_tick_node(int bin,int slot,long long now);
int overlay_route_add_advertisements(int interface,overlay_buffer *e);
int overlay_route_add_advertisements(overlay_buffer *e);
int ovleray_route_please_advertise(overlay_node *n);
int overlay_abbreviate_set_current_sender(unsigned char *in);
@ -1056,9 +1067,8 @@ int overlay_route_saw_advertisements(int i,overlay_frame *f, long long now);
int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now);
int overlay_route_please_advertise(overlay_node *n);
int rhizome_server_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int rhizome_server_poll();
int rhizome_saw_voice_traffic();
int overlay_saw_mdp_containing_frame(int interface,overlay_frame *f,long long now);
int overlay_saw_mdp_containing_frame(overlay_frame *f,long long now);
#include "nacl.h"
@ -1096,7 +1106,6 @@ int overlay_address_is_broadcast(unsigned char *a);
int overlay_broadcast_generate_address(unsigned char *a);
int overlay_abbreviate_unset_current_sender();
int rhizome_fetching_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int rhizome_fetch_poll();
int rhizome_opendb();
typedef struct dna_identity_status {
@ -1160,12 +1169,11 @@ int mkdirsn(const char *path, size_t len, mode_t mode);
#define FORM_SERVAL_INSTANCE_PATH(buf, path) (form_serval_instance_path(buf, sizeof(buf), (path)))
int overlay_mdp_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int overlay_mdp_poll();
int overlay_mdp_reply_error(int sock,
struct sockaddr_un *recvaddr,int recvaddrlen,
int error_number,char *message);
extern int mdp_abstract_socket;
extern int mdp_named_socket;
extern struct sched_ent mdp_abstract;
extern struct sched_ent mdp_named;
typedef struct sockaddr_mdp {
@ -1321,7 +1329,7 @@ int overlay_mdp_recv(overlay_mdp_frame *mdp,int *ttl);
int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms);
/* Server-side MDP functions */
int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now);
int overlay_saw_mdp_frame(overlay_mdp_frame *mdp,long long now);
int overlay_mdp_swap_src_dst(overlay_mdp_frame *mdp);
int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr,int recvaddrlen,
overlay_mdp_frame *mdpreply);
@ -1431,7 +1439,6 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
int vomp_mdp_received(overlay_mdp_frame *mdp);
char *vomp_describe_state(int state);
char *vomp_describe_codec(int c);
int vomp_tick();
int vomp_tick_interval();
int vomp_sample_size(int c);
int vomp_codec_timespan(int c);
@ -1480,7 +1487,6 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int monitor_setup_sockets();
int monitor_poll();
int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int monitor_call_status(vomp_call_state *call);
int monitor_send_audio(vomp_call_state *call,overlay_mdp_frame *audio);
@ -1542,3 +1548,41 @@ void sigIoHandler(int signal);
#define WRITE_STR(fd, str) write(fd, str, strlen(str))
int rhizome_http_server_start();
int overlay_mdp_setup_sockets();
int schedule(struct sched_ent *alarm);
int unschedule(struct sched_ent *alarm);
int watch(struct sched_ent *alarm);
int unwatch(struct sched_ent *alarm);
int fd_poll();
void overlay_interface_discover(struct sched_ent *alarm);
void overlay_check_ticks(struct sched_ent *alarm);
void overlay_dummy_poll(struct sched_ent *alarm);
void overlay_route_tick(struct sched_ent *alarm);
void rhizome_enqueue_suggestions(struct sched_ent *alarm);
void server_shutdown_check(struct sched_ent *alarm);
void overlay_mdp_poll(struct sched_ent *alarm);
void fd_periodicstats(struct sched_ent *alarm);
void vomp_tick(struct sched_ent *alarm);
void rhizome_check_connections(struct sched_ent *alarm);
void monitor_client_poll(struct sched_ent *alarm);
void monitor_poll(struct sched_ent *alarm);
void overlay_interface_poll(struct sched_ent *alarm);
void rhizome_client_poll(struct sched_ent *alarm);
void rhizome_fetch_poll(struct sched_ent *alarm);
void rhizome_server_poll(struct sched_ent *alarm);
/* function timing routines */
int fd_checkalarms();
int fd_func_exit(struct call_stats *this_call, struct profile_total *call_stats);
int fd_func_enter(struct call_stats *this_call);
#define IN() static struct profile_total _aggregate_stats={NULL,0,__FUNCTION__,0,0,0}; struct call_stats _this_call; fd_func_enter(&_this_call);
#define OUT() fd_func_exit(&_this_call, &_aggregate_stats);
#define RETURN(X) { OUT() return(X); }
#define SET_NONBLOCKING(X) fcntl(X,F_SETFL,fcntl(X, F_GETFL, NULL)|O_NONBLOCK);
#define SET_BLOCKING(X) fcntl(X,F_SETFL,fcntl(X, F_GETFL, NULL)&(~O_NONBLOCK));

101
server.c
View File

@ -48,7 +48,6 @@ int client_port;
void signal_handler(int signal);
int getKeyring(char *s);
int createServerSocket();
int simpleServerMode();
int recvwithttl(int sock,unsigned char *buffer,int bufferlen,int *ttl,
struct sockaddr *recvaddr,unsigned int *recvaddrlen)
@ -72,8 +71,6 @@ int recvwithttl(int sock,unsigned char *buffer,int bufferlen,int *ttl,
msg.msg_controllen = sizeof(struct cmsghdr)*16;
msg.msg_flags = 0;
fcntl(sock,F_SETFL, O_NONBLOCK);
int len = recvmsg(sock,&msg,0);
if (0&&debug&DEBUG_PACKETRX) {
@ -187,20 +184,7 @@ int server(char *backing_file)
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
if (overlayMode)
{
/* Now find and initialise all the suitable network interfaces, i.e.,
those running IPv4.
Packet radio dongles will get discovered later as the interfaces get probed.
This will setup the sockets for the server to communicate on each interface.
XXX - Problems may persist where the same address is used on multiple interfaces,
but otherwise hopefully it will allow us to bridge multiple networks.
*/
overlay_interface_discover();
}
else
if (!overlayMode)
{
/* Create a simple socket for listening on if we are not in overlay mesh mode. */
createServerSocket();
@ -223,15 +207,14 @@ int server(char *backing_file)
fprintf(f,"%d\n", server_getpid);
fclose(f);
if (!overlayMode) simpleServerMode();
else overlayServerMode();
overlayServerMode();
return 0;
}
/* Called periodically by the server process in its main loop.
*/
void server_shutdown_check()
void server_shutdown_check(struct sched_ent *alarm)
{
if (servalShutdown) {
INFO("Shutdown flag set -- terminating with cleanup");
@ -255,6 +238,10 @@ void server_shutdown_check()
exit(1);
}
}
if (alarm){
alarm->alarm = overlay_gettime_ms()+1000;
schedule(alarm);
}
}
int server_create_stopfile()
@ -433,7 +420,7 @@ void signal_handler(int signal)
/* Terminate the server process. The shutting down should be done from the main-line code
rather than here, so we first try to tell the mainline code to do so. If, however, this is
not the first time we have been asked to shut down, then we will do it here. */
server_shutdown_check();
server_shutdown_check(NULL);
WHY("Asking Serval process to shutdown cleanly");
servalShutdown = 1;
return;
@ -443,8 +430,8 @@ void signal_handler(int signal)
if (sock>-1) close(sock);
int i;
for(i=0;i<overlay_interface_count;i++)
if (overlay_interfaces[i].fd>-1)
close(overlay_interfaces[i].fd);
if (overlay_interfaces[i].alarm.poll.fd>-1)
close(overlay_interfaces[i].alarm.poll.fd);
execv(exec_args[0],exec_args);
/* Quit if the exec() fails */
exit(-3);
@ -824,74 +811,6 @@ int createServerSocket()
return 0;
}
extern int sigIoFlag;
int simpleServerMode()
{
while(1) {
struct sockaddr recvaddr;
socklen_t recvaddrlen=sizeof(recvaddr);
struct pollfd fds[128];
int fdcount;
int len;
int r;
server_shutdown_check();
bzero((void *)&recvaddr,sizeof(recvaddr));
/* 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_server_poll();
/* Get list of file descripters to watch */
fds[0].fd=sock; fds[0].events=POLLIN;
fdcount=1;
rhizome_server_get_fds(fds,&fdcount,128);
if (debug&DEBUG_IO) {
strbuf b = strbuf_alloca(fdcount * 6);
int i;
for (i = 0;i < fdcount; ++i)
strbuf_sprintf(b, " %d", fds[i].fd);
DEBUGF("poll()ing file descriptors: %s", strbuf_str(b));
}
/* Wait patiently for packets to arrive. */
if (rhizome_enabled()) rhizome_server_poll();
while ((r=poll(fds,fdcount,100000))<1) {
if (sigIoFlag) { sigIoFlag=0; break; }
sleep(0);
}
if (rhizome_enabled()) rhizome_server_poll();
unsigned char buffer[16384];
int ttl=-1; // unknown
if (fds[0].revents&POLLIN) {
len=recvwithttl(sock,buffer,sizeof(buffer),&ttl,&recvaddr,&recvaddrlen);
client_port=((struct sockaddr_in*)&recvaddr)->sin_port;
client_addr=((struct sockaddr_in*)&recvaddr)->sin_addr;
if (debug&DEBUG_DNAREQUESTS) DEBUGF("Received packet from %s:%d (len=%d)",inet_ntoa(client_addr),client_port,len);
if (debug&DEBUG_PACKETRX) dump("recvaddr",(unsigned char *)&recvaddr,recvaddrlen);
if (debug&DEBUG_PACKETRX) dump("packet",(unsigned char *)buffer,len);
if (dropPacketP(len)) {
if (debug&DEBUG_SIMULATION) DEBUG("Simulation mode: Dropped packet due to simulated link parameters.");
continue;
}
/* Simple server mode doesn't really use interface numbers, so lie and say interface -1 */
if (packetOk(-1,buffer,len,NULL,ttl,&recvaddr,recvaddrlen,1)) {
if (debug&DEBUG_PACKETFORMATS) DEBUG("Ignoring invalid packet");
}
if (debug&DEBUG_PACKETRX) DEBUG("Finished processing packet, waiting for next one.");
}
}
return 0;
}
#ifdef DEBUG_MEM_ABUSE
unsigned char groundzero[65536];
int memabuseInitP=0;

View File

@ -36,9 +36,9 @@ setup_servald_instance() {
push_instance
set_instance "$1"
executeOk_servald config set debug.interfaces Yes
executeOk_servald config set debug.packetformats No
executeOk_servald config set debug.tx No
executeOk_servald config set debug.rx No
executeOk_servald config set debug.packetformats Yes
executeOk_servald config set debug.tx Yes
executeOk_servald config set debug.rx Yes
executeOk_servald config set interfaces "+>$2"
executeOk_servald config set monitor.socket "org.servalproject.servald.monitor.socket.$TFWUNIQUE.$instance_name"
executeOk_servald config set mdp.socket "org.servalproject.servald.mdp.socket.$TFWUNIQUE.$instance_name"
@ -65,7 +65,7 @@ setup_servald_instances() {
setup_servald_instance +B $DUMMYNET
SIDB=$sid
# Now make sure that they can see each other
secs=0.5
secs=5
sleep $secs # Should be plenty of time
tfw_log "# Dummynet file after $secs seconds: "`ls -l $DUMMYNET`
set_instance +A

52
vomp.c
View File

@ -321,7 +321,7 @@ int vomp_send_status(vomp_call_state *call,int flags,overlay_mdp_frame *arg)
long long now=overlay_gettime_ms();
for(i=0;i<vomp_interested_usock_count;i++)
if (vomp_interested_expiries[i]>=now) {
overlay_mdp_reply(mdp_named_socket,
overlay_mdp_reply(mdp_named.poll.fd,
vomp_interested_usocks[i],
vomp_interested_usock_lengths[i],
&mdp);
@ -415,6 +415,7 @@ int vomp_call_destroy(vomp_call_state *call)
call->local.did,call->remote.did);
/* tell everyone the call has died */
call->local.state=VOMP_STATE_CALLENDED; call->remote.state=VOMP_STATE_CALLENDED;
vomp_send_status(call,VOMP_TELLREMOTE|VOMP_TELLINTERESTED,NULL);
/* now release the call structure */
@ -474,7 +475,7 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
if (!memcmp(recvaddr->sun_path,
vomp_interested_usocks[i],recvaddrlen))
/* found it -- so we are already monitoring this one */
return overlay_mdp_reply_error(mdp_named_socket,recvaddr,recvaddrlen,
return overlay_mdp_reply_error(mdp_named.poll.fd,recvaddr,recvaddrlen,
0,"Success");
if (vomp_interested_expiries[i]<now) candidate=i;
}
@ -487,7 +488,7 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
}
vomp_interested_usocks[i]=malloc(recvaddrlen);
if (!vomp_interested_usocks[i])
return overlay_mdp_reply_error(mdp_named_socket, recvaddr,recvaddrlen,
return overlay_mdp_reply_error(mdp_named.poll.fd, recvaddr,recvaddrlen,
4002,"Out of memory");
bcopy(recvaddr,vomp_interested_usocks[i],
recvaddrlen);
@ -505,10 +506,10 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
}
return overlay_mdp_reply_error
(mdp_named_socket,recvaddr,recvaddrlen,0,"Success");
(mdp_named.poll.fd,recvaddr,recvaddrlen,0,"Success");
} else {
return overlay_mdp_reply_error
(mdp_named_socket,recvaddr,recvaddrlen,
(mdp_named.poll.fd,recvaddr,recvaddrlen,
4003,"Too many listeners (try again in a minute?)");
}
}
@ -536,12 +537,12 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
}
vomp_interested_usock_count--;
return overlay_mdp_reply_error
(mdp_named_socket,recvaddr,recvaddrlen,
(mdp_named.poll.fd,recvaddr,recvaddrlen,
0,"Success. You have been removed.");
}
}
return overlay_mdp_reply_error
(mdp_named_socket,recvaddr,recvaddrlen,
(mdp_named.poll.fd,recvaddr,recvaddrlen,
0,"Success. You were never listening.");
}
break;
@ -585,7 +586,7 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
}
}
return overlay_mdp_reply(mdp_named_socket,recvaddr,recvaddrlen,&mdpreply);
return overlay_mdp_reply(mdp_named.poll.fd,recvaddr,recvaddrlen,&mdpreply);
}
break;
case VOMPEVENT_DIAL:
@ -593,12 +594,12 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
These need to be passed to the node being called to provide caller id,
and potentially handle call-routing, e.g., if it is a gateway.
*/
fprintf(stderr,"DIAL Request!\n");
DEBUG("DIAL Request!\n");
{
/* Populate call structure */
if (vomp_call_count>=VOMP_MAX_CALLS)
return overlay_mdp_reply_error
(mdp_named_socket,recvaddr,recvaddrlen,4004,
(mdp_named.poll.fd,recvaddr,recvaddrlen,4004,
"All call slots in use");
int slot=vomp_call_count++;
vomp_call_state *call=&vomp_call_states[slot];
@ -618,10 +619,10 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
{
if (urandombytes((unsigned char *)&call->local.session,sizeof(int)))
return overlay_mdp_reply_error
(mdp_named_socket,recvaddr,recvaddrlen,4005,
(mdp_named.poll.fd,recvaddr,recvaddrlen,4005,
"Insufficient entropy");
call->local.session&=VOMP_SESSION_MASK;
printf("session=0x%08x\n",call->local.session);
DEBUGF("session=0x%08x\n",call->local.session);
int i;
for(i=0;i<vomp_call_count;i++)
if (i!=slot)
@ -638,7 +639,7 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
WHY("sending MDP reply back");
dump("recvaddr",(unsigned char *)recvaddr,recvaddrlen);
int result= overlay_mdp_reply_error
(mdp_named_socket,recvaddr,recvaddrlen,0, "Success");
(mdp_named.poll.fd,recvaddr,recvaddrlen,0, "Success");
if (result) WHY("Failed to send MDP reply");
return result;
}
@ -650,12 +651,12 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
=vomp_find_call_by_session(mdp->vompevent.call_session_token);
if (!call)
return overlay_mdp_reply_error
(mdp_named_socket,recvaddr,recvaddrlen,4006,
(mdp_named.poll.fd,recvaddr,recvaddrlen,4006,
"No such call");
if (call->local.state==VOMP_STATE_INCALL) vomp_call_stop_audio(call);
call->local.state=VOMP_STATE_CALLENDED;
monitor_call_status(call);
overlay_mdp_reply_error(mdp_named_socket,
overlay_mdp_reply_error(mdp_named.poll.fd,
recvaddr,recvaddrlen,0,"Success");
return vomp_send_status(call,VOMP_TELLREMOTE|VOMP_TELLINTERESTED,NULL);
}
@ -667,7 +668,7 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
=vomp_find_call_by_session(mdp->vompevent.call_session_token);
if (!call)
return overlay_mdp_reply_error
(mdp_named_socket,recvaddr,recvaddrlen,4006,
(mdp_named.poll.fd,recvaddr,recvaddrlen,4006,
"No such call");
if (call->local.state==VOMP_STATE_RINGINGIN) {
call->local.state=VOMP_STATE_INCALL;
@ -675,11 +676,11 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
call->ringing=0;
/* state machine does job of starting audio stream, just tell everyone about
the changed state. */
overlay_mdp_reply_error(mdp_named_socket,
overlay_mdp_reply_error(mdp_named.poll.fd,
recvaddr,recvaddrlen,0,"Success");
return vomp_send_status(call,VOMP_TELLREMOTE|VOMP_TELLINTERESTED,NULL);
} else {
overlay_mdp_reply_error(mdp_named_socket,
overlay_mdp_reply_error(mdp_named.poll.fd,
recvaddr,recvaddrlen,4009,
"Call is not RINGINGIN, so cannot be picked up");
}
@ -699,7 +700,7 @@ int vomp_mdp_event(overlay_mdp_frame *mdp,
break;
default:
/* didn't understand it, so respond with an error */
return overlay_mdp_reply_error(mdp_named_socket,
return overlay_mdp_reply_error(mdp_named.poll.fd,
recvaddr,recvaddrlen,4001,
"Invalid VOMPEVENT request (use DIAL,HANGUP,CALLREJECT,AUDIOSTREAMING,REGISTERINTERST,WITHDRAWINTERST only)");
@ -1457,7 +1458,7 @@ int app_vomp_monitor(int argc, const char *const *argv, struct command_line_opti
return overlay_mdp_client_done();
}
int vomp_tick()
void vomp_tick(struct sched_ent *alarm)
{
/* Send any reminder packets for call state, and also process any audio. */
unsigned long long now=overlay_gettime_ms();
@ -1507,12 +1508,9 @@ int vomp_tick()
i--;
break;
}
}
return 0;
}
alarm->alarm = overlay_gettime_ms()+1000;
schedule(alarm);
return;
}
int vomp_tick_interval()
{
/* Work out the number of milliseconds until the next vomp tick is required. */
return 1000;
}