Beispiel #1
0
// update the alarm time and return 1 if changed
static int
overlay_calc_queue_time(overlay_txqueue *queue, struct overlay_frame *frame){
  do{
    if (frame->destination_resolved)
      break;
    if (!frame->destination)
      break;
    if (subscriber_is_reachable(frame->destination)&REACHABLE)
      break;
    if (directory_service){
      if (subscriber_is_reachable(directory_service)&REACHABLE)
	break;
    }
    // ignore payload alarm if the destination is currently unreachable
    return 0;
  }while(0);

  time_ms_t next_allowed_packet=0;
  if (frame->destination_resolved && frame->interface){
    // don't include interfaces which are currently transmitting using a serial buffer
    if (frame->interface->tx_bytes_pending>0)
      return 0;
    next_allowed_packet = limit_next_allowed(&frame->interface->transfer_limit);
  }else{
    // check all interfaces
    int i;
    for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
    {
      if (overlay_interfaces[i].state!=INTERFACE_STATE_UP)
	continue;
      if ((!frame->destination) && (frame->interface_sent_sequence[i]==FRAME_DONT_SEND ||
	  !link_state_interface_has_neighbour(&overlay_interfaces[i])))
	continue;
      time_ms_t next_packet = limit_next_allowed(&overlay_interfaces[i].transfer_limit);
      if (next_packet < frame->interface_dont_send_until[i])
        next_packet = frame->interface_dont_send_until[i];
      if (next_allowed_packet==0||next_packet < next_allowed_packet)
	next_allowed_packet = next_packet;
    }
    if (next_allowed_packet==0)
      return 0;
  }
  
  if (next_allowed_packet < frame->dont_send_until)
    next_allowed_packet = frame->dont_send_until;

  if (ob_position(frame->payload)<SMALL_PACKET_SIZE &&
      next_allowed_packet < frame->enqueued_at + overlay_tx[frame->queue].small_packet_grace_interval)
    next_allowed_packet = frame->enqueued_at + overlay_tx[frame->queue].small_packet_grace_interval;

  overlay_queue_schedule_next(next_allowed_packet);
  
  return 0;
}
Beispiel #2
0
// quick test to make sure the specified route is valid.
int subscriber_is_reachable(struct subscriber *subscriber){
  if (!subscriber)
    return REACHABLE_NONE;
  
  int ret = subscriber->reachable;
  
  if (ret==REACHABLE_INDIRECT){
    if (!subscriber->next_hop)
      ret = REACHABLE_NONE;
    
    // avoid infinite recursion...
    else if (!(subscriber->next_hop->reachable & REACHABLE_DIRECT))
      ret = REACHABLE_NONE;
    else{
      int r = subscriber_is_reachable(subscriber->next_hop);
      if (r&REACHABLE_ASSUMED)
	ret = REACHABLE_NONE;
      else if (!(r & REACHABLE_DIRECT))
	ret = REACHABLE_NONE;
    }
  }
  
  if (ret & REACHABLE_DIRECT){
    // make sure the interface is still up
    if (!subscriber->interface)
      ret=REACHABLE_NONE;
    else if (subscriber->interface->state!=INTERFACE_STATE_UP)
      ret=REACHABLE_NONE;
  }
  
  return ret;
}
Beispiel #3
0
// load a unicast address from configuration
int load_subscriber_address(struct subscriber *subscriber)
{
  if (subscriber_is_reachable(subscriber)&REACHABLE)
    return 0;
  int i = config_host_list__get(&config.hosts, (const sid_t*)subscriber->sid);
  // No unicast configuration? just return.
  if (i == -1)
    return 1;
  const struct config_host *hostc = &config.hosts.av[i].value;
  overlay_interface *interface = NULL;
  if (*hostc->interface){
    interface = overlay_interface_find_name(hostc->interface);
    if (!interface)
      return WHY("Can't fund configured interface");
  }
  struct sockaddr_in addr;
  bzero(&addr, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_addr = hostc->address;
  addr.sin_port = htons(hostc->port);
  if (addr.sin_addr.s_addr==INADDR_NONE){
    if (interface || overlay_interface_get_default()){
      if (resolve_name(hostc->host, &addr.sin_addr))
	return -1;
    }else{
      // interface isnt up yet
      return 1;
    }
  }
  if (config.debug.overlayrouting)
    DEBUGF("Loaded address %s:%d for %s", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), alloca_tohex_sid(subscriber->sid));
  return overlay_send_probe(subscriber, addr, interface, OQ_MESH_MANAGEMENT);
}
Beispiel #4
0
static void directory_update(struct sched_ent *alarm){
  load_directory_config();
  
  if (directory_service){
    if (subscriber_is_reachable(directory_service) != REACHABLE_NONE){
      directory_send_keyring(directory_service);
      
      alarm->alarm = gettime_ms() + DIRECTORY_UPDATE_INTERVAL;
      alarm->deadline = alarm->alarm + 10000;
      schedule(alarm);
    }else
      DEBUGF("Directory service is not reachable");
  }
}
Beispiel #5
0
int overlay_send_stun_request(struct subscriber *server, struct subscriber *request){
  if ((!server) || (!request))
    return -1;
  if (!(subscriber_is_reachable(server)&REACHABLE))
    return -1;
  // don't bother with a stun request if the peer is already reachable directly
  // TODO link timeouts
  if (subscriber_is_reachable(request)&REACHABLE_DIRECT)
    return -1;
  
  time_ms_t now = gettime_ms();
  if (request->last_stun_request +1000 > now)
    return -1;
  
  request->last_stun_request=now;
  
  overlay_mdp_frame mdp;
  bzero(&mdp, sizeof(mdp));
  mdp.packetTypeAndFlags=MDP_TX;
  
  bcopy(my_subscriber->sid, mdp.out.src.sid, SID_SIZE);
  bcopy(server->sid, mdp.out.dst.sid, SID_SIZE);
  mdp.out.src.port=MDP_PORT_STUN;
  mdp.out.dst.port=MDP_PORT_STUNREQ;
  mdp.out.queue=OQ_MESH_MANAGEMENT;
  
  struct overlay_buffer *payload = ob_static(mdp.out.payload, sizeof(mdp.out.payload));
  overlay_address_append(NULL, payload, request);
  mdp.out.payload_length=ob_position(payload);
  if (config.debug.overlayrouting)
    DEBUGF("Sending STUN request to %s", alloca_tohex_sid(server->sid));
  overlay_mdp_dispatch(&mdp,0 /* system generated */,
		       NULL,0);
  ob_free(payload);
  return 0;
}
Beispiel #6
0
static void
overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, time_ms_t now){
  struct overlay_frame *frame = queue->first;
  
  // TODO stop when the packet is nearly full?
  while(frame){
    if (frame->enqueued_at + queue->latencyTarget < now){
      if (config.debug.rejecteddata)
	DEBUGF("Dropping frame type %x for %s due to expiry timeout", 
	       frame->type, frame->destination?alloca_tohex_sid(frame->destination->sid):"All");
      frame = overlay_queue_remove(queue, frame);
      continue;
    }
    
    /* Note, once we queue a broadcast packet we are committed to sending it out every interface, 
     even if we hear it from somewhere else in the mean time
     */
    
    // ignore payloads that are waiting for ack / nack resends
    if (frame->dont_send_until > now)
      goto skip;

    // quickly skip payloads that have no chance of fitting
    if (packet->buffer && ob_limit(frame->payload) > ob_remaining(packet->buffer))
      goto skip;
    
    if (!frame->destination_resolved){
      frame->next_hop = frame->destination;
      
      if (frame->next_hop){
	// Where do we need to route this payload next?
	
	int r = subscriber_is_reachable(frame->next_hop);
	
	// first, should we try to bounce this payload off the directory service?
	if (r==REACHABLE_NONE && 
	    directory_service && 
	    frame->next_hop!=directory_service){
	  frame->next_hop=directory_service;
	  r=subscriber_is_reachable(directory_service);
	}
	
	// do we need to route via a neighbour?
	if (r&REACHABLE_INDIRECT){
	  frame->next_hop = frame->next_hop->next_hop;
	  r = subscriber_is_reachable(frame->next_hop);
	}
	
	if (!(r&REACHABLE_DIRECT)){
	  goto skip;
	}
	
	frame->interface = frame->next_hop->interface;
	
	// if both broadcast and unicast are available, pick on based on interface preference
	if ((r&(REACHABLE_UNICAST|REACHABLE_BROADCAST))==(REACHABLE_UNICAST|REACHABLE_BROADCAST)){
	  if (frame->interface->prefer_unicast){
	    r=REACHABLE_UNICAST;
	    // used by tests
	    if (config.debug.overlayframes)
	      DEBUGF("Choosing to send via unicast for %s", alloca_tohex_sid(frame->destination->sid));
	  }else
	    r=REACHABLE_BROADCAST;
	}
	
	if(r&REACHABLE_UNICAST){
	  frame->recvaddr = frame->next_hop->address;
	  frame->unicast = 1;
	}else
	  frame->recvaddr = frame->interface->broadcast_address;

	// degrade packet version if required to reach the destination
	if (frame->packet_version > frame->next_hop->max_packet_version)
	  frame->packet_version = frame->next_hop->max_packet_version;

	frame->destination_resolved=1;
      }else{
	
	if (packet->buffer){
	  // check if we can stuff into this packet
	  if (frame->interface_sent_sequence[packet->i]==FRAME_DONT_SEND || frame->interface_dont_send_until[packet->i] >now)
	    goto skip;
	  frame->interface = packet->interface;
	  frame->recvaddr = packet->interface->broadcast_address;
	  
	}else{
	  // find an interface that we haven't broadcast on yet
	  frame->interface = NULL;
	  int i, keep=0;
	  for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
	  {
	    if (overlay_interfaces[i].state!=INTERFACE_STATE_UP ||
                frame->interface_sent_sequence[i]==FRAME_DONT_SEND ||
	        !link_state_interface_has_neighbour(&overlay_interfaces[i]))
	      continue;
	    keep=1;
	    if (frame->interface_dont_send_until[i] >now)
	      continue;
	    time_ms_t next_allowed = limit_next_allowed(&overlay_interfaces[i].transfer_limit);
	    if (next_allowed > now)
	      continue;
	    frame->interface = &overlay_interfaces[i];
	    frame->recvaddr = overlay_interfaces[i].broadcast_address;
	    break;
	  }
	  
	  if (!keep){
	    // huh, we don't need to send it anywhere?
	    frame = overlay_queue_remove(queue, frame);
	    continue;
	  }
	  
	  if (!frame->interface)
	    goto skip;
	}
      }
    }
    
    if (!packet->buffer){
      if (frame->interface->socket_type==SOCK_STREAM){
	// skip this interface if the stream tx buffer has data
	if (frame->interface->tx_bytes_pending>0)
	  goto skip;
      }
      
      // can we send a packet on this interface now?
      if (limit_is_allowed(&frame->interface->transfer_limit))
	goto skip;
      
      if (frame->source_full)
	my_subscriber->send_full=1;

      if (frame->interface->encapsulation!=ENCAP_SINGLE)
        overlay_init_packet(packet, frame->next_hop, frame->unicast, frame->packet_version, frame->interface, frame->recvaddr);

    }else{
      // is this packet going our way?
      if (frame->interface!=packet->interface ||
	  frame->packet_version!=packet->packet_version ||
	  memcmp(&packet->dest, &frame->recvaddr, sizeof(packet->dest))!=0){
	goto skip;
      }
    }
    
    if (frame->send_hook){
      // last minute check if we really want to send this frame, or track when we sent it
      if (frame->send_hook(frame, packet->seq, frame->send_context)){
        // drop packet
        frame = overlay_queue_remove(queue, frame);
        continue;
      }
    }

    if (frame->mdp_sequence == -1){
      frame->mdp_sequence = mdp_sequence = (mdp_sequence+1)&0xFFFF;
    }else if(((mdp_sequence - frame->mdp_sequence)&0xFFFF) >= 64){
      // too late, we've sent too many packets for the next hop to correctly de-duplicate
      if (config.debug.overlayframes)
        DEBUGF("Retransmition of frame %p mdp seq %d, is too late to be de-duplicated", frame, frame->mdp_sequence, frame->interface_sent_sequence[packet->i], packet->seq);
      frame = overlay_queue_remove(queue, frame);
      continue;
    }else{
      if (config.debug.overlayframes)
        DEBUGF("Retransmitting frame %p mdp seq %d, from packet seq %d in seq %d", frame, frame->mdp_sequence, frame->interface_sent_sequence[packet->i], packet->seq);
    }

    if (frame->interface->encapsulation==ENCAP_SINGLE){
      // send MDP packets without aggregating them together
      struct overlay_buffer *buff = ob_new();

      int ret=single_packet_encapsulation(buff, frame);
      if (!ret){
	ret=overlay_broadcast_ensemble(frame->interface, &frame->recvaddr, ob_ptr(buff), ob_position(buff));
      }

      ob_free(buff);

      if (ret)
	goto skip;
    }else{
      if (overlay_frame_append_payload(&packet->context, packet->interface, frame, packet->buffer)){
        // payload was not queued
        goto skip;
      }
    }

    frame->interface_sent_sequence[packet->i] = packet->seq;
    frame->interface_dont_send_until[packet->i] = now+200;

    if (config.debug.overlayframes){
      DEBUGF("Sent payload %p, %d type %x len %d for %s via %s, seq %d", 
	     frame, frame->mdp_sequence,
	     frame->type, ob_position(frame->payload),
	     frame->destination?alloca_tohex_sid(frame->destination->sid):"All",
	     frame->next_hop?alloca_tohex_sid(frame->next_hop->sid):alloca_tohex(frame->broadcast_id.id, BROADCAST_LEN),
             frame->interface_sent_sequence[packet->i]);
    }
    
    if (frame->destination)
      frame->destination->last_tx=now;
    if (frame->next_hop)
      frame->next_hop->last_tx=now;
    
    // mark the payload as sent

    if (frame->destination_resolved){
      if (frame->resend>0 && frame->packet_version>=1 && frame->next_hop && packet->seq !=-1 && (!frame->unicast)){
        frame->dont_send_until = now+200;
	frame->destination_resolved = 0;
	if (config.debug.overlayframes)
	  DEBUGF("Holding onto payload for ack/nack resend in %lldms", frame->dont_send_until - now);
	goto skip;
      }
    }else{
      if (frame->resend<=0 || frame->packet_version<1 || packet->seq==-1 || frame->unicast){
	// dont retransmit if we aren't sending sequence numbers, or we've run out of allowed resends
        frame->interface_sent_sequence[packet->i] = FRAME_DONT_SEND;
      }
      int i;
      for(i=0;i<OVERLAY_MAX_INTERFACES;i++){
	if (overlay_interfaces[i].state==INTERFACE_STATE_UP &&
	    link_state_interface_has_neighbour(&overlay_interfaces[i]) &&
            frame->interface_sent_sequence[i]!=FRAME_DONT_SEND){
	  goto skip;
	}
      }
    }
    
    frame = overlay_queue_remove(queue, frame);
    continue;
    
  skip:
    // if we can't send the payload now, check when we should try next
    overlay_calc_queue_time(queue, frame);
    frame = frame->next;
  }
}
Beispiel #7
0
int overlay_payload_enqueue(struct overlay_frame *p)
{
  /* Add payload p to queue q.
   
   Queues get scanned from first to last, so we should append new entries
   on the end of the queue.
   
   Complain if there are too many frames in the queue.
   */
  
  if (!p) return WHY("Cannot queue NULL");
  
  do{
    if (p->destination_resolved)
      break;
    if (!p->destination)
      break;
    int r = subscriber_is_reachable(p->destination);
    if (r&REACHABLE)
      break;
    
    if (directory_service){
      r = subscriber_is_reachable(directory_service);
      if (r&REACHABLE)
	break;
    }
    
    return WHYF("Cannot send %x packet, destination %s is %s", p->type, 
		alloca_tohex_sid(p->destination->sid), r==REACHABLE_SELF?"myself":"unreachable");
  } while(0);
  
  if (p->queue>=OQ_MAX) 
    return WHY("Invalid queue specified");
  
  /* queue a unicast probe if we haven't for a while. */
  if (p->destination && (p->destination->last_probe==0 || gettime_ms() - p->destination->last_probe > 5000))
    overlay_send_probe(p->destination, p->destination->address, p->destination->interface, OQ_MESH_MANAGEMENT);
  
  overlay_txqueue *queue = &overlay_tx[p->queue];

  if (config.debug.packettx)
    DEBUGF("Enqueuing packet for %s* (q[%d]length = %d)",
	   p->destination?alloca_tohex(p->destination->sid, 7): alloca_tohex(p->broadcast_id.id,BROADCAST_LEN),
	   p->queue, queue->length);
  
  if (p->payload && ob_remaining(p->payload)<0){
    // HACK, maybe should be done in each caller
    // set the size of the payload based on the position written
    ob_limitsize(p->payload,ob_position(p->payload));
  }
  
  if (queue->length>=queue->maxLength) 
    return WHYF("Queue #%d congested (size = %d)",p->queue,queue->maxLength);
  {
    int i;
    for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
      p->interface_sent_sequence[i]=FRAME_DONT_SEND;
  }

  if (p->destination_resolved){
    p->interface_sent_sequence[p->interface - overlay_interfaces]=FRAME_NOT_SENT;
  }else{
    if (p->destination){
      // allow the packet to be resent
      if (p->resend == 0)
        p->resend = 1;
    }else{
      int i;
      int interface_copies = 0;
      
      // hook to allow for flooding via olsr
      olsr_send(p);
      
      // make sure there is an interface up that allows broadcasts
      for(i=0;i<OVERLAY_MAX_INTERFACES;i++){
	if (overlay_interfaces[i].state!=INTERFACE_STATE_UP
	    || !overlay_interfaces[i].send_broadcasts)
	  continue;
	if (!link_state_interface_has_neighbour(&overlay_interfaces[i])){
          if (config.debug.verbose && config.debug.overlayframes)
	    DEBUGF("Skipping broadcast on interface %s, as we have no neighbours", overlay_interfaces[i].name);
	  continue;
	}
	p->interface_sent_sequence[i]=FRAME_NOT_SENT;
	interface_copies++;
      }
      
      // just drop it now
      if (interface_copies == 0){
        if (config.debug.verbose && config.debug.overlayframes)
	  DEBUGF("Not transmitting broadcast packet, as we have no neighbours on any interface");
	return -1;
      }

      // allow the packet to be resent
      if (p->resend == 0)
        p->resend = 1;
    }
  }
  
  struct overlay_frame *l=queue->last;
  if (l) l->next=p;
  p->prev=l;
  p->next=NULL;
  p->enqueued_at=gettime_ms();
  p->mdp_sequence = -1;
  // it should be safe to try sending all packets with an mdp sequence
  if (p->packet_version==0)
    p->packet_version=1;
  queue->last=p;
  if (!queue->first) queue->first=p;
  queue->length++;
  if (p->queue==OQ_ISOCHRONOUS_VOICE)
    rhizome_saw_voice_traffic();
  
  overlay_calc_queue_time(queue, p);
  return 0;
}