Multicast Router Simulator

This C code simulates a multicast router, which can be connected to other routers and clients and allows its clients to subscribe to distant clients for regularly sent data messages. This was assigned as the final project in Edo Biagioni's Networks course at UHM in Fall 1998.

Items appearing here:

Related files:



/* router.c
 * A router in a multicast network
 *
 * David Pautler */

#include "utils.h"

#define MAX_NUM_LINKS      10 /* must be < (MAX_PAYLOAD - 8)/8 == 61 */
#define MAX_NUM_HOSTS      20
#define POS_INFINITY      100

#define MAX_DATA_MSG_BUFFERS 20
#define HOST_NUM_LEN        2  /* bytes */
#define GROUP_0_PAD         1

/*****************************************************************
 *     External Data (shared from comm_layer.c)
 ****************************************************************/

extern short print_comm_layer_debug_p;

extern int   my_ip;
extern short my_port;
extern short ima_router_p;

/*****************************************************************
 *     Global Data
 ****************************************************************/

MC_Packet recv_packet;




Shared Resources
/*****************************************************************
 *     Resources
 ****************************************************************/

int current_time;

/***** Link Table **********/

struct link {
  enum connection_status status;
  int                    time_last_heard;
  int                    ip;
  short                  port;
  char                   ima_client_p;
} link_table[MAX_NUM_LINKS];

/***** Network Map **********/

struct map_entry {
  short in_use_p;
  short port;
  int   ip;
  char  ima_client_p;
};
  
struct router {
  int              time_last_heard; /* do not allow unheard rtrs to persist */
  short            in_use_p;
  short            port;
  int              ip;
  struct map_entry neighbors[MAX_NUM_LINKS];
} routers[MAX_NUM_HOSTS];

/***** Groups Table **********/

struct group_link {
  enum connection_status status;
  int                    ip;
  short                  port;
  short                  seq_at_subscrip_time;
  short                  last_seq_num_sent;
  short                  last_ack_num_received;
};

struct data_msg {
  char  contents[MAX_MC_PAYLOAD];
  int   last_send_time;
  int   length;
};

struct group_entry {
  enum connection_status status;

  short                  expected_seq_num; /* rtr as receiver of group */

  int                    sender_ip;        /* rtr as sender of group */
  short                  sender_port;

  short                  num_subscribers;
  struct group_link      subscribers[MAX_NUM_LINKS];

  short                  num_data_msgs_sent;
  int                    next_msg_index;
  struct data_msg        msgs[MAX_DATA_MSG_BUFFERS];
} groups[MAX_NUM_GROUPS];




Complete list of function prototypes
/*****************************************************************
 *     Prototypes
 ****************************************************************/

struct link* find_neighbor_p(int ip, short port);
struct link* find_free_neighbor_p();
short all_neighbor_routers_detached_p();
short find_any_attached_neighbor_router_p(int* _router_ip, 
                                          short* _router_port);

short find_nearest(struct router* r, int dest_ip, short dest_port, 
                   int* _n_ip, short* _n_port);
short find_nearest_neighbor_for(int dest_ip, short dest_port, 
                                int* _neighbors_ip, short* _neighbors_port);

short new_link_p(int ip, short port, char client_p);

short all_subscribers_have_caught_up_p(int group);

int make_router_data_payload(char data_payload[]);
void send_data_to_group_subscribers(int grp, char payload[], int payload_len,
                                    int sender_ip, short sender_port);
void send_my_links_to_group0(); /* and give my regards to broadway */

struct group_link* find_subscriber(int group, int ip, short port);
void add_subscriber(int group, int ip, short port, short curr_seq);
void remove_subscriber(int group, int ip, short port);

void initialize_link_table();
void initialize_network_map();
void initialize_groups();

void add_entries_to_router(struct router* r, 
                           int num_links, char* data_payload);
void update_network_map(char* data_payload);

void do_receiving(char mc_packet[], int packet_len);
void do_sending_timing_receiving();




Helper Functions
/*****************************************************************
 *     Predicates (may also change params passed via ptr)
 ****************************************************************/

struct link* find_neighbor_p(int ip, short port)
{
  int i;

  for (i = 0; i < MAX_NUM_LINKS; i++)
    if ( (link_table[i].status == ATTACHED) &&
         (link_table[i].ip     == ip) &&
         (link_table[i].port   == port) ) {
      return &(link_table[i]);
    }
  return NULL;
}

struct link* find_free_neighbor_p()
{
  int i;
  for (i = 0; i < MAX_NUM_LINKS; i++)
    if (link_table[i].status == DETACHED) {
      return &(link_table[i]);
    }
  return NULL;
}

short all_neighbor_routers_detached_p()
{
  int i;
  for (i = 0; i < MAX_NUM_LINKS; i++)
    if ( (link_table[i].status == ATTACHED) &&
         (! link_table[i].ima_client_p) )
      return 0;
  return 1;
}

/* Find the first router listed in the link_table that is attached,
 * and set the router_ip and router_port to its values.  Return 1
 * is successful and 0 otherwise. */
short find_any_attached_neighbor_router_p(int* _router_ip, short* _router_port)
{
  int i;
  for (i = 0; i < MAX_NUM_LINKS; i++)
    if ( (link_table[i].status == ATTACHED) &&
         (! link_table[i].ima_client_p) ) {
      *_router_ip   = link_table[i].ip;
      *_router_port = link_table[i].port;
      return 1;
    }
  return 0;
}

short find_nearest(struct router* r,
                   int dest_ip, short dest_port, 
                   int* _n_ip, short* _n_port)
{
  int i;
  short hops_between;

  for (i = 0; i < MAX_NUM_LINKS; i++)
    if ( r->neighbors[i].in_use_p &&
         (r->neighbors[i].ip == dest_ip) &&
         (r->neighbors[i].port == dest_port) &&
         ((hops_between = find_nearest_neighbor_for(r->ip, r->port,
                                                    _n_ip, _n_port))
          > 0 ))
      /* _n_ip & _n_port already set by FNNF */
      return hops_between;
  return 0;
}

short find_nearest_neighbor_for(int dest_ip, short dest_port, 
                                int* _neighbors_ip, short* _neighbors_port)
{
  int i, nip;
  short nport, hops_away, min_hops = POS_INFINITY;

  if (find_neighbor_p(dest_ip, dest_port) != NULL) {
    *_neighbors_ip   = dest_ip;
    *_neighbors_port = dest_port;
    return 1;
  }

  for (i = 0; i < MAX_NUM_HOSTS; i++)
    if ( routers[i].in_use_p &&
         ((hops_away = find_nearest(&(routers[i]),
                                    dest_ip, dest_port, &nip, &nport))
          > 0 ) &&
         (hops_away < min_hops) ) {
      min_hops        = hops_away + 1;
      *_neighbors_ip   = nip;
      *_neighbors_port = nport;

      printf("    ");
      print_port(dest_port);
      printf(" is just %i hops away\n", min_hops);
    }
  if (min_hops < POS_INFINITY)
    return min_hops;
  return 0;
}

short new_link_p(int ip, short port, char client_p)
{
  int i;

  for (i = 0; i < MAX_NUM_LINKS; i++)
    if ( (link_table[i].ip   == ip) &&
         (link_table[i].port == port) )
      if (link_table[i].status == DETACHED) {
        link_table[i].status = ATTACHED;
        return 1;
      }
      else
        return 0;
  /* No pre-existing entry, so use first open slot */
  for (i = 0; i < MAX_NUM_LINKS; i++)
    if (link_table[i].status == DETACHED) {
      link_table[i].status       = ATTACHED;
      link_table[i].ip           = ip;
      link_table[i].port         = port;
      link_table[i].ima_client_p = client_p;
      return 1;
    }
  return 0; /* if no open slots, act as though ignorant of update */
}

short all_subscribers_have_caught_up_p(int group)
{
  int i;
  for (i = 0; i < MAX_NUM_LINKS; i++)
    if (groups[group].subscribers[i].last_ack_num_received <
        groups[group].subscribers[i].last_seq_num_sent)
      return 0;
  return 1;
}

/*****************************************************************
 *     Actions
 ****************************************************************/

int make_router_data_payload(char data_payload[])
{
  int   i;
  char* ptr_offset;
  short num_hosts;

  memcpy((int*) data_payload, &my_ip, IP_LEN);
  memcpy((short*) (data_payload + IP_LEN), &my_port, PORT_LEN);

  num_hosts = 0;
  ptr_offset = data_payload + IP_LEN + PORT_LEN + HOST_NUM_LEN;
  for (i = 0; i < MAX_NUM_LINKS; i++)
    if (link_table[i].status == ATTACHED) {
      num_hosts++;
      memcpy((int*) ptr_offset,
             &(link_table[i].ip),
             IP_LEN);
      memcpy((short*) (ptr_offset + IP_LEN),
             &(link_table[i].port),
             PORT_LEN);
      *(ptr_offset + IP_LEN + PORT_LEN) = link_table[i].ima_client_p;
      ptr_offset += IP_LEN + PORT_LEN + HOST_TYPE_LEN + GROUP_0_PAD;
    }
  memcpy((short*) (data_payload + IP_LEN + PORT_LEN),
         &num_hosts,
         HOST_NUM_LEN);
  return ptr_offset - data_payload; /* length of payload */
}

void send_data_to_group_subscribers(int group, char payload[], int payload_len,
                                    int sender_ip, short sender_port )
{
  int   i, index;
  short seq_num, subscriber_seq;
  short some_msg_sent_p = 0;

  index   = groups[group].next_msg_index;
  memcpy(groups[group].msgs[index].contents,
         payload,
         payload_len);
  groups[group].msgs[index].length         = payload_len;
  groups[group].msgs[index].last_send_time = current_time;

  seq_num = groups[group].num_data_msgs_sent;
  for (i = 0; i < MAX_NUM_LINKS; i++)
    if ( (groups[group].subscribers[i].status == ATTACHED) &&
         (! ( (groups[group].subscribers[i].ip   == sender_ip) &&
              (groups[group].subscribers[i].port == sender_port) ))) {
      subscriber_seq
        = seq_num - groups[group].subscribers[i].seq_at_subscrip_time;
      groups[group].subscribers[i].last_seq_num_sent
        = subscriber_seq;
      send_data_msg((char) group,
                    groups[group].subscribers[i].ip,
                    groups[group].subscribers[i].port,
                    subscriber_seq,
                    payload,
                    payload_len);
      some_msg_sent_p = 1;
    }
  if (some_msg_sent_p) {
    groups[group].num_data_msgs_sent++;

    /* reset to 0 when all subscribers have ACK'd up to last seq sent;
     * otherwise, this datum increases along with num_data_msgs_sent */
    groups[group].next_msg_index++;
  }

  if (groups[group].next_msg_index > MAX_DATA_MSG_BUFFERS)
    printf("  Any more data msgs will exceed num buffers for this group\n");
}

void send_my_links_to_group0()
{
  char  data_payload[MAX_MC_PAYLOAD];
  int   payload_len;

  payload_len = make_router_data_payload(data_payload);
  send_data_to_group_subscribers(0, data_payload, payload_len, my_ip, my_port);
}

struct group_link* find_subscriber(int group, int ip, short port)
{
  int i;
  for (i = 0; i < MAX_NUM_LINKS; i++)
    if ( (groups[group].subscribers[i].status == ATTACHED) &&
         (groups[group].subscribers[i].ip     == ip) &&
         (groups[group].subscribers[i].port   == port) )
      return &(groups[group].subscribers[i]);
  return NULL;
}

void add_subscriber(int group, int ip, short port, short curr_seq)
{
  int i;

  if (find_subscriber(group, ip, port)) {
    printf("  host is already subscribed to grp %i at seq %i; seq now: %i\n",
           group,
           groups[group].subscribers[i].seq_at_subscrip_time,
           curr_seq);
    return;
  }
  for (i = 0; i < MAX_NUM_LINKS; i++)
    if (groups[group].subscribers[i].status == DETACHED) {
      printf("  adding subscriber to group %i at seq %i\n", group, curr_seq);
      groups[group].subscribers[i].status               = ATTACHED;
      groups[group].subscribers[i].ip                   = ip;
      groups[group].subscribers[i].port                 = port;
      groups[group].subscribers[i].seq_at_subscrip_time = curr_seq;
      groups[group].num_subscribers++;
      return;
    }
}

void remove_subscriber(int group, int ip, short port)
{
  struct group_link* _subscriber;

  if (_subscriber = find_subscriber(group, ip, port)) {
    printf("  removing subscriber to group %i\n", group); /* DEBUG */
    _subscriber->status = DETACHED;
    groups[group].num_subscribers--;
  }
}

void initialize_link_table()
{
  int i;
  for (i = 0; i < MAX_NUM_LINKS; i++) {
    link_table[i].status          = DETACHED;
    link_table[i].time_last_heard = -QUIET_HOST_LIMIT - 1;
  }
}

void initialize_network_map()
{
  int i;
  for (i = 0; i < MAX_NUM_HOSTS; i++) {
    routers[i].time_last_heard = -QUIET_HOST_LIMIT - 1;
    routers[i].in_use_p        = 0;
  }
}

void initialize_groups()
{
  int i, j;
  for (i = 0; i < MAX_NUM_GROUPS; i++) {
    groups[i].status             = DETACHED;
    groups[i].expected_seq_num   = 0;
    groups[i].num_data_msgs_sent = 0;
    groups[i].next_msg_index     = 0;
    groups[i].num_subscribers    = 0;

    for (j = 0; j < MAX_NUM_LINKS; j++) {
      groups[i].subscribers[j].status                = DETACHED;
      groups[i].subscribers[j].last_seq_num_sent     = -1;
      groups[i].subscribers[j].last_ack_num_received = -1;
    }
  }
}

void add_entries_to_router(struct router* r, 
                           int num_links, char* data_payload)
{
  int j;

  /* first, erase all entries for this router */
  for (j = 0; j < MAX_NUM_LINKS; j++)
    r->neighbors[j].in_use_p = 0;

  /* next, copy link table in the packet into the router's entries */
  for (j = 0; j < num_links; j++) {
    memcpy(&(r->neighbors[j].ip),
           (int*)   data_payload,
           IP_LEN);
    memcpy(&(r->neighbors[j].port),
           (short*) (data_payload + IP_LEN), 
           PORT_LEN);
    r->neighbors[j].ima_client_p = *(data_payload + IP_LEN + PORT_LEN);
    r->neighbors[j].in_use_p     = 1;
    data_payload += (IP_LEN + PORT_LEN + HOST_TYPE_LEN + GROUP_0_PAD);
  }
}

void update_network_map(char* data_payload)
{
  int   i, j, ip;
  short num_links1, port, done = 0;

  memcpy(&ip,   (int*)   data_payload,            IP_LEN);
  memcpy(&port, (short*) (data_payload + IP_LEN), PORT_LEN);
  memcpy(&num_links1,
         (short*) (data_payload + IP_LEN + PORT_LEN),
         HOST_NUM_LEN);
  data_payload += (IP_LEN + PORT_LEN + HOST_NUM_LEN);
  for (i = 0; i < MAX_NUM_HOSTS; i++)
    if ( routers[i].in_use_p &&
         (routers[i].ip == ip) &&
         (routers[i].port == port) ) {

      routers[i].time_last_heard = current_time;
      add_entries_to_router(&(routers[i]), (int) num_links1, data_payload);
      done = 1;
      break; /* don't bother looking for an unused router row */
    }

  if (! done)
    for (i = 0; i < MAX_NUM_HOSTS; i++)
      if (! routers[i].in_use_p) {
        routers[i].time_last_heard = current_time;
        routers[i].in_use_p        = 1;
        routers[i].ip              = ip;
        routers[i].port            = port;
        add_entries_to_router(&(routers[i]), (int) num_links1, data_payload);
        break;
      }

  print_my_name();
  printf("newly updated network map:\n");
  for (i = 0; i < MAX_NUM_HOSTS; i++)
    if (routers[i].in_use_p) {
      printf("  ");
      print_port(routers[i].port);
      printf(" :");
      for (j = 0; j < MAX_NUM_LINKS; j++)
        if (routers[i].neighbors[j].in_use_p) {
          printf(" ");
          print_port(routers[i].neighbors[j].port);
        }
      printf("\n");
    }
}


Handle incoming packets
/*****************************************************************
 *     Flow of Control
 ****************************************************************/

void do_receiving (char mc_packet[], int packet_len)
{
  int i, j, group, ip, sender_ip, neighbors_ip, payload_len, index;
  short seq_num, ack_num, port, sender_port, neighbors_port, subscriber_seq;
  short last_ack_num, num_links;
  char* payload_ptr;
  char from_client_p, some_link_went_down_p;
  struct group_link* _subscriber;
  struct link* _neighbor;

  if (data_msg_p(mc_packet)) {
    group       = get_packet_group(mc_packet);
    sender_ip   = get_packet_sender_ip(mc_packet, DATA_ID);
    sender_port = get_packet_sender_port(mc_packet, DATA_ID);
    seq_num     = get_data_packet_seq_num(mc_packet);

    print_my_name();
    printf("received DATA packet %i from group %i\n", seq_num, group);
    payload_ptr = (mc_packet + MC_HDR_LEN + PORT_LEN + IP_LEN 
                   + SEQ_NUM_LEN + DATAPAD);

    if ((_neighbor = find_neighbor_p(sender_ip, sender_port)) != NULL) {
      _neighbor->status          = ATTACHED;
      _neighbor->time_last_heard = current_time;
    }
    else
      printf("failed to update link from data\n");
    if (group == 0) {
      update_network_map(payload_ptr);
      memcpy(&num_links,
             (short*) (payload_ptr + IP_LEN + PORT_LEN),
             HOST_NUM_LEN);
      payload_len = IP_LEN + PORT_LEN + HOST_NUM_LEN 
        + num_links * (IP_LEN + PORT_LEN + HOST_TYPE_LEN + GROUP_0_PAD);
    }
    else
      payload_len = NON_GRP0_PAYLOAD_LEN;
    groups[group].status = ATTACHED;
    if (seq_num <= groups[group].expected_seq_num) {
      send_ack_msg((char) group, 
                   sender_ip,
                   sender_port,
                   seq_num);
      if (seq_num == groups[group].expected_seq_num) {
        groups[group].expected_seq_num++;
        send_data_to_group_subscribers(group, payload_ptr, payload_len,
                                       sender_ip, sender_port);
      }
    }
  }
  else if (ack_msg_p(mc_packet)) {
    group       = get_packet_group(mc_packet);
    sender_ip   = get_packet_sender_ip(mc_packet, ACK_ID);
    sender_port = get_packet_sender_port(mc_packet, ACK_ID);
    ack_num     = get_ack_packet_ack_num(mc_packet);

    print_my_name();
    printf("received ACK %i from group %i\n", ack_num, group);
    if ( (_neighbor = find_neighbor_p(sender_ip, sender_port)) != NULL ) {
      _neighbor->status          = ATTACHED;
      _neighbor->time_last_heard = current_time;
    }
    if (_subscriber = find_subscriber(group, sender_ip, sender_port)) {
      _subscriber->last_ack_num_received = ack_num;

      /* this allows us to reuse stale buffers */
      if (all_subscribers_have_caught_up_p(group))
        groups[group].next_msg_index = 0;

      /* Router already sent ACK immediately after getting data, so
       * ack'ing here for each subscriber is unnecessary (doing it
       * for even one subscriber would be), but the only "harm" is
       * putting more packets on the network and increasing traffic
       *
       *      if (find_nearest_neighbor_for(groups[group].sender_ip,
       *                                    groups[group].sender_port,
       *                                    &neighbors_ip,
       *                                    &neighbors_port) > 0)
       *        send_ack_msg((char) group, 
       *                     neighbors_ip,
       *                     neighbors_port,
       *                     ack_num + _subscriber->seq_at_subscrip_time);
       */
    }
  }
  else if (join_msg_p(mc_packet)) {
    group = get_packet_group(mc_packet);
    ip    = get_packet_sender_ip(mc_packet, JOIN_ID);
    port  = get_packet_sender_port(mc_packet, JOIN_ID);

    print_my_name();
    printf("received JOIN for group %i\n", group);
    if ( (_neighbor = find_neighbor_p(ip, port)) != NULL ) {
      _neighbor->status          = ATTACHED;
      _neighbor->time_last_heard = current_time;
      add_subscriber(group,
                     ip,
                     port,
                     groups[group].expected_seq_num);
      if (group == 0)
        groups[group].status = ATTACHED;
      else if (groups[group].status == DETACHED) {
        printf("  trying to join upstream...\n");
        groups[group].sender_ip
          = get_join_packet_group_sender_ip(mc_packet);
        groups[group].sender_port 
          = get_join_packet_group_sender_port(mc_packet);
        if (find_nearest_neighbor_for(groups[group].sender_ip,
                                      groups[group].sender_port,
                                      &neighbors_ip,
                                      &neighbors_port))
          send_join_msg((char) group,
                        neighbors_ip,
                        neighbors_port,
                        groups[group].sender_ip,
                        groups[group].sender_port);
      }
    }
  }
  else if (detach_msg_p(mc_packet)) {
    group = get_packet_group(mc_packet);
    ip    = get_packet_sender_ip(mc_packet, DETACH_ID);
    port  = get_packet_sender_port(mc_packet, DETACH_ID);

    print_my_name();
    printf("received DETACH for group %i\n", group);
    if ( (_neighbor = find_neighbor_p(ip, port)) != NULL ) {
      _neighbor->status          = ATTACHED;
      _neighbor->time_last_heard = current_time;
    }
    if (groups[group].status == ATTACHED) {
      remove_subscriber(group,
                        ip,
                        port);
      printf("  group %i has %i subscribers left\n", 
             group,
             groups[group].num_subscribers);
      if (groups[group].num_subscribers == 0) {
        printf("  trying to detach from upstream...\n");
        if (find_nearest_neighbor_for(groups[group].sender_ip,
                                      groups[group].sender_port,
                                      &neighbors_ip,
                                      &neighbors_port)) {
          send_detach_msg((char) group,
                          neighbors_ip,
                          neighbors_port);
          groups[group].status = DETACHED;
        }
      }
    }
  }
  else if (link_msg_p(mc_packet)) {
    ip            = get_packet_sender_ip(mc_packet, LINK_ID);
    port          = get_packet_sender_port(mc_packet, LINK_ID);
    from_client_p = link_packet_from_client_p(mc_packet);

    print_my_name();
    printf("received LINK from ");
    print_ip(ip);
    printf(" ");
    print_port(port);
    printf("\n");

    if ( (_neighbor = find_neighbor_p(ip, port)) != NULL ) {
      _neighbor->status          = ATTACHED;
      _neighbor->time_last_heard = current_time;
    }
    else if ((_neighbor = find_free_neighbor_p()) != NULL) {
      _neighbor->status          = ATTACHED;
      _neighbor->time_last_heard = current_time;
      _neighbor->ip              = ip;           /* this is the way we add */
      _neighbor->port            = port;         /* client neighbors mostly */
      _neighbor->ima_client_p    = from_client_p;
    }
    else
      printf("no free link cells\n");

    if (new_link_p(ip, port, from_client_p)) {
      if ( (groups[0].status == DETACHED) &&
           (! from_client_p) ) {
        groups[0].status = ATTACHED;
        send_join_msg(0, ip, port, ip, port);
      }
      /* if Group0 attached, send link table data */
      if (groups[0].status == ATTACHED)
        send_my_links_to_group0();
    }
  }

  some_link_went_down_p = 0;
  for (i = 0; i < MAX_NUM_LINKS; i++)
    if ( (link_table[i].status == ATTACHED) &&
         ((current_time - link_table[i].time_last_heard) 
          > QUIET_HOST_LIMIT) ) {
      link_table[i].status  = DETACHED;
      some_link_went_down_p = 1;
    }
  if (some_link_went_down_p)
    send_my_links_to_group0();

  /* drop any routers from network map that we haven't heard from recently */
  for (i = 0; i < MAX_NUM_HOSTS; i++)
    if ( routers[i].in_use_p &&
         ((current_time - routers[i].time_last_heard) 
          > QUIET_HOST_LIMIT) )
      routers[i].in_use_p = 0;

  /* resend any data msgs that haven't been ack'd */
  for (i = 0; i < MAX_NUM_GROUPS; i++)
    for (j = 0; j < groups[i].num_subscribers; j++) {
      last_ack_num = groups[i].subscribers[j].last_ack_num_received;
      seq_num      = groups[i].subscribers[j].last_seq_num_sent;
      index        = (int) (seq_num - (last_ack_num + 1));
      if ( (last_ack_num < seq_num) &&
           ((current_time - groups[i].msgs[index].last_send_time)
            > NO_ACK_WAIT_LIMIT) ) {
        printf("\nRetransmit msg %i; last seq %i last send time %i\n", 
               last_ack_num+1, 
               seq_num,
               groups[i].msgs[index].last_send_time);
        send_data_msg((char) group,
                      groups[group].subscribers[i].ip,
                      groups[group].subscribers[i].port,
                      last_ack_num + 1,
                      groups[group].msgs[index].contents,
                      groups[group].msgs[index].length);
      }
    }

  if (all_neighbor_routers_detached_p())
    groups[0].status = DETACHED;
}




Send packets as appropriate and call the packet receiver at regular intervals
void do_sending_timing_receiving ()
{
  int i, router_ip;
  short router_port;

  current_time = 0;
  sleep(10); /* wait some so other routers listening when LINK & JOIN sent */
  while (1) {

    /* notify all neighbors than I'm still here */
    for (i = 0; i < MAX_NUM_LINKS; i++)
      if (link_table[i].status == ATTACHED)
        send_link_msg(ROUTER_ID,
                      link_table[i].ip,
                      link_table[i].port);

    /* if Group0 detached but neighbor router attached, send join */
    if ( (groups[0].status == DETACHED) &&
         (find_any_attached_neighbor_router_p(&router_ip, &router_port)) ) {
      send_join_msg(0,
                    router_ip,   /* packet immediate dest */
                    router_port,
                    router_ip,   /* requested group sender */
                    router_port);
        add_subscriber(0, router_ip, router_port, 0);
        }

    for (i = 0; i < SENDING_INTERVAL; i++) {  /* TIMER */
      /* print_my_name();
         printf("tick %i\n", current_time); */
      current_time++;

      mc_receive(recv_packet); /* calls do_receiving() */
      sleep(1);
    }

    /* if Group0 attached, send link table data */
    if (groups[0].status == ATTACHED)
      send_my_links_to_group0();
  } /* while loop */
}




Parse command-line options and start up the simulator
/*****************************************************************
 *     MAIN
 ****************************************************************/

int main(int argc, char* argv[])
{
  int i, j, group;

  print_comm_layer_debug_p = 0; /* extern global var */

  if ( (argc % 2) == 0 ) {
    ima_router_p = 1;
    my_port = parse_port(argv[1]);

    mc_init(&my_ip, &my_port); /* opens socket, sets my_ip */
    print_my_name();
    printf("was just created as a router.\n");

    initialize_link_table();
    initialize_network_map();
    initialize_groups();
    i = 2;     /* position in command-line of 1st neighbor router ip */
    j = 0;     /* cell in link table for 1st neighbor */
    for (; i < argc && j < MAX_NUM_LINKS; i += 2, j++) {
      link_table[j].status          = ATTACHED;
      link_table[j].time_last_heard = 0;
      link_table[j].ip              = parse_ip(argv[i]);
      link_table[j].port            = parse_port(argv[i+1]);
      link_table[j].ima_client_p    = 0; /* start assume all neighbors rtrs */
    }
    do_sending_timing_receiving();

    mc_close();
  }
  else {
    printf("Incorrect number of command-line arguments: %i\n", argc - 1);
    printf("Usage: router rtr_port (neighbor_rtr_IP neighbor_rtr_port)*\n");
  }

  return EXIT_SUCCESS;
}

This page last updated on January 6, 1999.

Maintained by David Pautler

Copyright 1999 David Pautler