mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-18 02:39:44 +00:00
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:
commit
8020ea3b74
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
2
client.c
2
client.c
@ -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");
|
||||
|
@ -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
191
fdqueue.c
Normal 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;
|
||||
}
|
50
keyring.c
50
keyring.c
@ -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
1
lsif.c
@ -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 */
|
||||
|
@ -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
456
monitor.c
@ -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
271
overlay.c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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)
|
||||
|
499
overlay_mdp.c
499
overlay_mdp.c
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
208
performance_timing.c
Normal 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;
|
||||
}
|
||||
|
64
rhizome.h
64
rhizome.h
@ -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();
|
||||
|
||||
|
@ -42,6 +42,7 @@ int rhizome_manifest_verify(rhizome_manifest *m)
|
||||
}
|
||||
|
||||
if (m->sig_count==0) {
|
||||
WHYF("Manifest has zero valid signatures");
|
||||
m->errors++;
|
||||
}
|
||||
|
||||
|
137
rhizome_crypto.c
137
rhizome_crypto.c
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
630
rhizome_fetch.c
630
rhizome_fetch.c
@ -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;
|
||||
}
|
||||
|
564
rhizome_http.c
564
rhizome_http.c
@ -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;
|
||||
|
@ -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
598
serval.h
@ -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
101
server.c
@ -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;
|
||||
|
@ -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
52
vomp.c
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user