2012-01-12 03:38:24 +00:00
|
|
|
/*
|
|
|
|
Serval Distributed Numbering Architecture (DNA)
|
|
|
|
Copyright (C) 2010 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.
|
|
|
|
*/
|
|
|
|
|
2012-02-23 02:15:42 +00:00
|
|
|
#include "serval.h"
|
2012-01-12 03:38:24 +00:00
|
|
|
#include "rhizome.h"
|
2012-08-27 02:41:06 +00:00
|
|
|
#include <assert.h>
|
2012-01-12 03:38:24 +00:00
|
|
|
#include <stdlib.h>
|
2012-10-02 13:56:21 +00:00
|
|
|
#include <math.h>
|
2012-09-05 09:23:22 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2012-01-12 03:38:24 +00:00
|
|
|
|
|
|
|
int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar)
|
|
|
|
{
|
2012-06-26 06:32:49 +00:00
|
|
|
IN();
|
2012-01-12 03:38:24 +00:00
|
|
|
/* 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
|
|
|
|
bundles.
|
|
|
|
|
2012-10-02 09:54:35 +00:00
|
|
|
Old BAR format (no longer used):
|
|
|
|
|
2012-01-12 03:38:24 +00:00
|
|
|
64 bits - manifest ID prefix.
|
|
|
|
56 bits - low 56 bits of version number.
|
|
|
|
8 bits - TTL of bundle in hops.
|
|
|
|
64 bits - length of associated file.
|
|
|
|
16 bits - min latitude (-90 - +90).
|
|
|
|
16 bits - min longitude (-180 - +180).
|
|
|
|
16 bits - max latitude (-90 - +90).
|
|
|
|
16 bits - max longitude (-180 - +180).
|
2012-10-02 09:54:35 +00:00
|
|
|
|
|
|
|
New BAR format with longer manifest ID prefix:
|
|
|
|
|
|
|
|
120 bits - manifest ID prefix.
|
|
|
|
8 bits - log2(length) of associated file.
|
|
|
|
56 bits - low 56 bits of version number.
|
|
|
|
16 bits - min latitude (-90 - +90).
|
|
|
|
16 bits - min longitude (-180 - +180).
|
|
|
|
16 bits - max latitude (-90 - +90).
|
|
|
|
16 bits - max longitude (-180 - +180).
|
|
|
|
8 bits - TTL of bundle in hops (0xff = unlimited distribution)
|
|
|
|
|
2012-01-12 03:38:24 +00:00
|
|
|
*/
|
|
|
|
|
2012-06-26 06:32:49 +00:00
|
|
|
if (!m) { RETURN(WHY("null manifest passed in")); }
|
2012-01-12 03:38:24 +00:00
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Manifest prefix */
|
2012-10-02 09:54:35 +00:00
|
|
|
for(i=0;i<RHIZOME_BAR_PREFIX_BYTES;i++)
|
|
|
|
bar[RHIZOME_BAR_PREFIX_OFFSET+i]=m->cryptoSignPublic[i];
|
2012-01-12 03:38:24 +00:00
|
|
|
/* file length */
|
2012-10-02 09:54:35 +00:00
|
|
|
bar[RHIZOME_BAR_FILESIZE_OFFSET]=log2(m->fileLength);
|
|
|
|
/* Version */
|
|
|
|
for(i=0;i<7;i++) bar[RHIZOME_BAR_VERSION_OFFSET+6-i]=(m->version>>(8*i))&0xff;
|
|
|
|
|
2012-01-12 03:38:24 +00:00
|
|
|
/* geo bounding box */
|
|
|
|
double minLat=rhizome_manifest_get_double(m,"min_lat",-90);
|
|
|
|
if (minLat<-90) minLat=-90; if (minLat>90) minLat=90;
|
|
|
|
double minLong=rhizome_manifest_get_double(m,"min_long",-180);
|
|
|
|
if (minLong<-180) minLong=-180; if (minLong>180) minLong=180;
|
|
|
|
double maxLat=rhizome_manifest_get_double(m,"max_lat",+90);
|
|
|
|
if (maxLat<-90) maxLat=-90; if (maxLat>90) maxLat=90;
|
|
|
|
double maxLong=rhizome_manifest_get_double(m,"max_long",+180);
|
2012-10-02 09:54:35 +00:00
|
|
|
if (maxLong<-180) maxLong=-180; if (maxLong>180) maxLong=180;
|
2012-01-12 03:38:24 +00:00
|
|
|
unsigned short v;
|
2012-10-02 09:54:35 +00:00
|
|
|
int o=RHIZOME_BAR_GEOBOX_OFFSET;
|
|
|
|
v=(minLat+90)*(65535/180); bar[o++]=(v>>8)&0xff; bar[o++]=(v>>0)&0xff;
|
|
|
|
v=(minLong+180)*(65535/360); bar[o++]=(v>>8)&0xff; bar[o++]=(v>>0)&0xff;
|
|
|
|
v=(maxLat+90)*(65535/180); bar[o++]=(v>>8)&0xff; bar[o++]=(v>>0)&0xff;
|
|
|
|
v=(maxLong+180)*(65535/360); bar[o++]=(v>>8)&0xff; bar[o++]=(v>>0)&0xff;
|
|
|
|
|
|
|
|
/* TTL */
|
|
|
|
if (m->ttl>0) bar[RHIZOME_BAR_TTL_OFFSET]=m->ttl-1;
|
|
|
|
else bar[RHIZOME_BAR_TTL_OFFSET]=0;
|
2012-01-12 03:38:24 +00:00
|
|
|
|
2012-06-26 06:32:49 +00:00
|
|
|
RETURN(0);
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
|
|
|
|
2012-09-14 04:10:14 +00:00
|
|
|
long long rhizome_bar_version(unsigned char *bar)
|
|
|
|
{
|
|
|
|
long long version=0;
|
|
|
|
int i;
|
|
|
|
// for(i=0;i<7;i++) bar[8+6-i]=(m->version>>(8*i))&0xff;
|
2012-10-02 09:54:35 +00:00
|
|
|
for(i=0;i<7;i++) version|=bar[RHIZOME_BAR_VERSION_OFFSET+6-i]<<(8LL*i);
|
2012-09-14 04:10:14 +00:00
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
2012-10-02 09:54:35 +00:00
|
|
|
/* This function only displays the first 8 bytes, and should not be used
|
|
|
|
for comparison. */
|
|
|
|
unsigned long long rhizome_bar_bidprefix_ll(unsigned char *bar)
|
2012-09-21 11:41:27 +00:00
|
|
|
{
|
|
|
|
long long bidprefix=0;
|
|
|
|
int i;
|
2012-10-02 09:54:35 +00:00
|
|
|
for(i=0;i<8;i++)
|
|
|
|
bidprefix|=((unsigned long long)bar[RHIZOME_BAR_PREFIX_OFFSET+7-i])<<(8*i);
|
2012-09-21 11:41:27 +00:00
|
|
|
return bidprefix;
|
|
|
|
}
|
|
|
|
|
2012-01-12 03:38:24 +00:00
|
|
|
int bundles_available=-1;
|
|
|
|
int bundle_offset[2]={0,0};
|
|
|
|
int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e)
|
|
|
|
{
|
2012-06-26 06:32:49 +00:00
|
|
|
IN();
|
2012-05-22 03:35:29 +00:00
|
|
|
int voice_mode=0;
|
|
|
|
|
|
|
|
/* behave differently during voice mode.
|
|
|
|
Basically don't encourage people to grab stuff from us, but keep
|
|
|
|
just enough activity going so that it is possible to send a (small)
|
|
|
|
message/file during a call.
|
|
|
|
|
|
|
|
XXX Eventually only advertise small/recently changed files during voice calls.
|
|
|
|
We need to change manifest table to include payload length to make our life
|
|
|
|
easy here (also would let us order advertisements by size of payload).
|
|
|
|
For now, we will just advertised only occassionally.
|
2012-09-07 22:25:32 +00:00
|
|
|
|
|
|
|
XXX Actually, we will move all processing of Rhizome into a separate process
|
|
|
|
so that the CPU delays caused by Rhizome verifying signatures isn't a problem.
|
|
|
|
We will still want to limit network usage during calls, however.
|
2012-05-22 03:35:29 +00:00
|
|
|
*/
|
2012-08-09 02:44:32 +00:00
|
|
|
time_ms_t now = gettime_ms();
|
2012-05-22 03:35:29 +00:00
|
|
|
if (now<rhizome_voice_timeout) voice_mode=1;
|
2012-06-26 06:32:49 +00:00
|
|
|
if (voice_mode) if (random()&3) { RETURN(0); }
|
2012-05-22 03:35:29 +00:00
|
|
|
|
2012-01-12 03:38:24 +00:00
|
|
|
int pass;
|
|
|
|
int bytes=e->sizeLimit-e->length;
|
2012-07-02 06:37:35 +00:00
|
|
|
int overhead=1+11+1+2+2; /* maximum overhead */
|
2012-01-12 03:38:24 +00:00
|
|
|
int slots=(bytes-overhead)/RHIZOME_BAR_BYTES;
|
|
|
|
if (slots>30) slots=30;
|
|
|
|
int slots_used=0;
|
|
|
|
int bytes_used=0;
|
|
|
|
int bytes_available=bytes-overhead-1 /* one byte held for expanding RFS */;
|
|
|
|
int bundles_advertised=0;
|
|
|
|
|
2012-06-26 06:32:49 +00:00
|
|
|
if (slots<1) { RETURN(WHY("No room for node advertisements")); }
|
2012-01-12 03:38:24 +00:00
|
|
|
|
2012-06-26 06:32:49 +00:00
|
|
|
if (!rhizome_db) { RETURN(WHY("Rhizome not enabled")); }
|
2012-01-12 03:38:24 +00:00
|
|
|
|
|
|
|
if (ob_append_byte(e,OF_TYPE_RHIZOME_ADVERT))
|
2012-07-03 00:56:22 +00:00
|
|
|
RETURN(WHY("could not add rhizome bundle advertisement header"));
|
2012-07-02 06:37:35 +00:00
|
|
|
ob_append_byte(e, 1); /* TTL (1 byte) */
|
2012-06-25 08:33:00 +00:00
|
|
|
|
2012-07-12 00:50:13 +00:00
|
|
|
ob_append_rfs(e,1+11+1+2+RHIZOME_BAR_BYTES*slots_used/* RFS */);
|
2012-01-12 03:38:24 +00:00
|
|
|
|
2012-07-02 06:37:35 +00:00
|
|
|
/* Stuff in dummy address fields (11 bytes) */
|
2012-01-12 03:38:24 +00:00
|
|
|
ob_append_byte(e,OA_CODE_BROADCAST);
|
|
|
|
{ int i; for(i=0;i<8;i++) ob_append_byte(e,random()&0xff); } /* BPI for broadcast */
|
|
|
|
ob_append_byte(e,OA_CODE_PREVIOUS);
|
2012-07-17 06:00:50 +00:00
|
|
|
overlay_abbreviate_clear_most_recent_address();
|
|
|
|
overlay_abbreviate_append_address(e, overlay_get_my_sid());
|
2012-01-12 03:38:24 +00:00
|
|
|
|
|
|
|
/* Randomly choose whether to advertise manifests or BARs first. */
|
|
|
|
int skipmanifests=random()&1;
|
2012-07-02 06:37:35 +00:00
|
|
|
/* Version of rhizome advert block (1 byte):
|
2012-01-12 03:38:24 +00:00
|
|
|
1 = manifests then BARs,
|
2012-07-02 06:37:35 +00:00
|
|
|
2 = BARs only,
|
|
|
|
3 = HTTP port then manifests then BARs,
|
|
|
|
4 = HTTP port then BARs only
|
|
|
|
*/
|
|
|
|
ob_append_byte(e,3+skipmanifests);
|
|
|
|
/* Rhizome HTTP server port number (2 bytes) */
|
2012-07-12 02:40:59 +00:00
|
|
|
ob_append_short(e, rhizome_http_server_port);
|
2012-01-12 03:38:24 +00:00
|
|
|
|
|
|
|
/* XXX Should add priority bundles here.
|
|
|
|
XXX Should prioritise bundles for subscribed groups, Serval-authorised files
|
|
|
|
etc over common bundles.
|
|
|
|
XXX Should wait a while after going through bundle list so that we don't waste
|
|
|
|
CPU on db queries if there are not many bundles. Actually, we probably just
|
|
|
|
shouldn't be sending bundles blindly on every tick.
|
|
|
|
XXX How do we indicate group membership with BARs? Or do groups actively poll?
|
2012-02-09 06:40:52 +00:00
|
|
|
|
|
|
|
XXX XXX XXX We should cache database results so that we don't waste all our time
|
|
|
|
and energy asking the database much the same questions possibly many times per
|
|
|
|
second.
|
2012-01-12 03:38:24 +00:00
|
|
|
*/
|
2012-06-08 03:43:26 +00:00
|
|
|
|
|
|
|
// TODO Group handling not completely thought out here yet.
|
2012-01-12 03:38:24 +00:00
|
|
|
|
2012-08-24 05:56:25 +00:00
|
|
|
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
|
|
|
|
|
2012-01-12 03:38:24 +00:00
|
|
|
/* Get number of bundles available if required */
|
2012-06-08 03:43:26 +00:00
|
|
|
long long tmp = 0;
|
2012-08-24 05:56:25 +00:00
|
|
|
if (sqlite_exec_int64_retry(&retry, &tmp, "SELECT COUNT(BAR) FROM MANIFESTS;") != 1)
|
2012-06-26 06:32:49 +00:00
|
|
|
{ RETURN(WHY("Could not count BARs for advertisement")); }
|
2012-06-08 03:43:26 +00:00
|
|
|
bundles_available = (int) tmp;
|
2012-01-12 03:38:24 +00:00
|
|
|
if (bundles_available==-1||(bundle_offset[0]>=bundles_available))
|
|
|
|
bundle_offset[0]=0;
|
|
|
|
if (bundles_available==-1||(bundle_offset[1]>=bundles_available))
|
|
|
|
bundle_offset[1]=0;
|
2012-05-27 20:53:20 +00:00
|
|
|
if(0)
|
2012-05-24 07:41:55 +00:00
|
|
|
DEBUGF("%d bundles in database (%d %d), slots=%d.",bundles_available,
|
2012-05-27 20:53:20 +00:00
|
|
|
bundle_offset[0],bundle_offset[1],slots);
|
2012-01-12 03:38:24 +00:00
|
|
|
|
2012-05-17 01:43:29 +00:00
|
|
|
sqlite3_stmt *statement=NULL;
|
|
|
|
sqlite3_blob *blob=NULL;
|
|
|
|
|
2012-08-24 05:56:25 +00:00
|
|
|
for(pass=skipmanifests;pass<2;pass++) {
|
|
|
|
switch(pass) {
|
|
|
|
case 0: /* Full manifests */
|
|
|
|
statement = sqlite_prepare("SELECT MANIFEST,ROWID FROM MANIFESTS LIMIT %d,%d", bundle_offset[pass], slots);
|
|
|
|
break;
|
|
|
|
case 1: /* BARs */
|
|
|
|
statement = sqlite_prepare("SELECT BAR,ROWID FROM MANIFESTS LIMIT %d,%d", bundle_offset[pass], slots);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!statement)
|
|
|
|
RETURN(WHY("Could not prepare sql statement for fetching BARs for advertisement"));
|
|
|
|
while( bytes_used < bytes_available
|
|
|
|
&& sqlite_step_retry(&retry, statement) == SQLITE_ROW
|
|
|
|
&& e->length + RHIZOME_BAR_BYTES <= e->sizeLimit
|
|
|
|
) {
|
|
|
|
int column_type=sqlite3_column_type(statement, 0);
|
|
|
|
switch(column_type) {
|
|
|
|
case SQLITE_BLOB:
|
|
|
|
if (blob)
|
|
|
|
sqlite3_blob_close(blob);
|
|
|
|
blob = NULL;
|
|
|
|
int ret;
|
|
|
|
int64_t rowid = sqlite3_column_int64(statement, 1);
|
|
|
|
do ret = sqlite3_blob_open(rhizome_db, "main", "manifests", pass?"bar":"manifest", rowid, 0 /* read only */, &blob);
|
|
|
|
while (sqlite_code_busy(ret) && sqlite_retry(&retry, "sqlite3_blob_open"));
|
|
|
|
if (!sqlite_code_ok(ret)) {
|
|
|
|
WHYF("sqlite3_blob_open() failed, %s", sqlite3_errmsg(rhizome_db));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
sqlite_retry_done(&retry, "sqlite3_blob_open");
|
|
|
|
|
|
|
|
int blob_bytes=sqlite3_blob_bytes(blob);
|
|
|
|
if (pass&&(blob_bytes!=RHIZOME_BAR_BYTES)) {
|
|
|
|
if (debug&DEBUG_RHIZOME)
|
|
|
|
DEBUG("Found a BAR that is the wrong size - ignoring");
|
|
|
|
sqlite3_blob_close(blob);
|
|
|
|
blob=NULL;
|
|
|
|
continue;
|
|
|
|
}
|
2012-01-12 03:38:24 +00:00
|
|
|
|
2012-08-24 05:56:25 +00:00
|
|
|
/* Only include manifests that are <=1KB inline.
|
|
|
|
Longer ones are only advertised by BAR */
|
|
|
|
if (blob_bytes>1024) {
|
|
|
|
WARN("ignoring manifest > 1k");
|
|
|
|
sqlite3_blob_close(blob);
|
|
|
|
blob = NULL;
|
|
|
|
bundle_offset[pass]++;
|
|
|
|
continue;
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
2012-08-24 05:56:25 +00:00
|
|
|
|
|
|
|
/* XXX This whole section is too hard to follow how the frame gets
|
|
|
|
built up. In particular the calculations for space required etc
|
|
|
|
are quite opaque... and I wrote it! */
|
|
|
|
int overhead=0;
|
|
|
|
int frameFull=0;
|
|
|
|
if (!pass) overhead=2;
|
|
|
|
if (0) DEBUGF("e=%p, e->bytes=%p,e->length=%d, e->allocSize=%d", e,e->bytes,e->length,e->allocSize);
|
|
|
|
|
|
|
|
if (ob_makespace(e,overhead+2+blob_bytes)) {
|
|
|
|
if (0||debug&DEBUG_RHIZOME) {
|
|
|
|
rhizome_manifest *m=rhizome_new_manifest();
|
|
|
|
char mdata[blob_bytes]; mdata[0]=0; mdata[1]=0;
|
|
|
|
sqlite3_blob_read(blob,&mdata[0],blob_bytes,0);
|
|
|
|
rhizome_read_manifest_file(m,mdata, blob_bytes);
|
|
|
|
long long version = rhizome_manifest_get_ll(m, "version");
|
|
|
|
DEBUGF("Stop cramming %s advertisements: not enough space for %s*:v%lld (%d bytes, size limit=%d, used=%d)",
|
|
|
|
pass?"BARs":"manifests",
|
|
|
|
alloca_tohex(m->cryptoSignPublic, 8),
|
|
|
|
version,
|
|
|
|
blob_bytes,e->sizeLimit,e->length);
|
|
|
|
rhizome_manifest_free(m);
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
2012-08-24 05:56:25 +00:00
|
|
|
frameFull=1;
|
|
|
|
} else if (!pass) {
|
|
|
|
/* put manifest length field and manifest ID */
|
|
|
|
/* XXX why on earth is this being done this way, instead of
|
|
|
|
with ob_append_byte() ??? */
|
|
|
|
ob_setbyte(e,e->length,(blob_bytes>>8)&0xff);
|
|
|
|
ob_setbyte(e,e->length+1,(blob_bytes>>0)&0xff);
|
|
|
|
if (0&&debug&DEBUG_RHIZOME)
|
|
|
|
DEBUGF("length bytes written at offset 0x%x",e->length);
|
|
|
|
}
|
|
|
|
if (frameFull) {
|
|
|
|
sqlite3_blob_close(blob);
|
|
|
|
blob=NULL;
|
|
|
|
goto stopStuffing;
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
2012-08-24 05:56:25 +00:00
|
|
|
if (e->length+overhead+blob_bytes>=e->allocSize) {
|
|
|
|
WHY("Reading blob will overflow overlay_buffer");
|
|
|
|
sqlite3_blob_close(blob);
|
|
|
|
blob=NULL;
|
|
|
|
continue;
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
2012-08-24 05:56:25 +00:00
|
|
|
if (sqlite3_blob_read(blob,&e->bytes[e->length+overhead],blob_bytes,0) != SQLITE_OK) {
|
|
|
|
WHYF("sqlite3_blob_read() failed, %s", sqlite3_errmsg(rhizome_db));
|
|
|
|
sqlite3_blob_close(blob);
|
|
|
|
blob=NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* debug: show which BID/version combos we are advertising */
|
|
|
|
if (0 && (!pass)) {
|
|
|
|
rhizome_manifest *m = rhizome_new_manifest();
|
|
|
|
rhizome_read_manifest_file(m, (char *)&e->bytes[e->length+overhead], blob_bytes);
|
|
|
|
long long version = rhizome_manifest_get_ll(m, "version");
|
|
|
|
DEBUGF("Advertising manifest %s* version %lld", alloca_tohex(m->cryptoSignPublic, 8), version);
|
|
|
|
rhizome_manifest_free(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
e->length+=overhead+blob_bytes;
|
|
|
|
if (e->length>e->allocSize) {
|
|
|
|
sqlite3_blob_close(blob);
|
|
|
|
blob=NULL;
|
|
|
|
FATAL("e->length > e->size");
|
|
|
|
}
|
|
|
|
bytes_used+=overhead+blob_bytes;
|
|
|
|
bundles_advertised++;
|
|
|
|
bundle_offset[pass]++;
|
|
|
|
|
|
|
|
sqlite3_blob_close(blob);
|
|
|
|
blob=NULL;
|
|
|
|
}
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
2012-08-24 05:56:25 +00:00
|
|
|
stopStuffing:
|
|
|
|
if (blob)
|
|
|
|
sqlite3_blob_close(blob);
|
|
|
|
blob = NULL;
|
|
|
|
if (statement)
|
|
|
|
sqlite3_finalize(statement);
|
|
|
|
statement = NULL;
|
|
|
|
if (!pass) {
|
|
|
|
/* Mark end of whole manifests by writing 0xff, which is more than the MSB
|
|
|
|
of a manifest's length is allowed to be. */
|
|
|
|
ob_append_byte(e,0xff);
|
|
|
|
bytes_used++;
|
|
|
|
}
|
|
|
|
}
|
2012-05-17 01:43:29 +00:00
|
|
|
|
2012-08-24 05:56:25 +00:00
|
|
|
if (blob)
|
|
|
|
sqlite3_blob_close(blob);
|
|
|
|
blob = NULL;
|
|
|
|
if (statement)
|
|
|
|
sqlite3_finalize(statement);
|
|
|
|
statement = NULL;
|
|
|
|
|
|
|
|
if (debug & DEBUG_RHIZOME)
|
|
|
|
DEBUGF("Appended %d rhizome advertisements to packet using %d bytes", bundles_advertised, bytes_used);
|
2012-07-12 00:50:13 +00:00
|
|
|
ob_patch_rfs(e, COMPUTE_RFS_LENGTH);
|
2012-08-24 05:56:25 +00:00
|
|
|
|
2012-06-26 06:32:49 +00:00
|
|
|
RETURN(0);
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now)
|
|
|
|
{
|
2012-06-26 06:32:49 +00:00
|
|
|
IN();
|
|
|
|
if (!f) { RETURN(-1); }
|
2012-01-12 03:38:24 +00:00
|
|
|
int ofs=0;
|
|
|
|
int ad_frame_type=f->payload->bytes[ofs++];
|
2012-06-25 08:33:00 +00:00
|
|
|
struct sockaddr_in httpaddr = *(struct sockaddr_in *)f->recvaddr;
|
2012-07-11 04:51:49 +00:00
|
|
|
httpaddr.sin_port = htons(RHIZOME_HTTP_PORT);
|
2012-01-12 03:38:24 +00:00
|
|
|
int manifest_length;
|
|
|
|
rhizome_manifest *m=NULL;
|
2012-08-27 02:41:06 +00:00
|
|
|
char httpaddrtxt[INET_ADDRSTRLEN];
|
|
|
|
|
2012-06-25 08:33:00 +00:00
|
|
|
switch (ad_frame_type) {
|
2012-07-02 06:37:35 +00:00
|
|
|
case 3:
|
2012-06-25 08:33:00 +00:00
|
|
|
/* The same as type=1, but includes the source HTTP port number */
|
2012-07-11 04:51:49 +00:00
|
|
|
httpaddr.sin_port = htons((f->payload->bytes[ofs] << 8) + f->payload->bytes[ofs + 1]);
|
2012-06-25 08:33:00 +00:00
|
|
|
ofs += 2;
|
|
|
|
// FALL THROUGH ...
|
|
|
|
case 1:
|
2012-01-12 03:38:24 +00:00
|
|
|
/* Extract whole manifests */
|
|
|
|
while(ofs<f->payload->length) {
|
|
|
|
manifest_length=(f->payload->bytes[ofs]<<8)+f->payload->bytes[ofs+1];
|
|
|
|
if (manifest_length>=0xff00) {
|
|
|
|
ofs++;
|
|
|
|
break;
|
2012-02-15 13:08:23 +00:00
|
|
|
}
|
2012-07-27 05:29:01 +00:00
|
|
|
if (manifest_length>f->payload->length - ofs) {
|
2012-08-27 02:41:06 +00:00
|
|
|
assert(inet_ntop(AF_INET, &httpaddr.sin_addr, httpaddrtxt, sizeof(httpaddrtxt)) != NULL);
|
|
|
|
WHYF("Illegal manifest length field in rhizome advertisement frame from %s:%d (%d vs %d)",
|
|
|
|
httpaddrtxt, ntohs(httpaddr.sin_port), manifest_length, f->payload->length - ofs);
|
2012-02-15 13:08:23 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-01-12 03:38:24 +00:00
|
|
|
|
|
|
|
ofs+=2;
|
|
|
|
if (manifest_length==0) continue;
|
|
|
|
|
|
|
|
/* Read manifest without verifying signatures (which would waste lots of
|
|
|
|
energy, everytime we see a manifest that we already have).
|
|
|
|
In fact, it would be better here to do a really rough and ready parser
|
|
|
|
to get the id and version fields out, and avoid the memory copies that
|
2012-05-22 08:03:33 +00:00
|
|
|
otherwise happen.
|
|
|
|
But we do need to make sure that at least one signature is there.
|
|
|
|
*/
|
2012-05-25 06:08:13 +00:00
|
|
|
m = rhizome_new_manifest();
|
2012-05-24 07:57:59 +00:00
|
|
|
if (!m) {
|
|
|
|
WHY("Out of manifests");
|
2012-06-26 06:32:49 +00:00
|
|
|
RETURN(0);
|
2012-05-24 07:57:59 +00:00
|
|
|
}
|
2012-05-25 23:54:47 +00:00
|
|
|
if (rhizome_read_manifest_file(m, (char *)&f->payload->bytes[ofs],
|
|
|
|
manifest_length) == -1) {
|
2012-05-25 06:08:13 +00:00
|
|
|
WHY("Error importing manifest body");
|
|
|
|
rhizome_manifest_free(m);
|
2012-06-26 06:32:49 +00:00
|
|
|
RETURN(0);
|
2012-05-25 06:08:13 +00:00
|
|
|
}
|
2012-05-27 06:30:51 +00:00
|
|
|
char manifest_id_prefix[RHIZOME_MANIFEST_ID_STRLEN + 1];
|
|
|
|
if (rhizome_manifest_get(m, "id", manifest_id_prefix, sizeof manifest_id_prefix) == NULL) {
|
2012-05-25 10:12:45 +00:00
|
|
|
WHY("Manifest does not contain 'id' field");
|
|
|
|
rhizome_manifest_free(m);
|
2012-06-26 06:32:49 +00:00
|
|
|
RETURN(0);
|
2012-05-25 10:12:45 +00:00
|
|
|
}
|
2012-05-27 06:30:51 +00:00
|
|
|
/* trim manifest ID to a prefix for ease of debugging
|
|
|
|
(that is the only use of this */
|
|
|
|
manifest_id_prefix[8]=0;
|
2012-05-25 08:37:19 +00:00
|
|
|
long long version = rhizome_manifest_get_ll(m, "version");
|
2012-07-13 01:36:10 +00:00
|
|
|
if (debug & DEBUG_RHIZOME_RX) DEBUGF("manifest id=%s* version=%lld", manifest_id_prefix, version);
|
2012-05-25 08:37:19 +00:00
|
|
|
|
2012-05-22 08:03:33 +00:00
|
|
|
/* Crude signature presence test */
|
2012-05-24 07:57:59 +00:00
|
|
|
for(i=m->manifest_all_bytes-1;i>0;i--)
|
2012-05-22 08:03:33 +00:00
|
|
|
if (!m->manifestdata[i]) {
|
|
|
|
/* A null in the middle says we have a signature */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!i) {
|
|
|
|
/* ignore the announcement, but don't ignore other people
|
|
|
|
offering the same manifest */
|
2012-05-24 07:41:55 +00:00
|
|
|
WARN("Ignoring manifest announcment with no signature");
|
2012-05-25 06:08:13 +00:00
|
|
|
rhizome_manifest_free(m);
|
2012-06-26 06:32:49 +00:00
|
|
|
RETURN(0);
|
2012-05-22 08:03:33 +00:00
|
|
|
}
|
|
|
|
int importManifest=0;
|
2012-06-25 08:33:00 +00:00
|
|
|
if (rhizome_ignore_manifest_check(m, &httpaddr))
|
2012-05-22 04:45:35 +00:00
|
|
|
{
|
|
|
|
/* Ignoring manifest that has caused us problems recently */
|
2012-05-27 06:30:51 +00:00
|
|
|
if (1) WARNF("Ignoring manifest with errors: %s*", manifest_id_prefix);
|
2012-05-22 04:45:35 +00:00
|
|
|
}
|
2012-10-02 07:02:48 +00:00
|
|
|
else if (m->errors == 0)
|
2012-01-12 03:38:24 +00:00
|
|
|
{
|
|
|
|
/* Manifest is okay, so see if it is worth storing */
|
2012-01-27 06:48:14 +00:00
|
|
|
if (rhizome_manifest_version_cache_lookup(m)) {
|
|
|
|
/* We already have this version or newer */
|
2012-07-13 01:36:10 +00:00
|
|
|
if (debug & DEBUG_RHIZOME_RX) DEBUG("We already have that manifest or newer.");
|
2012-01-27 06:48:14 +00:00
|
|
|
importManifest=0;
|
|
|
|
} else {
|
2012-07-13 01:36:10 +00:00
|
|
|
if (debug & DEBUG_RHIZOME_RX) DEBUG("Not seen before.");
|
2012-01-27 06:48:14 +00:00
|
|
|
importManifest=1;
|
|
|
|
}
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-07-13 01:36:10 +00:00
|
|
|
if (debug & DEBUG_RHIZOME) DEBUG("Unverified manifest has errors - so not processing any further.");
|
2012-05-22 04:45:35 +00:00
|
|
|
/* Don't waste any time on this manifest in future attempts for at least
|
|
|
|
a minute. */
|
2012-06-25 08:33:00 +00:00
|
|
|
rhizome_queue_ignore_manifest(m, &httpaddr, 60000);
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
2012-10-02 07:02:48 +00:00
|
|
|
if (m) {
|
|
|
|
rhizome_manifest_free(m);
|
|
|
|
m = NULL;
|
|
|
|
}
|
2012-01-12 03:38:24 +00:00
|
|
|
if (importManifest) {
|
|
|
|
/* Okay, so the manifest looks like it is potentially interesting to us,
|
|
|
|
i.e., we don't already have it or a later version of it.
|
|
|
|
Now reread the manifest, this time verifying signatures */
|
2012-05-25 06:08:13 +00:00
|
|
|
if ((m = rhizome_new_manifest()) == NULL)
|
|
|
|
WHY("Out of manifests");
|
2012-05-25 23:54:47 +00:00
|
|
|
else if (rhizome_read_manifest_file(m, (char *)&f->payload->bytes[ofs], manifest_length) == -1) {
|
2012-05-25 06:08:13 +00:00
|
|
|
WHY("Error importing manifest body");
|
2012-05-25 07:31:56 +00:00
|
|
|
rhizome_manifest_free(m);
|
2012-05-25 06:08:13 +00:00
|
|
|
m = NULL;
|
2012-06-26 07:24:40 +00:00
|
|
|
/* 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. */
|
2012-05-25 06:08:13 +00:00
|
|
|
} else if (m->errors) {
|
2012-10-02 07:02:48 +00:00
|
|
|
if (debug&DEBUG_RHIZOME)
|
|
|
|
DEBUGF("Verifying manifest %s* revealed errors -- not storing.", manifest_id_prefix);
|
2012-06-25 08:33:00 +00:00
|
|
|
rhizome_queue_ignore_manifest(m, &httpaddr, 60000);
|
2012-05-25 07:31:56 +00:00
|
|
|
rhizome_manifest_free(m);
|
2012-05-25 06:08:13 +00:00
|
|
|
m = NULL;
|
2012-01-12 03:38:24 +00:00
|
|
|
} else {
|
2012-10-02 07:02:48 +00:00
|
|
|
if (debug&DEBUG_RHIZOME)
|
|
|
|
DEBUGF("Verifying manifest %s* revealed no errors -- will try to store.", manifest_id_prefix);
|
2012-01-27 05:08:06 +00:00
|
|
|
/* Add manifest to import queue. We need to know originating IPv4 address
|
|
|
|
so that we can transfer by HTTP. */
|
2012-06-25 08:33:00 +00:00
|
|
|
rhizome_suggest_queue_manifest_import(m, &httpaddr);
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
|
|
|
}
|
2012-02-09 06:40:52 +00:00
|
|
|
if (!manifest_length) {
|
|
|
|
WHY("Infinite loop in packet decoding");
|
|
|
|
break;
|
|
|
|
}
|
2012-01-12 03:38:24 +00:00
|
|
|
ofs+=manifest_length;
|
|
|
|
}
|
2012-06-25 08:33:00 +00:00
|
|
|
break;
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|
2012-06-26 06:32:49 +00:00
|
|
|
RETURN(0);
|
2012-01-12 03:38:24 +00:00
|
|
|
}
|