/* 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. */ #include "mphlr.h" #ifdef HAVE_IFADDRS_H #include #endif int overlay_ready=0; int overlay_interface_count=0; overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES]; int overlay_last_interface_number=-1; struct interface_rules { char *namespec; unsigned long long speed_in_bits; int port; char type; char excludeP; struct interface_rules *next; }; struct interface_rules *interface_filter=NULL; unsigned int overlay_sequence_number=0; time_t overlay_sequence_start_time; /* Do we need to repeat our abbreviation policy? */ int overlay_interface_repeat_abbreviation_policy[OVERLAY_MAX_INTERFACES]={1}; long long overlay_gettime_ms() { struct timeval nowtv; if (gettimeofday(&nowtv,NULL)) return WHY("gettimeofday() failed"); /* Get current time in milliseconds */ long long now=(nowtv.tv_sec-overlay_sequence_start_time)*1000LL; now=now+nowtv.tv_usec/1000; return now; } int overlay_update_sequence_number() { long long now=overlay_gettime_ms(); overlay_sequence_number=now&0xffffffff; return 0; } int overlay_interface_type(char *s) { if (!strcasecmp(s,"ethernet")) return OVERLAY_INTERFACE_ETHERNET; if (!strcasecmp(s,"wifi")) return OVERLAY_INTERFACE_WIFI; if (!strcasecmp(s,"other")) return OVERLAY_INTERFACE_UNKNOWN; if (!strcasecmp(s,"catear")) return OVERLAY_INTERFACE_PACKETRADIO; return WHY("Invalid interface type -- consider using 'wifi','ethernet' or 'other'"); } int overlay_interface_arg(char *arg) { /* Parse an interface argument, of the form: <+|->[interfacename][=type] +interface tells DNA to sit on that interface -interface tells DNA to not sit on that interface +/- without an interface tells DNA to sit on all interfaces. The first match rules, so -en0+ tells DNA to use all interfaces, excepting en0 The optional =type specifier tells DNA how to handle the interface in terms of bandwidth:distance relationship for calculating tick times etc. The special type =custom allows full specification: XXX - Settle the custom specification now that we have changed the interface management. */ char sign[80]="+"; char interface_name[80]=""; char speed[80]="1m"; char typestring[80]="wifi"; int port=PORT_DNA; int type=OVERLAY_INTERFACE_UNKNOWN; int n=0; /* Too long */ if (strlen(arg)>79) return WHY("interface specification was >79 characters"); struct interface_rules *r=calloc(sizeof(struct interface_rules),1); if (!r) return WHY("calloc(struct interface rules),1) failed"); if (sscanf(arg,"%[+-]%n%[^=+-]%n=%[^:]%n:%d%n:%[^:]%n", sign,&n,interface_name,&n,typestring,&n,&port,&n,speed,&n)>=1) { if (n1) { free(r); return WHY("Sign must be + or -"); } switch(sign[0]) { case '+': break; case '-': r->excludeP=1; break; default: free(r); return WHY("Invalid interface list item: Must begin with + or -"); } long long speed_in_bits=parse_quantity(speed); if (speed_in_bits<=1) { free(r); return WHY("Interfaces must be capable of at least 1 bit per second"); } if (nnamespec=strdup(interface_name); r->speed_in_bits=speed_in_bits; r->port=port; r->type=type; r->next=interface_filter; interface_filter=r; return 0; } else { free(r); return WHY("Bad interface specification"); } } int overlay_interface_args(char *arg) { /* Parse series of comma-separated interface definitions from a single argument */ int i=0; char interface[80]; int len=0; for(i=0;arg[i];i++) { if (arg[i]==',') { interface[len]=0; if (overlay_interface_arg(interface)) return WHY("Could not add interface"); len=0; } else { if (len<79) { interface[len++]=arg[i]; interface[len]=0; } else return WHY("Interface definition is too long (each must be <80 characters)"); } } if (len) if (overlay_interface_arg(interface)) return WHY("Could not add final interface"); return 0; } int overlay_interface_init_socket(int interface,struct sockaddr_in src_addr,struct sockaddr_in broadcast, struct sockaddr_in netmask) { #define I(X) overlay_interfaces[interface].X I(local_address)=src_addr; I(broadcast_address)=broadcast; I(netmask)=netmask; I(fileP)=0; overlay_sequence_start_time=time(0); I(fd)=socket(PF_INET,SOCK_DGRAM,0); if (I(fd)<0) { return WHY("Could not create UDP socket for interface"); } src_addr.sin_family = AF_INET; src_addr.sin_port = htons( I(port) ); /* XXX Is this right? Are we really setting the local side address? I was in a plane when at the time, so couldn't Google it. */ if (debug&4) fprintf(stderr,"src_addr=%08x\n",(unsigned int)src_addr.sin_addr.s_addr); if(bind(I(fd),(struct sockaddr *)&src_addr,sizeof(src_addr))) { perror("bind()"); return WHY("MP HLR server could not bind to requested UDP port (bind() failed)"); } if (debug&4) fprintf(stderr,"Bound to port 0x%04x\n",src_addr.sin_port); int broadcastP=1; if(setsockopt(I(fd), SOL_SOCKET, SO_BROADCAST, &broadcastP, sizeof(broadcastP)) < 0) { perror("setsockopt"); return WHY("setsockopt() failed"); } return 0; #undef I } int overlay_interface_init(char *name,struct sockaddr_in src_addr,struct sockaddr_in broadcast, struct sockaddr_in netmask,int speed_in_bits,int port,int type) { /* Too many interfaces */ if (overlay_interface_count>=OVERLAY_MAX_INTERFACES) return WHY("Too many interfaces -- Increase OVERLAY_MAX_INTERFACES"); #define I(X) overlay_interfaces[overlay_interface_count].X strcpy(I(name),name); /* 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(tick_ms)=500; I(last_tick_ms)=0; I(fd)=0; switch(type) { case OVERLAY_INTERFACE_PACKETRADIO: I(tick_ms)=15000; break; case OVERLAY_INTERFACE_ETHERNET: I(tick_ms)=500; break; case OVERLAY_INTERFACE_WIFI: I(tick_ms)=500; break; } if (name[0]=='>') { I(fileP)=1; I(fd) = open(&name[1],O_APPEND|O_NONBLOCK|O_RDWR); if (I(fd)<1) return WHY("could not open dummy interface file for append"); /* Seek to end of file as initial reading point */ I(offset)=lseek(I(fd),0,SEEK_END); /* socket gets reused to hold file offset */ /* XXX later add pretend location information so that we can decide which "packets" to receive based on closeness */ } else { if (overlay_interface_init_socket(overlay_interface_count,src_addr,broadcast,netmask)) return WHY("overlay_interface_init_socket() failed"); } overlay_interface_count++; #undef I return 0; } int overlay_rx_messages() { int i; /* 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;i0); count+=c[i]; } /* Grab packets from interfaces in round-robin fashion until all have been grabbed, or until we have spent too long (maybe 10ms?) */ while(count>0) for(i=0;i2048-128) { WHY("Truncating long packet to fit within 1920 byte limit for dummy interface"); len=2048-128; } bzero(&buf[128+len],2048-(128+len)); bcopy(bytes,&buf[128],len); if (write(overlay_interfaces[interface_number].fd,buf,2048)!=2048) { perror("write()"); return WHY("write() failed"); } else return 0; } else { if(sendto(overlay_interfaces[interface_number].fd, bytes, len, 0, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) != len) { /* Failed to send */ perror("sendto(c)"); return WHY("sendto() failed"); } else /* Sent okay */ return 0; } } /* This function is called to return old non-overlay requests back out the interface they came in. */ int overlay_sendto(struct sockaddr_in *recipientaddr,unsigned char *bytes,int len) { if (debug>1) fprintf(stderr,"Sending %d bytes.\n",len); if(overlay_broadcast_ensemble(overlay_last_interface_number,recipientaddr,bytes,len)) return -1; else return len; } int overlay_interface_discover() { #ifdef HAVE_IFADDRS_H struct ifaddrs *ifaddr,*ifa; int family,i; if (getifaddrs(&ifaddr) == -1) { perror("getifaddr()"); return WHY("getifaddrs() failed"); } /* Mark all interfaces as not observed, so that we know if we need to cull any */ for(i=0;inamespec[0]=='>') { for(i=0;inamespec)) break; if (inamespec,dummyaddr,dummyaddr,dummyaddr, 1000000,PORT_DNA,OVERLAY_INTERFACE_WIFI)) WHY("Could not initialise newly seen interface"); else if (debug&4)fprintf(stderr,"Registered interface %s\n",r->namespec); } } r=r->next; } /* Check through actual network interfaces */ for (ifa=ifaddr;ifa!=NULL;ifa=ifa->ifa_next) { family=ifa->ifa_addr->sa_family; switch(family) { case AF_INET: { unsigned char *name=(unsigned char *)ifa->ifa_name; struct sockaddr_in local=*(struct sockaddr_in *)ifa->ifa_addr; struct sockaddr_in netmask=*(struct sockaddr_in *)ifa->ifa_netmask; unsigned int broadcast_bits=local.sin_addr.s_addr|~netmask.sin_addr.s_addr; struct sockaddr_in broadcast=local; broadcast.sin_addr.s_addr=broadcast_bits; if (debug>3) printf("%s: %08x %08x %08x\n",name,local.sin_addr.s_addr,netmask.sin_addr.s_addr,broadcast.sin_addr.s_addr); /* Now register the interface, or update the existing interface registration */ struct interface_rules *r=interface_filter,*me=NULL; while(r) { if (!strcasecmp((char *)name,r->namespec)) me=r; if (!r->namespec[0]) me=r; r=r->next; } if (me&&(!me->excludeP)) { if (debug&4)fprintf(stderr,"Interface %s is interesting.\n",name); /* We should register or update this interface. */ int i; for(i=0;ispeed_in_bits,me->port,me->type)) WHY("Could not initialise newly seen interface"); else if (debug&4) fprintf(stderr,"Registered interface %s\n",name); } } break; } } } freeifaddrs(ifaddr); #endif return 0; } 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) { overlay_frame **p=&overlay_tx[q].first; while(p&&*p) { /* Throw away any stale frames */ overlay_frame *pp=*p; if (!pp) break; /* XXX Uses hardcoded freshness threshold, when it should get it from the queue */ if (now>((*p)->enqueued_at+overlay_tx[q].latencyTarget)) { /* Stale, so remove from queue. */ /* Get pointer to stale entry */ overlay_frame *stale=*p; fprintf(stderr,"Removing stale frame at %p (now=%lld, expiry=%lld)\n",stale, now,((*p)->enqueued_at+overlay_tx[q].latencyTarget)); /* Make ->next pointer that points to the stale node skip the stale node */ *p=stale->next; /* If there is an entry after the stale now, make it's prev point to the node before the stale node */ if (*p) (*p)->prev=stale->prev; if (overlay_tx[q].first==stale) overlay_tx[q].first=stale->next; if (overlay_tx[q].last==stale) overlay_tx[q].last=stale->prev; op_free(stale); overlay_tx[q].length--; } else { /* XXX Filter for those which should be sent via this interface. To do that we need to know the nexthop, and the best route to the next hop. */ /* We keep trying to queue frames in case they will fit, as not all frames are of equal size. This means that lower bit-rate codecs will get higher priority, which is probably not all bad. The only hard limit is the maximum number of payloads we allow in a frame, which is set so high as to be irrelevant, even on loopback or gigabit ethernet interface */ if (*frame_pax>=frame_max_pax) break; if (!overlay_frame_package_fmt1(*p,e)) { /* Add payload to list of payloads we are sending with this frame so that we can dequeue them if we send them. */ pax[(*frame_pax)++]=*p; } p=&(*p)->next; } } return 0; } int overlay_tick_interface(int i, long long now) { int frame_pax=0; #define MAX_FRAME_PAX 1024 overlay_frame *pax[MAX_FRAME_PAX]; 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&4) fprintf(stderr,"Ticking interface #%d\n",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. */ overlay_buffer *e=ob_new(overlay_interfaces[i].mtu); if (!e) return WHY("ob_new() failed"); ob_limitsize(e,overlay_interfaces[i].mtu/4); /* 0. Setup Serval Mesh frame header. We do not use an explicit length field for these, as the various component payloads are all self-authenticating, or at least that is the theory. */ unsigned char bytes[]={/* Magic */ 'O',0x10, /* Version */ 0x00,0x01}; if (ob_append_bytes(e,bytes,4)) return WHY("ob_append_bytes() refused to append magic bytes."); /* 1. Send announcement about ourselves, including one SID that we host if we host more than one SID (the first SID we host becomes our own identity, saving a little bit of data here). */ overlay_add_selfannouncement(i,e); /* 2. Add any queued high-priority isochronous data (i.e. voice) to the frame. */ overlay_stuff_packet_from_queue(i,e,OQ_ISOCHRONOUS_VOICE,now,pax,&frame_pax,MAX_FRAME_PAX); ob_limitsize(e,overlay_interfaces[i].mtu/2); /* 3. Add some mesh reachability reports (unlike BATMAN we announce reachability to peers progressively). 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. */ overlay_stuff_packet_from_queue(i,e,OQ_MESH_MANAGEMENT,now,pax,&frame_pax,MAX_FRAME_PAX); ob_limitsize(e,overlay_interfaces[i].mtu*3/4); /* Add advertisements for ROUTES not Rhizome bundles. Rhizome bundle advertisements are lower priority */ overlay_route_add_advertisements(i,e); ob_limitsize(e,overlay_interfaces[i].mtu); /* 4. XXX Add lower-priority queued data */ /* 5. XXX Fill the packet up to a suitable size with anything that seems a good idea */ overlay_rhizome_add_advertisements(i,e); /* Now send the frame. This takes the form of a special DNA packet with a different service code, which we setup earlier. */ if (debug&4) fprintf(stderr,"Sending %d bytes\n",e->length); if (!overlay_broadcast_ensemble(i,NULL,e->bytes,e->length)) { overlay_update_sequence_number(); fprintf(stderr,"Successfully transmitted tick frame #%d on interface #%d (%d bytes)\n", overlay_sequence_number,i,e->length); /* De-queue the passengers who were aboard. */ int j,q; for(q=0;qnext; /* Now get rid of this frame once we have found it */ if (*p) { fprintf(stderr,"** dequeueing pax @ %p\n",*p); *p=pax[j]->next; if (pax[j]->next) pax[j]->next->prev=pax[j]->prev; if (op_free(pax[j])) WHY("op_free() failed"); overlay_tx[q].length--; } } } return 0; } else return WHY("overlay_broadcast_ensemble() failed"); } long long overlay_time_in_ms() { long long now; struct timeval nowtv; if (gettimeofday(&nowtv,NULL)) return WHY("gettimeofday() failed"); /* Get current time in milliseconds */ now=nowtv.tv_sec*1000LL; now=now+nowtv.tv_usec/1000; return now; } int overlay_check_ticks() { /* Check if any interface(s) are due for a tick */ int i; /* Check for changes to interfaces */ overlay_interface_discover(); long long now=overlay_time_in_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&4) fprintf(stderr,"Examining %d interfaces.\n",overlay_interface_count); for(i=0;i0) { if (debug&4)fprintf(stderr,"Interface %s ticks every %dms, last at %lld.\n",overlay_interfaces[i].name, overlay_interfaces[i].tick_ms,overlay_interfaces[i].last_tick_ms); if (now>=overlay_interfaces[i].last_tick_ms+overlay_interfaces[i].tick_ms) { /* This interface is due for a tick */ overlay_tick_interface(i,now); overlay_interfaces[i].last_tick_ms=now; } } else if (debug&4)fprintf(stderr,"Interface %s is awol.\n",overlay_interfaces[i].name); } return 0; } long long overlay_time_until_next_tick() { /* By default only tick once per day */ long long nexttick=86400*1000; long long now; struct timeval tv; gettimeofday(&tv,NULL); now=tv.tv_sec*1000LL+tv.tv_usec/1000; int i; if (debug&4)fprintf(stderr,"Tick-check on %d interfaces at %lldms\n",overlay_interface_count,now); for(i=0;i0) { if (debug&4) fprintf(stderr,"Interface %s ticks every %dms, last at T-%lldms.\n",overlay_interfaces[i].name, overlay_interfaces[i].tick_ms,now-overlay_interfaces[i].last_tick_ms); long long thistick=(overlay_interfaces[i].last_tick_ms+overlay_interfaces[i].tick_ms)-now; if (thistick<0) thistick=0; if (thistick