From f6c899e107d3209e1a640522c893c661958e4caa Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 22 Aug 2012 10:21:38 +0930 Subject: [PATCH] Refactor overlay buffer interface to support simple parsing --- Makefile.in | 1 + commandline.c | 2 +- overlay.c | 6 +- overlay_abbreviations.c | 10 +- overlay_advertise.c | 45 ++++-- overlay_buffer.c | 343 ++++++++++++++++++++++++---------------- overlay_buffer.h | 74 +++++++++ overlay_interface.c | 13 +- overlay_mdp.c | 67 ++++---- overlay_packetformats.c | 15 +- overlay_payload.c | 48 ++---- overlay_route.c | 25 +-- rhizome_packetformats.c | 187 +++++++--------------- serval.h | 45 +----- 14 files changed, 460 insertions(+), 421 deletions(-) create mode 100644 overlay_buffer.h diff --git a/Makefile.in b/Makefile.in index c805c771..26b6035b 100755 --- a/Makefile.in +++ b/Makefile.in @@ -82,6 +82,7 @@ MONITORCLIENTOBJS= $(MONITORCLIENTSRCS:.c=.o) HDRS= fifo.h \ Makefile \ + overlay_buffer.h \ rhizome.h \ serval.h \ strbuf.h \ diff --git a/commandline.c b/commandline.c index 5cf761c4..3ea7e558 100644 --- a/commandline.c +++ b/commandline.c @@ -1506,7 +1506,7 @@ int app_id_self(int argc, const char *const *argv, struct command_line_option *o a.addrlist.mode = MDP_ADDRLIST_MODE_ROUTABLE_PEERS; /* get routable (reachable) peers */ else return WHYF("unsupported arg '%s'", argv[1]); - a.addrlist.first_sid=-1; + a.addrlist.first_sid=0; a.addrlist.last_sid=0x7fffffff; a.addrlist.frame_sid_count=MDP_MAX_SID_REQUEST; diff --git a/overlay.c b/overlay.c index fab78c36..61efccab 100644 --- a/overlay.c +++ b/overlay.c @@ -71,6 +71,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" #include "rhizome.h" #include "strbuf.h" +#include "overlay_buffer.h" int overlayMode=0; @@ -199,8 +200,7 @@ int process_incoming_frame(time_ms_t now, struct overlay_interface *interface, o 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 WHYF("Support for f->type=0x%x not yet implemented",f->type); break; } return 0; @@ -214,7 +214,7 @@ int overlay_frame_process(struct overlay_interface *interface,overlay_frame *f) time_ms_t now = gettime_ms(); if (debug&DEBUG_OVERLAYFRAMES) - DEBUGF(">>> Received frame (type=%02x, bytes=%d)",f->type,f->payload?f->payload->length:-1); + DEBUGF(">>> Received frame (type=%02x, bytes=%d)",f->type,f->payload ? f->payload->sizeLimit:-1); // only examine payloads that are broadcasts, or where I'm the next hop if (overlay_address_is_broadcast(f->nexthop)) { diff --git a/overlay_abbreviations.c b/overlay_abbreviations.c index 197534e9..d9f88454 100644 --- a/overlay_abbreviations.c +++ b/overlay_abbreviations.c @@ -18,7 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "serval.h" - +#include "overlay_buffer.h" /* We use 256bit Curve25519 addresses in the overlay mesh. This means we have very large addresses to send around the place on a regular basis, which is bad. @@ -240,17 +240,17 @@ int overlay_abbreviate_try_byindex(unsigned char *in,unsigned char *out,int *ofs return 1; } -int overlay_abbreviate_append_address(overlay_buffer *b,unsigned char *a) +int overlay_abbreviate_append_address(struct overlay_buffer *b,unsigned char *a) { int count=0; ob_makespace(b,SID_SIZE+3); - int r=overlay_abbreviate_address(a,&b->bytes[b->length],&count); + int r=overlay_abbreviate_address(a,&b->bytes[b->position],&count); if (debug&DEBUG_PACKETCONSTRUCTION) { DEBUGF("address %s abbreviates as shown in this", alloca_tohex_sid(a)); - dump(NULL, &b->bytes[b->length], count); + dump(NULL, &b->bytes[b->position], count); } if (r) return r; - b->length+=count; + b->position+=count; overlay_abbreviate_set_most_recent_address(a); return 0; } diff --git a/overlay_advertise.c b/overlay_advertise.c index f0ebea6c..87680817 100644 --- a/overlay_advertise.c +++ b/overlay_advertise.c @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" #include "subscribers.h" +#include "overlay_buffer.h" /* List of prioritised advertisements */ #define OVERLAY_MAX_ADVERTISEMENT_REQUESTS 16 @@ -59,7 +60,7 @@ int overlay_route_please_advertise(overlay_node *n) struct subscriber *last_advertised=NULL; int add_advertisement(struct subscriber *subscriber, void *context){ - overlay_buffer *e=context; + struct overlay_buffer *e=context; if (subscriber->node){ overlay_node *n=subscriber->node; @@ -84,7 +85,7 @@ int add_advertisement(struct subscriber *subscriber, void *context){ return 0; } -int overlay_route_add_advertisements(overlay_buffer *e) +int overlay_route_add_advertisements(struct overlay_buffer *e) { /* Construct a route advertisement frame and append it to e. @@ -113,12 +114,14 @@ int overlay_route_add_advertisements(overlay_buffer *e) */ int i; + ob_checkpoint(e); + if (ob_append_byte(e,OF_TYPE_NODEANNOUNCE)) return WHY("could not add node advertisement header"); ob_append_byte(e,1); /* TTL */ // assume we might fill the packet - ob_append_rfs(e, e->sizeLimit - e->length); + ob_append_rfs(e, e->sizeLimit - e->position); /* Stuff in dummy address fields */ ob_append_byte(e,OA_CODE_BROADCAST); @@ -142,16 +145,22 @@ int overlay_route_add_advertisements(overlay_buffer *e) } */ struct subscriber *start = last_advertised; + int start_pos = e->position; // append announcements starting from the last node we advertised enum_subscribers(start, add_advertisement, e); // if we didn't start at the beginning and still have space, start again from the beginning - if (start && e->sizeLimit - e->length >=8){ + if (start && e->sizeLimit - e->position >=8){ enum_subscribers(NULL, add_advertisement, e); } - - ob_patch_rfs(e,COMPUTE_RFS_LENGTH); + + if (e->position == start_pos){ + // no advertisements? don't bother to send the payload at all. + ob_rewind(e); + overlay_abbreviate_clear_most_recent_address(); + }else + ob_patch_rfs(e,COMPUTE_RFS_LENGTH); return 0; } @@ -168,26 +177,30 @@ int overlay_route_add_advertisements(overlay_buffer *e) */ int overlay_route_saw_advertisements(int i,overlay_frame *f, long long now) { - int ofs=0; IN(); - while(ofspayload->length) + while(f->payload->position < f->payload->sizeLimit) { struct subscriber *subscriber; + unsigned char *sid = ob_get_bytes_ptr(f->payload, 6); + int score=ob_get(f->payload); + int gateways_en_route=ob_get(f->payload); + + // stop if hit end of payload + if (!sid || score<0 || gateways_en_route<0) + continue; + + subscriber = find_subscriber(sid, 6, 0); - subscriber = find_subscriber(&f->payload->bytes[ofs], 6, 0); if (!subscriber){ //WARN("Dispatch PLEASEEXPLAIN not implemented"); - goto next; + continue; } - int score=f->payload->bytes[ofs+6]; - int gateways_en_route=f->payload->bytes[ofs+7]; - /* Don't record routes to ourselves */ if (overlay_address_is_local(subscriber->sid)) { if (debug & DEBUG_OVERLAYROUTING) DEBUGF("Ignore announcement about me (%s)", alloca_tohex_sid(subscriber->sid)); - goto next; + continue; } /* Don't let nodes advertise paths to themselves! @@ -195,7 +208,7 @@ int overlay_route_saw_advertisements(int i,overlay_frame *f, long long now) if (!memcmp(overlay_abbreviate_current_sender.b,subscriber->sid,SID_SIZE)){ if (debug & DEBUG_OVERLAYROUTING) DEBUGF("Ignore announcement about neighbour (%s)", alloca_tohex_sid(subscriber->sid)); - goto next; + continue; } /* File it */ @@ -206,8 +219,6 @@ int overlay_route_saw_advertisements(int i,overlay_frame *f, long long now) now-2500,now, score,gateways_en_route); - next: - ofs+=8; } RETURN(0);; diff --git a/overlay_buffer.c b/overlay_buffer.c index 3604e220..103895c4 100644 --- a/overlay_buffer.c +++ b/overlay_buffer.c @@ -18,12 +18,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "serval.h" +#include "overlay_buffer.h" -overlay_buffer *ob_new(int size) +/* + When writing to a buffer, sizeLimit may place an upper bound on the amount of space to use + + When reading from a buffer, sizeLimit should first be set to the length of any existing data. + + In either case, functions that don't take an offset use and advance the position. + */ + + + +struct overlay_buffer *ob_new(void) { - overlay_buffer *ret=calloc(sizeof(overlay_buffer),1); + struct overlay_buffer *ret=calloc(sizeof(struct overlay_buffer),1); if (!ret) return NULL; - + ob_unlimitsize(ret); return ret; @@ -31,19 +42,52 @@ overlay_buffer *ob_new(int size) // index an existing static buffer. // and allow other callers to use the ob_ convenience methods for reading and writing up to size bytes. -overlay_buffer *ob_static(unsigned char *bytes, int size){ - overlay_buffer *ret=calloc(sizeof(overlay_buffer),1); +struct overlay_buffer *ob_static(unsigned char *bytes, int size){ + struct overlay_buffer *ret=calloc(sizeof(struct overlay_buffer),1); if (!ret) return NULL; ret->bytes = bytes; - ret->allocSize =-1; - ret->sizeLimit=size; + ret->allocSize = size; + ret->allocated = 0; + ob_unlimitsize(ret); + return ret; } -int ob_free(overlay_buffer *b) +// create a new overlay buffer from an existing piece of another buffer. +// Both buffers will point to the same memory region. +// It is up to the caller to ensure this buffer is not used after the parent buffer is freed. +struct overlay_buffer *ob_slice(struct overlay_buffer *b, int offset, int length){ + struct overlay_buffer *ret=calloc(sizeof(struct overlay_buffer),1); + if (!ret) return NULL; + + ret->bytes = b->bytes+offset; + ret->allocSize = length; + ret->allocated = 0; + ob_unlimitsize(ret); + + return ret; +} + +struct overlay_buffer *ob_dup(struct overlay_buffer *b){ + struct overlay_buffer *ret=calloc(sizeof(struct overlay_buffer),1); + ret->sizeLimit = b->sizeLimit; + ret->position = b->position; + ret->checkpointLength = b->checkpointLength; + + if (b->bytes){ + int byteCount = b->sizeLimit; + if (byteCount > b->allocSize) + byteCount = b->allocSize; + + ob_append_bytes(ret, b->bytes, byteCount); + } + return ret; +} + +int ob_free(struct overlay_buffer *b) { if (!b) return WHY("Asked to free NULL"); - if (b->bytes && b->allocSize>0) free(b->bytes); + if (b->bytes && b->allocated) free(b->bytes); b->bytes=NULL; b->allocSize=0; b->sizeLimit=0; @@ -51,109 +95,100 @@ int ob_free(overlay_buffer *b) return 0; } -int ob_checkpoint(overlay_buffer *b) +int ob_checkpoint(struct overlay_buffer *b) { if (!b) return WHY("Asked to checkpoint NULL"); - b->checkpointLength=b->length; + b->checkpointLength=b->position; return 0; } -int ob_rewind(overlay_buffer *b) +int ob_rewind(struct overlay_buffer *b) { if (!b) return WHY("Asked to rewind NULL"); - b->length=b->checkpointLength; + b->position=b->checkpointLength; return 0; } -int ob_setlength(overlay_buffer *b,int bytes){ - if (bytes > b->sizeLimit) return WHY("Length exceeds size limit"); - if (b->allocSize>=0 && bytes > b->allocSize) return WHY("Length exceeds allocated size"); - b->length=bytes; - return 0; -} - -int ob_limitsize(overlay_buffer *b,int bytes) +int ob_limitsize(struct overlay_buffer *b,int bytes) { if (!b) return WHY("Asked to limit size of NULL"); - if (b->length>bytes) return WHY("Length of data in buffer already exceeds size limit"); + if (b->position>bytes) return WHY("Length of data in buffer already exceeds size limit"); if (b->checkpointLength>bytes) return WHY("Checkpointed length of data in buffer already exceeds size limit"); + if (b->bytes && (!b->allocated) && bytes > b->allocSize) return WHY("Size limit exceeds buffer size"); if (bytes<0) return WHY("Can't limit buffer to a negative size"); - if (b->allocSize<0) return WHY("Can't change the limit of a static buffer"); b->sizeLimit=bytes; return 0; } -int ob_unlimitsize(overlay_buffer *b) +int ob_unlimitsize(struct overlay_buffer *b) { if (!b) return WHY("b is NULL"); - if (b->allocSize<0) return WHY("Can't change the limit of a static buffer"); b->sizeLimit=-1; return 0; } -int ob_makespace(overlay_buffer *b,int bytes) +int ob_makespace(struct overlay_buffer *b,int bytes) { - if (b->sizeLimit!=-1 && b->length+bytes>b->sizeLimit) { + if (b->sizeLimit!=-1 && b->position+bytes>b->sizeLimit) { if (debug&DEBUG_PACKETFORMATS) WHY("Asked to make space beyond size limit"); - return -1; - } - - if (b->allocSize<0){ - return WHY("Can't resize a static buffer"); + return -1; } + // already enough space? + if (b->position + bytes < b->allocSize) + return 0; + + if (b->bytes && !b->allocated) + return WHY("Can't resize a static buffer"); + if (0) - DEBUGF("ob_makespace(%p,%d)\n b->bytes=%p,b->length=%d,b->allocSize=%d\n", - b,bytes,b->bytes,b->length,b->allocSize); + DEBUGF("ob_makespace(%p,%d)\n b->bytes=%p,b->position=%d,b->allocSize=%d\n", + b,bytes,b->bytes,b->position,b->allocSize); - if (b->length+bytes>=b->allocSize) - { - int newSize=b->length+bytes; - if (newSize<64) newSize=64; - if (newSize&63) newSize+=64-(newSize&63); - if (newSize>1024) { - if (newSize&1023) newSize+=1024-(newSize&1023); - } - if (newSize>65536) { - if (newSize&65535) newSize+=65536-(newSize&65535); - } - if (0) DEBUGF("realloc(b->bytes=%p,newSize=%d)", b->bytes,newSize); - /* XXX OSX realloc() seems to be able to corrupt things if the heap is not happy when calling realloc(), making debugging memory corruption much harder. - So will do a three-stage malloc,bcopy,free to see if we can tease the bug out that way. */ - /* - unsigned char *r=realloc(b->bytes,newSize); - if (!r) return WHY("realloc() failed"); - b->bytes=r; - */ + int newSize=b->position+bytes; + if (newSize<64) newSize=64; + if (newSize&63) newSize+=64-(newSize&63); + if (newSize>1024) { + if (newSize&1023) newSize+=1024-(newSize&1023); + } + if (newSize>65536) { + if (newSize&65535) newSize+=65536-(newSize&65535); + } + if (0) DEBUGF("realloc(b->bytes=%p,newSize=%d)", b->bytes,newSize); + /* XXX OSX realloc() seems to be able to corrupt things if the heap is not happy when calling realloc(), making debugging memory corruption much harder. + So will do a three-stage malloc,bcopy,free to see if we can tease the bug out that way. */ + /* + unsigned char *r=realloc(b->bytes,newSize); + if (!r) return WHY("realloc() failed"); + b->bytes=r; + */ #ifdef MALLOC_PARANOIA #warning adding lots of padding to try to catch overruns - if (b->bytes) { - int i; - int corrupt=0; - for(i=0;i<4096;i++) if (b->bytes[b->allocSize+i]!=0xbd) corrupt++; - if (corrupt) { - WHYF("!!!!!! %d corrupted bytes in overrun catch tray", corrupt); - dump("overrun catch tray",&b->bytes[b->allocSize],4096); - sleep(3600); - } - } - unsigned char *new=malloc(newSize+4096); - if (!new) return WHY("realloc() failed"); - { - int i; - for(i=0;i<4096;i++) new[newSize+i]=0xbd; - } -#else - unsigned char *new=malloc(newSize); -#endif - bcopy(b->bytes,new,b->length); - if (b->bytes) free(b->bytes); - b->bytes=new; - b->allocSize=newSize; - return 0; + if (b->bytes) { + int i; + int corrupt=0; + for(i=0;i<4096;i++) if (b->bytes[b->allocSize+i]!=0xbd) corrupt++; + if (corrupt) { + WHYF("!!!!!! %d corrupted bytes in overrun catch tray", corrupt); + dump("overrun catch tray",&b->bytes[b->allocSize],4096); + sleep(3600); } - else - return 0; + } + unsigned char *new=malloc(newSize+4096); + if (!new) return WHY("realloc() failed"); + { + int i; + for(i=0;i<4096;i++) new[newSize+i]=0xbd; + } +#else + unsigned char *new=malloc(newSize); +#endif + bcopy(b->bytes,new,b->position); + if (b->bytes) free(b->bytes); + b->bytes=new; + b->allocated=1; + b->allocSize=newSize; + return 0; } @@ -162,44 +197,53 @@ int ob_makespace(overlay_buffer *b,int bytes) Functions that append data and increase the size of the buffer if possible / required */ -int ob_append_byte(overlay_buffer *b,unsigned char byte) +int ob_append_byte(struct overlay_buffer *b,unsigned char byte) { if (ob_makespace(b,1)) return WHY("ob_makespace() failed"); - b->bytes[b->length++] = byte; + b->bytes[b->position++] = byte; return 0; } -unsigned char *ob_append_space(overlay_buffer *b,int count) +unsigned char *ob_append_space(struct overlay_buffer *b,int count) { - if (ob_makespace(b,count)) { WHY("ob_makespace() failed"); return NULL; } + if (ob_makespace(b,count)) + return WHYNULL("ob_makespace() failed"); - unsigned char *r=&b->bytes[b->length]; - b->length+=count; + unsigned char *r=&b->bytes[b->position]; + b->position+=count; return r; } -int ob_append_bytes(overlay_buffer *b,unsigned char *bytes,int count) +int ob_append_bytes(struct overlay_buffer *b,unsigned char *bytes,int count) { if (ob_makespace(b,count)) return WHY("ob_makespace() failed"); - bcopy(bytes,&b->bytes[b->length],count); - b->length+=count; + bcopy(bytes,&b->bytes[b->position],count); + b->position+=count; return 0; } -int ob_append_short(overlay_buffer *b,unsigned short v) +int ob_append_ui16(struct overlay_buffer *b, uint16_t v) { - unsigned short s=htons(v); - return ob_append_bytes(b,(unsigned char *)&s,sizeof(unsigned short)); + if (ob_makespace(b, 2)) return WHY("ob_makespace() failed"); + b->bytes[b->position] = (v >> 8) & 0xFF; + b->bytes[b->position+1] = v & 0xFF; + b->position+=2; + return 0; } -int ob_append_int(overlay_buffer *b,unsigned int v) +int ob_append_ui32(struct overlay_buffer *b, uint32_t v) { - unsigned int s=htonl(v); - return ob_append_bytes(b,(unsigned char *)&s,sizeof(unsigned int)); + if (ob_makespace(b, 4)) return WHY("ob_makespace() failed"); + b->bytes[b->position] = (v >> 24) & 0xFF; + b->bytes[b->position+1] = (v >> 16) & 0xFF; + b->bytes[b->position+2] = (v >> 8) & 0xFF; + b->bytes[b->position+3] = v & 0xFF; + b->position+=4; + return 0; } -int ob_append_rfs(overlay_buffer *b,int l) +int ob_append_rfs(struct overlay_buffer *b,int l) { /* Encode the specified length and append it to the buffer */ if (l<0||l>0xffff) return -1; @@ -208,7 +252,7 @@ int ob_append_rfs(overlay_buffer *b,int l) and use ob_patch_rfs to set the value. That way we have only one lot of code that does the encoding. */ - b->var_length_offset=b->length; + b->var_length_offset=b->position; b->var_length_bytes=rfs_length(l); unsigned char c[3]={0,0,0}; @@ -228,41 +272,70 @@ int ob_append_rfs(overlay_buffer *b,int l) */ - -int test_offset(overlay_buffer *b,int start,int length){ - if (!b) FATAL("b is NULL"); - if (start<0) FATALF("passed illegal offset %d",start); - if (b->sizeLimit>=0 && start+length>b->sizeLimit) FATALF("passed offset too large %d", start+length); - if (b->allocSize>=0 && start+length>b->allocSize) FATALF("passed offset too large %d", start+length); +// make sure a range of bytes is valid for reading +int test_offset(struct overlay_buffer *b,int start,int length){ + if (!b) return -1; + if (start<0) return -1; + if (b->sizeLimit>=0 && start+length>b->sizeLimit) return -1; + if (start+length>b->allocSize) return -1; return 0; } -int ob_setbyte(overlay_buffer *b,int ofs,unsigned char value) +int ob_getbyte(struct overlay_buffer *b, int ofs) { - test_offset(b, ofs, 1); - b->bytes[ofs]=value; - return 0; -} - -int ob_getbyte(overlay_buffer *b,int ofs) -{ - test_offset(b, ofs, 1); - if (ofs >= b->length) FATALF("passed offset too large %d", ofs); + if (test_offset(b, ofs, 1)) + return -1; + return b->bytes[ofs]; } -unsigned int ob_get_int(overlay_buffer *b,int offset) -{ - // TODO unsigned -1? FATAL? - test_offset(b, offset, sizeof(unsigned int)); +int ob_get_bytes(struct overlay_buffer *b, unsigned char *buff, int len){ + if (test_offset(b, b->position, len)) + return -1; + + bcopy(b->bytes + b->position, buff, len); + b->position+=len; + return 0; +} - // Some platforms require alignment - if (((uintptr_t)&b->bytes[offset])&3) { - union { unsigned char uc[4]; uint32_t ui32; } bb; - bcopy(&b->bytes[offset], &bb.uc[0], 4); - return ntohl(bb.ui32); - } else - return ntohl(*((uint32_t*)&b->bytes[offset])); +unsigned char * ob_get_bytes_ptr(struct overlay_buffer *b, int len){ + if (test_offset(b, b->position, len)) + return NULL; + + unsigned char *ret = b->bytes + b->position; + b->position+=len; + return ret; +} + +uint32_t ob_get_ui32(struct overlay_buffer *b) +{ + if (test_offset(b, b->position, 4)) + return 0xFFFFFFFF; // ... unsigned + + uint32_t ret = b->bytes[b->position] << 24 + | b->bytes[b->position +1] << 16 + | b->bytes[b->position +2] << 8 + | b->bytes[b->position +3]; + b->position+=4; + return ret; +} + +uint16_t ob_get_ui16(struct overlay_buffer *b) +{ + if (test_offset(b, b->position, 2)) + return 0xFFFF; // ... unsigned + + uint16_t ret = b->bytes[b->position] << 8 + | b->bytes[b->position +1]; + b->position+=2; + return ret; +} + +int ob_get(struct overlay_buffer *b){ + if (test_offset(b, b->position, 1)) + return -1; + + return b->bytes[b->position++]; } int rfs_length(int l) @@ -307,21 +380,21 @@ int rfs_decode(unsigned char *b,int *ofs) } // move the data at offset, by shift bytes -int ob_indel_space(overlay_buffer *b,int offset,int shift) +int ob_indel_space(struct overlay_buffer *b,int offset,int shift) { - if (offset>=b->length) return -1; + if (offset>=b->position) return -1; if (shift>0 && ob_makespace(b, shift)) return -1; - bcopy(&b->bytes[offset],&b->bytes[offset+shift],b->length-offset); - b->length+=shift; + bcopy(&b->bytes[offset],&b->bytes[offset+shift],b->position-offset); + b->position+=shift; return 0; } -int ob_patch_rfs(overlay_buffer *b,int l) +int ob_patch_rfs(struct overlay_buffer *b,int l) { if (l==COMPUTE_RFS_LENGTH){ // assume the payload has been written, we can now calculate the actual length - l = b->length - (b->var_length_offset + b->var_length_bytes); + l = b->position - (b->var_length_offset + b->var_length_bytes); } if (l<0||l>0xffff) return -1; @@ -334,13 +407,13 @@ int ob_patch_rfs(overlay_buffer *b,int l) new_size,b->var_length_bytes,shift); dump("before indel", &b->bytes[b->var_length_offset], - b->length-b->var_length_offset); + b->position-b->var_length_offset); } if (ob_indel_space(b, b->var_length_offset + b->var_length_bytes, shift)) return -1; if (debug&DEBUG_PACKETCONSTRUCTION) { dump("after indel", &b->bytes[b->var_length_offset], - b->length-b->var_length_offset); + b->position-b->var_length_offset); } } @@ -350,7 +423,7 @@ int ob_patch_rfs(overlay_buffer *b,int l) if (debug&DEBUG_PACKETCONSTRUCTION) { dump("after patch", &b->bytes[b->var_length_offset], - b->length-b->var_length_offset); + b->position-b->var_length_offset); } return 0; @@ -364,10 +437,10 @@ int asprintable(int c) return c; } -int ob_dump(overlay_buffer *b,char *desc) +int ob_dump(struct overlay_buffer *b,char *desc) { - DEBUGF("overlay_buffer '%s' at %p : length=%d", desc, b, b->length); - dump(NULL, b->bytes, b->length); + DEBUGF("overlay_buffer '%s' at %p : length=%d", desc, b, b->position); + dump(NULL, b->bytes, b->position); return 0; } diff --git a/overlay_buffer.h b/overlay_buffer.h new file mode 100644 index 00000000..21862ac1 --- /dev/null +++ b/overlay_buffer.h @@ -0,0 +1,74 @@ +/* + Serval Daemon + Copyright (C) 2012 Serval Project Inc. + + 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. + */ + +#ifndef _SERVALD_OVERLAY_BUFFER_H +#define _SERVALD_OVERLAY_BUFFER_H + +struct overlay_buffer { + unsigned char *bytes; + + // remembered position for rewinding + int checkpointLength; + + // position of data read / written + int position; + + // maximum allowed bytes for reading / writing + int sizeLimit; + + // size of buffer + int allocSize; + + // is this an allocated buffer? can it be resized? Should it be freed? + int allocated; + + // length position and size for later patching + int var_length_offset; + int var_length_bytes; +}; + +struct overlay_buffer *ob_new(void); +struct overlay_buffer *ob_static(unsigned char *bytes, int size); +struct overlay_buffer *ob_slice(struct overlay_buffer *b, int offset, int length); +struct overlay_buffer *ob_dup(struct overlay_buffer *b); +int ob_free(struct overlay_buffer *b); +int ob_checkpoint(struct overlay_buffer *b); +int ob_rewind(struct overlay_buffer *b); +int ob_limitsize(struct overlay_buffer *b,int bytes); +int ob_unlimitsize(struct overlay_buffer *b); +int ob_makespace(struct overlay_buffer *b,int bytes); +int ob_append_byte(struct overlay_buffer *b,unsigned char byte); +int ob_append_bytes(struct overlay_buffer *b,unsigned char *bytes,int count); +unsigned char *ob_append_space(struct overlay_buffer *b,int count); +int ob_append_ui16(struct overlay_buffer *b, uint16_t v); +int ob_append_ui32(struct overlay_buffer *b, uint32_t v); +int ob_patch_rfs(struct overlay_buffer *b,int l); +int ob_append_rfs(struct overlay_buffer *b,int l); +// get one byte, -ve number indicates failure +int ob_getbyte(struct overlay_buffer *b,int ofs); +// get one byte from the current position, -ve number indicates failure +int ob_get(struct overlay_buffer *b); +int ob_get_bytes(struct overlay_buffer *b, unsigned char *buff, int len); +unsigned char * ob_get_bytes_ptr(struct overlay_buffer *b, int len); +uint32_t ob_get_ui32(struct overlay_buffer *b); +uint16_t ob_get_ui16(struct overlay_buffer *b); +int ob_dump(struct overlay_buffer *b,char *desc); + + +#endif diff --git a/overlay_interface.c b/overlay_interface.c index 83c7fdaa..3f1caea7 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "serval.h" #include "strbuf.h" +#include "overlay_buffer.h" #ifdef HAVE_IFADDRS_H #include @@ -52,7 +53,7 @@ struct profile_total sock_any_stats; struct outgoing_packet{ overlay_interface *interface; int i; - overlay_buffer *buffer; + struct overlay_buffer *buffer; }; struct sched_ent next_packet; @@ -925,7 +926,7 @@ static void overlay_init_packet(struct outgoing_packet *packet, int interface) { packet->i = interface; packet->interface = &overlay_interfaces[packet->i]; - packet->buffer=ob_new(packet->interface->mtu); + packet->buffer=ob_new(); ob_limitsize(packet->buffer, packet->interface->mtu); ob_append_bytes(packet->buffer,magic_header,4); @@ -1075,14 +1076,14 @@ overlay_fill_send_packet(struct outgoing_packet *packet, time_ms_t now) { if(packet->buffer){ // send the packet - if (packet->buffer->length>=HEADERFIELDS_LEN){ + if (packet->buffer->position>=HEADERFIELDS_LEN){ if (debug&DEBUG_PACKETCONSTRUCTION) - dump("assembled packet",&packet->buffer->bytes[0],packet->buffer->length); + dump("assembled packet",&packet->buffer->bytes[0],packet->buffer->position); if (debug&DEBUG_OVERLAYINTERFACES) - DEBUGF("Sending %d byte packet",packet->buffer->length); + DEBUGF("Sending %d byte packet",packet->buffer->position); - overlay_broadcast_ensemble(packet->i,NULL,packet->buffer->bytes,packet->buffer->length); + overlay_broadcast_ensemble(packet->i,NULL,packet->buffer->bytes,packet->buffer->position); } ob_free(packet->buffer); overlay_abbreviate_clear_most_recent_address(); diff --git a/overlay_mdp.c b/overlay_mdp.c index 84a9d84a..cca26a62 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" #include "strbuf.h" #include "subscribers.h" +#include "overlay_buffer.h" struct profile_total mdp_stats={.name="overlay_mdp_poll"}; @@ -280,7 +281,7 @@ unsigned char *overlay_mdp_decrypt(overlay_frame *f, overlay_mdp_frame *mdp, int { IN(); - *len=f->payload->length; + *len=f->payload->sizeLimit; unsigned char *b = NULL; unsigned char plain_block[(*len)+16]; @@ -288,7 +289,7 @@ unsigned char *overlay_mdp_decrypt(overlay_frame *f, overlay_mdp_frame *mdp, int case 0: /* get payload */ b=&f->payload->bytes[0]; - *len=f->payload->length; + *len=f->payload->sizeLimit; mdp->packetTypeAndFlags|=MDP_NOCRYPT|MDP_NOSIGN; break; case OF_CRYPTO_CIPHERED: @@ -306,7 +307,7 @@ unsigned char *overlay_mdp_decrypt(overlay_frame *f, overlay_mdp_frame *mdp, int /* get payload and following compacted signature */ b=&f->payload->bytes[0]; - *len=f->payload->length-crypto_sign_edwards25519sha512batch_BYTES; + *len=f->payload->sizeLimit-crypto_sign_edwards25519sha512batch_BYTES; /* get hash */ unsigned char hash[crypto_hash_sha512_BYTES]; @@ -344,7 +345,7 @@ unsigned char *overlay_mdp_decrypt(overlay_frame *f, overlay_mdp_frame *mdp, int 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; + int cipher_len=f->payload->sizeLimit-nb; bcopy(&f->payload->bytes[nb],&plain_block[16],cipher_len); if (0) { dump("nm bytes",k,crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES); @@ -374,7 +375,7 @@ int overlay_saw_mdp_containing_frame(overlay_frame *f, time_ms_t now) Take payload from mdp frame itself. */ overlay_mdp_frame mdp; - int len=f->payload->length; + int len=f->payload->sizeLimit; /* Get source and destination addresses */ bcopy(f->destination,mdp.in.dst.sid,SID_SIZE); @@ -750,13 +751,15 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, case 0: /* crypted and signed (using CryptoBox authcryption primitive) */ frame->modifiers=OF_CRYPTO_SIGNED|OF_CRYPTO_CIPHERED; /* Prepare payload */ - frame->payload=ob_new(1 /* frame type (MDP) */ - +1 /* MDP version */ - +4 /* dst port */ - +4 /* src port */ - +crypto_box_curve25519xsalsa20poly1305_NONCEBYTES - +crypto_box_curve25519xsalsa20poly1305_ZEROBYTES - +mdp->out.payload_length); + frame->payload=ob_new(); + /*length should be; + 1 - frame type (MDP) + +1 - MDP version + +4 - dst port + +4 - src port + +crypto_box_curve25519xsalsa20poly1305_NONCEBYTES + +crypto_box_curve25519xsalsa20poly1305_ZEROBYTES + +mdp->out.payload_length*/ { /* write cryptobox nonce */ unsigned char nonce[crypto_box_curve25519xsalsa20poly1305_NONCEBYTES]; @@ -792,7 +795,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, 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)")); } /* Get pointer to place in frame where the ciphered text needs to go */ - int cipher_offset=frame->payload->length; + int cipher_offset=frame->payload->position; 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")); } @@ -803,16 +806,16 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, /* 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); - frame->payload->length-=16; + frame->payload->position-=16; if (0) { DEBUG("authcrypted mdp frame"); dump("nm bytes",k,crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES); dump("nonce",nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES); dump("plain text",&plain[16],cipher_len-16); dump("cipher text",cipher_text,cipher_len-16); - DEBUGF("frame->payload->length=%d,cipher_len-16=%d,cipher_offset=%d", frame->payload->length,cipher_len-16,cipher_offset); + DEBUGF("frame->payload->length=%d,cipher_len-16=%d,cipher_offset=%d", frame->payload->position,cipher_len-16,cipher_offset); dump("frame",&frame->payload->bytes[0], - frame->payload->length); + frame->payload->position); } } break; @@ -838,12 +841,15 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, */ frame->modifiers=OF_CRYPTO_SIGNED; /* Prepare payload */ - frame->payload=ob_new(1 /* frame type (MDP) */ - +1 /* MDP version */ - +4 /* dst port */ - +4 /* src port */ - +crypto_sign_edwards25519sha512batch_BYTES - +mdp->out.payload_length); + frame->payload=ob_new(); + /* Length should be; + 1 - frame type (MDP) + +1 - MDP version + +4 - dst port + +4 - src port + +crypto_sign_edwards25519sha512batch_BYTES + +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")); } @@ -893,17 +899,20 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */ frame->modifiers=0; /* Copy payload body in */ - frame->payload=ob_new(1 /* frame type (MDP) */ - +1 /* MDP version */ - +4 /* dst port */ - +4 /* src port */ - +mdp->out.payload_length); + frame->payload=ob_new(); + /* Length should be; + 1 - frame type (MDP) + +1 - MDP version + +4 - dst port + +4 - src port + +mdp->out.payload_length + */ /* MDP version 1 */ ob_append_byte(frame->payload,0x01); ob_append_byte(frame->payload,0x01); /* Destination port */ - ob_append_int(frame->payload,mdp->out.src.port); - ob_append_int(frame->payload,mdp->out.dst.port); + ob_append_ui32(frame->payload,mdp->out.src.port); + ob_append_ui32(frame->payload,mdp->out.dst.port); ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length); break; } diff --git a/overlay_packetformats.c b/overlay_packetformats.c index 7067c0c3..f2b7062b 100644 --- a/overlay_packetformats.c +++ b/overlay_packetformats.c @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" #include "strbuf.h" +#include "overlay_buffer.h" struct sockaddr_in loopback = { .sin_family=0, @@ -236,12 +237,10 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s ensemble */ if (f.type==OF_TYPE_SELFANNOUNCE) overlay_abbreviate_set_current_sender(f.source); - - // TODO refactor all packet parsing to only allocate additional memory for the payload - // if it needs to be queued for forwarding. - + + /* Create an overlay buffer, wrapping around this static packet */ f.payload = ob_static(&packet[ofs], nextPayload - ofs); - ob_setlength(f.payload, nextPayload - ofs); + ob_limitsize(f.payload, nextPayload - ofs); /* Finally process the frame */ overlay_frame_process(interface,&f); @@ -257,7 +256,7 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s return 0; } -int overlay_add_selfannouncement(int interface,overlay_buffer *b) +int overlay_add_selfannouncement(int interface,struct overlay_buffer *b) { /* Pull the first record from the HLR database and turn it into a @@ -351,9 +350,9 @@ int overlay_add_selfannouncement(int interface,overlay_buffer *b) // number: one millisecond ago. if (last_ms == -1) last_ms = now - 1; - if (ob_append_int(b, last_ms)) + if (ob_append_ui32(b, last_ms)) return WHY("Could not add low sequence number to self-announcement"); - if (ob_append_int(b, now)) + if (ob_append_ui32(b, now)) return WHY("Could not add high sequence number to self-announcement"); if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("interface #%d: last_tick_ms=%lld, now=%lld (delta=%lld)", diff --git a/overlay_payload.c b/overlay_payload.c index eef21d3a..992d5064 100644 --- a/overlay_payload.c +++ b/overlay_payload.c @@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "serval.h" +#include "overlay_buffer.h" int overlay_payload_verify(overlay_frame *p) { @@ -27,7 +28,7 @@ int overlay_payload_verify(overlay_frame *p) return WHY("function not implemented"); } -int op_append_type(overlay_buffer *headers,overlay_frame *p) +int op_append_type(struct overlay_buffer *headers,overlay_frame *p) { unsigned char c[3]; switch(p->type&OF_TYPE_FLAG_BITS) @@ -59,16 +60,16 @@ int op_append_type(overlay_buffer *headers,overlay_frame *p) } -int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b) +int overlay_frame_package_fmt1(overlay_frame *p, struct overlay_buffer *b) { /* Convert a payload (frame) structure into a series of bytes. Assumes that any encryption etc has already been done. Will pick a next hop if one has not been chosen. */ - overlay_buffer *headers; + struct overlay_buffer *headers; - headers=ob_new(256); + headers=ob_new(); if (!headers) return WHY("could not allocate overlay buffer for headers"); @@ -111,26 +112,26 @@ int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b) we rely on context for abbreviating the addresses. So we write it initially and then patch it after. */ - int max_len=((SID_SIZE+3)*3+headers->length+p->payload->length); + int max_len=((SID_SIZE+3)*3+headers->position+p->payload->position); if (debug&DEBUG_PACKETCONSTRUCTION) DEBUGF("Appending RFS for max_len=%d\n",max_len); ob_append_rfs(headers,max_len); - int addrs_start=headers->length; + int addrs_start=headers->position; /* Write out addresses as abbreviated as possible */ overlay_abbreviate_append_address(headers,p->nexthop); overlay_abbreviate_append_address(headers,p->destination); overlay_abbreviate_append_address(headers,p->source); - int addrs_len=headers->length-addrs_start; - int actual_len=addrs_len+p->payload->length; + int addrs_len=headers->position-addrs_start; + int actual_len=addrs_len+p->payload->position; if (debug&DEBUG_PACKETCONSTRUCTION) DEBUGF("Patching RFS for actual_len=%d\n",actual_len); ob_patch_rfs(headers,actual_len); /* Write payload format plus total length of header bits */ - if (ob_makespace(b,2+headers->length+p->payload->length)) { + if (ob_makespace(b,2+headers->position+p->payload->position)) { /* Not enough space free in output buffer */ if (debug&DEBUG_PACKETFORMATS) DEBUGF("Could not make enough space free in output buffer"); @@ -138,11 +139,11 @@ int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b) } /* Package up headers and payload */ - if (ob_append_bytes(b,headers->bytes,headers->length)) { + if (ob_append_bytes(b,headers->bytes,headers->position)) { WHY("could not append header"); goto cleanup; } - if (ob_append_bytes(b,p->payload->bytes,p->payload->length)) { + if (ob_append_bytes(b,p->payload->bytes,p->payload->position)) { WHY("could not append payload"); goto cleanup; } @@ -156,13 +157,6 @@ cleanup: return -1; } -overlay_buffer *overlay_payload_unpackage(overlay_frame *b) { - /* Extract the payload at the current location in the buffer. */ - - WHY("not implemented"); - return NULL; -} - int dump_queue(char *msg,int q) { overlay_txqueue *qq=&overlay_tx[q]; @@ -191,7 +185,7 @@ int dump_payload(overlay_frame *p,char *message) message?message:""); DEBUGF(" next hop is %s",alloca_tohex_sid(p->nexthop)); if (p->payload) - dump("payload contents", &p->payload->bytes[0],p->payload->length); + dump("payload contents", &p->payload->bytes[0],p->payload->position); return 0; } @@ -204,8 +198,8 @@ 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)", + if (debug&DEBUG_PACKETTX) + DEBUGF("Enqueuing packet for %s* (q[%d]length = %d)", alloca_tohex(p->destination, 7), q,overlay_tx[q].length); @@ -274,16 +268,8 @@ overlay_frame *op_dup(overlay_frame *in) /* copy main data structure */ bcopy(in,out,sizeof(overlay_frame)); - out->payload=ob_new(in->payload->length); - if (!out->payload) { - free(out); - return WHYNULL("ob_new() failed"); - } - if (ob_append_bytes(out->payload,&in->payload->bytes[0],in->payload->length)) - { - op_free(out); - return WHYNULL("could not duplicate payload bytes"); - } + + out->payload=ob_dup(in->payload); return out; } diff --git a/overlay_route.c b/overlay_route.c index 1eb533ac..c66dd725 100644 --- a/overlay_route.c +++ b/overlay_route.c @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" #include "strbuf.h" #include "subscribers.h" +#include "overlay_buffer.h" /* Here we implement the actual routing algorithm which is heavily based on BATMAN. @@ -349,6 +350,7 @@ int overlay_route_ack_selfannounce(overlay_frame *f, if (overlay_resolve_next_hop(out)) { /* no open path, so convert to broadcast */ overlay_frame_set_broadcast_as_destination(out); + out->isBroadcast = 1; out->ttl=2; if (debug&DEBUG_OVERLAYROUTING) DEBUG("Broadcasting ack to selfannounce for hithero unroutable node"); @@ -368,13 +370,12 @@ int overlay_route_ack_selfannounce(overlay_frame *f, numbers means we can't just take the highest-numbered sequence number. So we need to take the observation which was most recently received. */ - out->payload=ob_new(4+32*2+1); /* will grow if it isn't big enough, but let's try to - avoid a realloc() if possible */ + out->payload=ob_new(); /* XXX - we should merge contiguous observation reports so that packet loss on the return path doesn't count against the link. */ - ob_append_int(out->payload,s1); - ob_append_int(out->payload,s2); + ob_append_ui32(out->payload,s1); + ob_append_ui32(out->payload,s2); /* The ack needs to contain the per-interface scores that we have built up for this neighbour. @@ -552,9 +553,9 @@ int overlay_route_saw_selfannounce(overlay_frame *f, time_ms_t now) RETURN(-1); } - s1=ob_get_int(f->payload, 0); - s2=ob_get_int(f->payload, 4); - sender_interface=ob_getbyte(f->payload, 8); + s1=ob_get_ui32(f->payload); + s2=ob_get_ui32(f->payload); + sender_interface=ob_get(f->payload); if (debug&DEBUG_OVERLAYROUTING) DEBUGF("Received self-announcement for sequence range [%08x,%08x] from interface %d",s1,s2,sender_interface); @@ -803,14 +804,14 @@ int overlay_route_saw_selfannounce_ack(overlay_frame *f,long long now) { IN(); if (debug&DEBUG_OVERLAYROUTING) - DEBUGF("processing selfannounce ack (payload length=%d)",f->payload->length); + DEBUGF("processing selfannounce ack (payload length=%d)",f->payload->sizeLimit); - if (f->payload->length<9) + if (f->payload->sizeLimit<9) RETURN(WHY("FOO! selfannounce ack packet too short")); - unsigned int s1=ob_get_int(f->payload,0); - unsigned int s2=ob_get_int(f->payload,4); - int iface=ob_getbyte(f->payload,8); + unsigned int s1=ob_get_ui32(f->payload); + unsigned int s2=ob_get_ui32(f->payload); + int iface=ob_get(f->payload); // Call something like the following for each link overlay_route_node_can_hear_me(f->source,iface,s1,s2,now); diff --git a/rhizome_packetformats.c b/rhizome_packetformats.c index 62a12110..6d4faada 100644 --- a/rhizome_packetformats.c +++ b/rhizome_packetformats.c @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" #include "rhizome.h" #include +#include "overlay_buffer.h" #include int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar) @@ -73,7 +74,7 @@ int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar) int bundles_available=-1; int bundle_offset[2]={0,0}; -int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e) +int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buffer *e) { IN(); int voice_mode=0; @@ -93,13 +94,10 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e) if (voice_mode) if (random()&3) { RETURN(0); } int pass; - int bytes=e->sizeLimit-e->length; + int bytes=e->sizeLimit-e->position; int overhead=1+11+1+2+2; /* maximum overhead */ 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; if (slots<1) { RETURN(WHY("No room for node advertisements")); } @@ -110,7 +108,7 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e) RETURN(WHY("could not add rhizome bundle advertisement header")); ob_append_byte(e, 1); /* TTL (1 byte) */ - ob_append_rfs(e,1+11+1+2+RHIZOME_BAR_BYTES*slots_used/* RFS */); + ob_append_rfs(e,1+11+1+2+RHIZOME_BAR_BYTES/* RFS */); /* Stuff in dummy address fields (11 bytes) */ ob_append_byte(e,OA_CODE_BROADCAST); @@ -129,7 +127,7 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e) */ ob_append_byte(e,3+skipmanifests); /* Rhizome HTTP server port number (2 bytes) */ - ob_append_short(e, rhizome_http_server_port); + ob_append_ui16(e, rhizome_http_server_port); /* XXX Should add priority bundles here. XXX Should prioritise bundles for subscribed groups, Serval-authorised files @@ -165,6 +163,7 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e) sqlite3_blob *blob=NULL; for(pass=skipmanifests;pass<2;pass++) { + ob_checkpoint(e); switch(pass) { case 0: /* Full manifests */ statement = sqlite_prepare("SELECT MANIFEST,ROWID FROM MANIFESTS LIMIT %d,%d", bundle_offset[pass], slots); @@ -175,9 +174,8 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e) } 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 + while( sqlite_step_retry(&retry, statement) == SQLITE_ROW + && e->position+RHIZOME_BAR_BYTES<=e->sizeLimit ) { int column_type=sqlite3_column_type(statement, 0); switch(column_type) { @@ -214,77 +212,37 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e) continue; } - /* 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); - } - 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); + /* make sure there's enough room for the blob, its length, + the 0xFF end marker and 1 spare for the rfs length to increase */ + if (ob_makespace(e,overhead+blob_bytes+2)) + goto stopStuffing; + + if (!pass) { + /* include manifest length field */ + ob_append_ui16(e, blob_bytes); } - if (frameFull) { - sqlite3_blob_close(blob); - blob=NULL; + + unsigned char *dest=ob_append_space(e, blob_bytes); + if (!dest){ + WHY("Reading blob will overflow overlay_buffer"); goto stopStuffing; } - if (e->length+overhead+blob_bytes>=e->allocSize) { - WHY("Reading blob will overflow overlay_buffer"); - sqlite3_blob_close(blob); - blob=NULL; - continue; - } - if (sqlite3_blob_read(blob,&e->bytes[e->length+overhead],blob_bytes,0) != SQLITE_OK) { + + if (sqlite3_blob_read(blob,dest,blob_bytes,0) != SQLITE_OK) { WHYF("sqlite3_blob_read() failed, %s", sqlite3_errmsg(rhizome_db)); - sqlite3_blob_close(blob); - blob=NULL; - continue; + goto stopStuffing; } - /* 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; + + ob_checkpoint(e); } } stopStuffing: @@ -294,23 +252,16 @@ int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e) if (statement) sqlite3_finalize(statement); statement = NULL; + + ob_rewind(e); + 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++; } } - 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); ob_patch_rfs(e, COMPUTE_RFS_LENGTH); RETURN(0); @@ -320,8 +271,7 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now) { IN(); if (!f) { RETURN(-1); } - int ofs=0; - int ad_frame_type=f->payload->bytes[ofs++]; + int ad_frame_type=ob_get(f->payload); struct sockaddr_in httpaddr = *(struct sockaddr_in *)f->recvaddr; httpaddr.sin_port = htons(RHIZOME_HTTP_PORT); int manifest_length; @@ -331,26 +281,26 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now) switch (ad_frame_type) { case 3: /* The same as type=1, but includes the source HTTP port number */ - httpaddr.sin_port = htons((f->payload->bytes[ofs] << 8) + f->payload->bytes[ofs + 1]); - ofs += 2; + httpaddr.sin_port = htons(ob_get_ui16(f->payload)); // FALL THROUGH ... case 1: /* Extract whole manifests */ - while(ofspayload->length) { - manifest_length=(f->payload->bytes[ofs]<<8)+f->payload->bytes[ofs+1]; - if (manifest_length>=0xff00) { - ofs++; + while(f->payload->position < f->payload->sizeLimit) { + if (ob_getbyte(f->payload, f->payload->position)==0xff){ + f->payload->position++; break; } - if (manifest_length>f->payload->length - ofs) { - 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); - break; - } - - ofs+=2; + + manifest_length=ob_get_ui16(f->payload); if (manifest_length==0) continue; + + unsigned char *data = ob_get_bytes_ptr(f->payload, manifest_length); + if (!data) { + assert(inet_ntop(AF_INET, &httpaddr.sin_addr, httpaddrtxt, sizeof(httpaddrtxt)) != NULL); + WHYF("Illegal manifest length field in rhizome advertisement frame %d vs %d.", + manifest_length, f->payload->sizeLimit - f->payload->position); + break; + } /* Read manifest without verifying signatures (which would waste lots of energy, everytime we see a manifest that we already have). @@ -364,12 +314,13 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now) WHY("Out of manifests"); RETURN(0); } - if (rhizome_read_manifest_file(m, (char *)&f->payload->bytes[ofs], - manifest_length) == -1) { + + if (rhizome_read_manifest_file(m, (char *)data, manifest_length) == -1) { WHY("Error importing manifest body"); rhizome_manifest_free(m); 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"); @@ -395,7 +346,7 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now) rhizome_manifest_free(m); RETURN(0); } - int importManifest=0; + if (rhizome_ignore_manifest_check(m, &httpaddr)) { /* Ignoring manifest that has caused us problems recently */ @@ -407,10 +358,12 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now) if (rhizome_manifest_version_cache_lookup(m)) { /* We already have this version or newer */ if (debug & DEBUG_RHIZOME_RX) DEBUG("We already have that manifest or newer."); - importManifest=0; } else { if (debug & DEBUG_RHIZOME_RX) DEBUG("Not seen before."); - importManifest=1; + + rhizome_suggest_queue_manifest_import(m, &httpaddr); + // the above function will free the manifest structure, make sure we don't free it again + m=NULL; } } else @@ -420,42 +373,10 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now) a minute. */ rhizome_queue_ignore_manifest(m, &httpaddr, 60000); } - if (m) rhizome_manifest_free(m); + + if (m) + rhizome_manifest_free(m); m=NULL; - 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 */ - if ((m = rhizome_new_manifest()) == NULL) - WHY("Out of manifests"); - else if (rhizome_read_manifest_file(m, (char *)&f->payload->bytes[ofs], manifest_length) == -1) { - WHY("Error importing manifest body"); - 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); - rhizome_manifest_free(m); - m = NULL; - } else { - if (debug&DEBUG_RHIZOME) DEBUGF("Verifying manifest %s* revealed no errors -- will try to store.", manifest_id_prefix); - /* Add manifest to import queue. We need to know originating IPv4 address - so that we can transfer by HTTP. */ - if (0) DEBUG("Suggesting fetching of a bundle"); - rhizome_suggest_queue_manifest_import(m, &httpaddr); - } - } - if (!manifest_length) { - WHY("Infinite loop in packet decoding"); - break; - } - ofs+=manifest_length; } break; } diff --git a/serval.h b/serval.h index 563f439c..a917685a 100644 --- a/serval.h +++ b/serval.h @@ -454,22 +454,6 @@ typedef struct overlay_peer { extern overlay_peer overlay_peers[OVERLAY_MAX_PEERS]; -typedef struct overlay_buffer { - unsigned char *bytes; - // position of data read / written - int length; - // allocated size of buffer - int allocSize; - // remembered position for rewinding - int checkpointLength; - // maximum allowed bytes for reading / writing - 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; @@ -627,27 +611,6 @@ int overlay_frame_resolve_addresses(overlay_frame *f); #define alloca_tohex_sid(sid) alloca_tohex((sid), SID_SIZE) #define alloca_tohex_sas(sas) alloca_tohex((sas), SAS_SIZE) -overlay_buffer *ob_new(int size); -overlay_buffer *ob_static(unsigned char *bytes, int size); -int ob_free(overlay_buffer *b); -int ob_checkpoint(overlay_buffer *b); -int ob_rewind(overlay_buffer *b); -int ob_setlength(overlay_buffer *b,int bytes); -int ob_limitsize(overlay_buffer *b,int bytes); -int ob_unlimitsize(overlay_buffer *b); -int ob_makespace(overlay_buffer *b,int bytes); -int ob_append_byte(overlay_buffer *b,unsigned char byte); -int ob_append_bytes(overlay_buffer *b,unsigned char *bytes,int count); -unsigned char *ob_append_space(overlay_buffer *b,int count); -int ob_append_short(overlay_buffer *b,unsigned short v); -int ob_append_int(overlay_buffer *b,unsigned int v); -int ob_patch_rfs(overlay_buffer *b,int l); -int ob_append_rfs(overlay_buffer *b,int l); -int ob_setbyte(overlay_buffer *b,int ofs,unsigned char value); -int ob_getbyte(overlay_buffer *b,int ofs); -int ob_dump(overlay_buffer *b,char *desc); -unsigned int ob_get_int(overlay_buffer *b,int offset); - int op_free(overlay_frame *p); overlay_frame *op_dup(overlay_frame *f); @@ -657,11 +620,11 @@ int overlay_rx_messages(); #define DEBUG_packet_visualise(M,P,N) logServalPacket(LOG_LEVEL_DEBUG, __HERE__, (M), (P), (N)) int overlay_add_selfannouncement(); -int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b); +int overlay_frame_package_fmt1(overlay_frame *p, struct overlay_buffer *b); int overlay_interface_args(const char *arg); int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *interface); int overlay_sendto(struct sockaddr_in *recipientaddr,unsigned char *bytes,int len); -int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e); +int overlay_rhizome_add_advertisements(int interface_number,struct overlay_buffer *e); int overlay_add_local_identity(unsigned char *s); int overlay_address_is_local(unsigned char *s); void overlay_update_queue_schedule(overlay_txqueue *queue, overlay_frame *frame); @@ -674,7 +637,7 @@ extern int overlay_local_identity_count; 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_append_address(struct overlay_buffer *b,unsigned char *a); int overlay_abbreviate_expand_address(unsigned char *in,int *inofs,unsigned char *out,int *ofs); int overlay_abbreviate_cache_address(unsigned char *sid); @@ -731,7 +694,7 @@ int overlay_route_record_link( time_ms_t 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_add_advertisements(overlay_buffer *e); +int overlay_route_add_advertisements(struct overlay_buffer *e); int ovleray_route_please_advertise(overlay_node *n); int overlay_abbreviate_set_current_sender(unsigned char *in);