www.pudn.com > myrip.rar > myrip.cpp


#include "myrip.h"

void rp_inverse_ntoh()
{
  void * tempptr =  & current_rip_packet.command;
  unsigned short * temp = (unsigned short *)( tempptr );
  *temp = ntohs(* temp);
    for(int i=0; i < current_rip_count; i++)
      {
	current_rip_packet.rip_entries[i].metric = ntohl(current_rip_packet.rip_entries[i].metric);
      }
}

void rp_inverse_hton()
{
  void * tempptr =  & current_rip_packet.command;
  unsigned short * temp = (unsigned short *)( tempptr );
  //unsigned short * temp = (unsigned short *)( & current_rip_packet);
  *temp = htons(* temp);
  //current_rip_packet.version = htons(current_rip_packet.version);
    for(int i=0; i < current_rip_count; i++)
      {
	current_rip_packet.rip_entries[i].metric = htonl(current_rip_packet.rip_entries[i].metric);
      }
}

void print_routing_table()
{
  char 	buf[INET_ADDRSTRLEN];
  size_t	buf_len = sizeof(buf);
  const char*	buf_ptr;
  
  printf("--------current routing table----------------\n");
  for (int i = 0; i < current_route_count; i++)
    {
      printf("%dth re:\n", i);
      buf_ptr = inet_ntop(AF_INET, &routing_table[i].dest, buf, buf_len);
      printf("destination: %s ", buf);
      buf_ptr = inet_ntop(AF_INET, &routing_table[i].dest, buf, buf_len);
      printf("next: %s ", buf);
      printf("metric: %d\n\n", routing_table[i].metric);
    }
  printf("---------------------------------------------\n");
}


void print_message(const char* title, const char* content)
{
    printf("\n----------- %s ---------------\n", title);
    printf("- %s -\n", content);
    printf("---------- end of message -----------\n");
}

void print_rip_packet()
{
  printf("----------rip packet contains %d entries: -------------\n", current_rip_count);
  printf("command: %s ",((current_rip_packet.command == RIP_RESPONSE)?"RESPONSE":"REQUEST"));
  printf("version: %d\n",current_rip_packet.version);
  for(int i = 0; i < current_rip_count; i++)
    {
      printf("entry %d: ",i);
      printf("ip: %s ",inet_ntoa(current_rip_packet.rip_entries[i].ip));
      printf("metric: %d\n",current_rip_packet.rip_entries[i].metric);
    }
  printf("--------------------------------------------------------\n");
}

int check_rip_packet()
{
    if (current_rip_packet.version == 2)
	return RIP_CHECK_OK;
    if (current_rip_packet.version == 0)
	return RIP_CHECK_FAIL;

    //check mbz
    if (current_rip_packet.zero)
	return RIP_CHECK_FAIL;
    for (int i = 0; i < current_rip_count; i++)
    {
	if (current_rip_packet.rip_entries[i].zero1 ||
		current_rip_packet.rip_entries[i].zero2 ||
		current_rip_packet.rip_entries[i].zero3)
	{
	    return RIP_CHECK_FAIL;
	}

	return RIP_CHECK_OK;
    }
}

int calculate_rip_metric(int rip_entry_number)
{
  if (current_rip_packet.rip_entries[rip_entry_number].metric + 1 > RIP_INFINITY)
    return RIP_INFINITY;
  return current_rip_packet.rip_entries[rip_entry_number].metric + 1;	
}

void reset_rip_packet(int command)
{
    current_rip_count = 0;
    current_rip_packet.command = command;
    current_rip_packet.version = 1;
    current_rip_packet.zero = 0;
    for (int i = 0; i < RIP_MAX_ENTRY; i++)
    {
	current_rip_packet.rip_entries[0].family = 2;
	current_rip_packet.rip_entries[0].zero1 = 0;
	current_rip_packet.rip_entries[0].ip.s_addr = 0;
	current_rip_packet.rip_entries[0].zero2 = 0;
	current_rip_packet.rip_entries[0].zero3 = 0;
	current_rip_packet.rip_entries[0].metric = 0;
    }
}

void reset_routing_table()
{
    current_route_count = 0;
    for (int i = 0; i < ROUTE_MAX_ENTRY; i++)
    {
	routing_table[i].dest.s_addr = 0;
	routing_table[i].next.s_addr = 0;
	routing_table[i].metric = 0;
	routing_table[i].valid = 1;
	routing_table[i].timer = 0;
	routing_table[i].flag = 0;
    }
}

void init_routing_table()
{
    reset_routing_table();

    for (int i = 0; i < LOCAL_ROUTE_ENTRY; i++)
    {
      if (inet_pton(AF_INET, local_ip[i], &(routing_table[i].dest)) <= 0)
	{
	  printf("inet_pton error\n");
	}
      if (inet_pton(AF_INET, local_ip[i], &(routing_table[i].next)) <= 0)
	{
	  printf("inet_pton error\n");
	}

	routing_table[i].metric = 1;
	routing_table[i].timer = time(NULL);
	routing_table[i].valid = ROUTE_VALID;
	routing_table[i].flag = 0;
    }
    current_route_count = LOCAL_ROUTE_ENTRY;
}

void get_local_ip()
{
  char ac[80];
  if (gethostname(ac, sizeof(ac)) == -1) {
    // cerr << "Error " << WSAGetLastError() <<
    //  " when getting local host name." << endl;
    return ;
  }
  printf("Host name is %s, ", ac);
  
  struct hostent *phe = gethostbyname(ac);
  if (phe == 0) {
    //cerr << "Yow! Bad host lookup." << endl;
    return ;
  }
  
  for (int i = 0; phe->h_addr_list[i] != 0; ++i) {
    local_addr;
    memcpy(&local_addr, phe->h_addr_list[i], sizeof(struct in_addr));
    printf("Address %d: %s \n=======================================\n",i, inet_ntoa(local_addr));
  }
    
}

void init_all()
{
  get_local_ip();
  reset_rip_packet(RIP_RESPONSE);
  init_routing_table();
}

void gen_request_all()
{
    current_rip_count = 1;
    current_rip_packet.command = RIP_REQUEST;
    current_rip_packet.version = 1;
    current_rip_packet.zero = 0;
    current_rip_packet.rip_entries[0].family = 0;
    current_rip_packet.rip_entries[0].zero1 = 0;
    current_rip_packet.rip_entries[0].ip.s_addr = 0;
    current_rip_packet.rip_entries[0].zero2 = 0;
    current_rip_packet.rip_entries[0].zero3 = 0;
    current_rip_packet.rip_entries[0].metric = RIP_INFINITY;
}

void send_rip_packet_to(struct in_addr &dest_ip)
{
  printf("begin sending rip packet:\n");
  print_rip_packet();
  rp_inverse_hton();
    struct sockaddr_in addr;
    int addr_len = sizeof(sockaddr_in);
    bzero(&addr, addr_len);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(dest_ip.s_addr);

    //addr.sin_port = htons(RIP_PORT);
    addr.sin_port = htons(RIP_PORT);
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    int val = 1;
    //bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
    setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val));
    // reverseMessage();

    if (sendto(sockfd, ¤t_rip_packet, RIP_PACKET_HEAD+
	       current_rip_count*sizeof(rip_entry)
	       , 0, 
		(const struct sockaddr*)&addr, addr_len) < 0)
      printf("sent green in send_rip_packet_to\n");
    close(sockfd);
	return;

}

void broadcast_rip_packet()
{
  printf("begin broadcasting rip packet:\n");
  print_rip_packet();
  rp_inverse_hton();
    struct sockaddr_in addr;
    int addr_len = sizeof(struct sockaddr_in);

    bzero(&addr, addr_len);
    addr.sin_family = AF_INET;
    //inet_aton("59.66.132.170", &addr.sin_addr);
    addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    //addr.sin_addr.s_addr=htonl(addr.sin_addr.s_addr);
    addr.sin_port = htons(520);
    //printf("sending rip packet...\n");
    
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    int val = 1;
    //bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
    setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val));
    if (sendto(sockfd, ¤t_rip_packet, 
	       RIP_PACKET_HEAD+current_rip_count*sizeof(rip_entry),
	       //sizeof(current_rip_packet), 
	       0, (struct sockaddr*)&addr, addr_len) < 0)
    {
	printf("broadcast error in broadcast_rip_packet\n");
    }
    close(sockfd);
    return;
}

void receive_rip_packet()
{
  struct sockaddr_in addr;
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
	printf("open socket error in start_rip_daemon\n");
	exit(-1);
    }
    bzero(&addr, sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(RIP_PORT);
    if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
    {
	printf("bind error in start_rip\n");
	exit(-1);
    }
    //struct sockaddr_in addr;
    int addr_len = sizeof(sockaddr_in);
    int packet_len = 0;

    packet_len = recvfrom(sockfd, ¤t_rip_packet, RIP_PACKET_HEAD + RIP_MAX_PACKET, 0, 
	    (struct sockaddr*)&addr, (socklen_t*)&addr_len);
    if (packet_len < 0)
      {
	printf("rip packet bad!!!\n");
	return;
      }
    current_rip_count = (packet_len - RIP_PACKET_HEAD) / sizeof(rip_entry);
    //--------------inverse
    rp_inverse_ntoh();
    //--------------end inverse
    struct in_addr source_addr;
    source_addr.s_addr = addr.sin_addr.s_addr;
    //char * temptemp="000.000.000.000";
    //inet_ntop(AF_INET, &source_addr.s_addr, temptemp, sizeof(temptemp));
    //printf("-----------%s\n",inet_ntoa(source_addr));
    
   
    if((source_addr.s_addr != local_addr.s_addr))
      {
	printf("packet received from %s\n", inet_ntoa(source_addr));
	print_rip_packet();
	if ((check_rip_packet() == RIP_CHECK_OK))
	  {
	    pthread_mutex_lock(&rt_mutex);
	    switch(current_rip_packet.command)
	      {
	      case RIP_REQUEST:
		handle_request(source_addr);
		break;
	      case RIP_RESPONSE:
		handle_response(source_addr);
		break;
	      default:
		break;
	      }
	    pthread_mutex_unlock(&rt_mutex);
	  }
	else
	  {
	    print_message("error:", "packet check error");
	  }
      }
}

void handle_request(struct in_addr &source_ip)
{
    if (current_route_count <= 0)
    {
	print_message("warnning:", "the route table is empty");
	return;
    }

    // reset_rip_packet(RIP_RESPONSE);

    //request for the whole route_table
    if (current_rip_count == 1 && 
	    current_rip_packet.rip_entries[0].family == 0 &&
	    current_rip_packet.rip_entries[0].metric == 16)
    {
	int route_iterator = 0;
	int sended_route_entry = 0;
	for(sended_route_entry = 0; 
	    sended_route_entry < current_route_count; 
	    sended_route_entry += RIP_MAX_ENTRY)
	  {
	    
	    reset_rip_packet(RIP_RESPONSE);
	    current_rip_count = 0;
	    while((route_iterator < current_route_count)&&(current_rip_count < RIP_MAX_ENTRY))
	      {
		//printf("test!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
		if (routing_table[route_iterator].dest.s_addr != source_ip.s_addr && 
		    routing_table[route_iterator].next.s_addr != source_ip.s_addr && 
		    routing_table[route_iterator].valid)
		  {
		    current_rip_packet.rip_entries[current_rip_count].ip.s_addr 
		      = routing_table[route_iterator].dest.s_addr;
		    current_rip_packet.rip_entries[current_rip_count].metric
		      = routing_table[route_iterator].metric;
		    current_rip_count++;	
		  }
		route_iterator++;
	      }
	    current_rip_packet.command = RIP_RESPONSE;
	    printf("respond to request----------------------------------\n");
	    send_rip_packet_to(source_ip);
	    // printf("----------------------------------------------------\n");
	  }
	return;
    }
    //request for certain route entry
    	
    for (int i = 0; i < current_rip_count; i++)
    {
      int j;
	for (j = 0; j < current_route_count; j++)
	{
	    if (routing_table[j].dest.s_addr == current_rip_packet.rip_entries[i].ip.s_addr && 
		routing_table[j].valid)
	    {
		current_rip_packet.rip_entries[current_rip_count].ip.s_addr 
		    = routing_table[j].dest.s_addr;
		current_rip_packet.rip_entries[current_rip_count].metric
		    = routing_table[j].metric;
		//current_rip_count++;
		break;
	    }
	}
	if(j == current_rip_count)
	  {
	    current_rip_packet.rip_entries[i].metric
	      = RIP_INFINITY;
	  }
    }
    current_rip_packet.command = RIP_RESPONSE;
    //send_rip_packet_to(source_ip);
    printf("respond to request----------------------------------\n");
    send_rip_packet_to(source_ip);
    // printf("----------------------------------------------------\n");
    return;
}

void handle_response(struct in_addr &source_ip)
{
  int route_exist = 0;

    int old_route_count = current_route_count;
    for (int i = 0; i < current_rip_count; i++)
    {
	route_exist = 0;
	for (int j = 0; j < old_route_count; j++)
	{               
	    if (routing_table[j].dest.s_addr == current_rip_packet.rip_entries[i].ip.s_addr)
	    {
		route_exist = 1;                               
		if((routing_table[j].next.s_addr == current_rip_packet.rip_entries[i].ip.s_addr)
		   ||(routing_table[j].metric > calculate_rip_metric(i)))
		{
		    routing_table[j].next.s_addr = source_ip.s_addr;
		    routing_table[j].metric = calculate_rip_metric(i);
		}
		routing_table[j].timer = time(NULL);
		routing_table[j].valid = 1;
		routing_table[j].flag = 1;///to be trigger...
		break;
	    }
	}
	if (route_exist == 0 && calculate_rip_metric(i) != RIP_INFINITY)
	{
	    routing_table[current_route_count].dest.s_addr = current_rip_packet.rip_entries[i].ip.s_addr;
	    routing_table[current_route_count].next.s_addr = source_ip.s_addr;
	    routing_table[current_route_count].metric = calculate_rip_metric(i);
	    routing_table[current_route_count].timer = time(NULL);
	    routing_table[current_route_count].valid = 1;
	    routing_table[current_route_count].flag = 1;//to be trigger...
	    current_route_count++;

	}
    }
    current_rip_count = 0;
    reset_rip_packet(RIP_RESPONSE);
    for (int n = 0; n < current_route_count; n++)
      {
	if( routing_table[n].flag == 1 )
	  {
	   
	    current_rip_packet.rip_entries[current_rip_count].ip.s_addr 
	      = routing_table[n].dest.s_addr;
	    current_rip_packet.rip_entries[current_rip_count].metric
	      = routing_table[n].metric;
	    current_rip_count++;	
	    current_rip_packet.command = RIP_RESPONSE;
	    
	    routing_table[n].flag = 0;
	  }
      }
    printf("update routing table caused by respond--------------\n");
    send_rip_packet_to(source_ip);
    // printf("----------------------------------------------------\n");
    //send_rip_packet_to(source_ip);
}

void * timer_routine(void *)
{
  int broadcasted_rip_count;
    time_t 	time_prev;
    time_t 	time_after;
    time_prev = time(NULL);
    while(1)
    {
     
	    sleep(5);
	    time_after = time(NULL);
	    pthread_mutex_lock(&rt_mutex);
	    update_routing_table();
	    pthread_mutex_unlock(&rt_mutex);
	    
	    if ((time_after - time_prev) >= (time_t)BROADCAST_INTERVAL )
	      {
		printf("begin broadcasting...\n");
		//pthread_mutex_lock(&crp_mutex);
		current_rip_packet.command = RIP_RESPONSE;
		current_rip_packet.version = 1;
		broadcasted_rip_count = 0;
		for(broadcasted_rip_count = 0; 
		    broadcasted_rip_count < current_route_count; 
		    broadcasted_rip_count += RIP_MAX_ENTRY)
		  {
		    reset_rip_packet(RIP_RESPONSE);
		    current_rip_count = 0;
		    for (int i = 0; (i < current_route_count)&&(i < RIP_MAX_ENTRY); i++)
		      {
			current_rip_packet.rip_entries[current_rip_count].ip 
			  = routing_table[i].dest;
			current_rip_packet.rip_entries[current_rip_count].metric
			  = routing_table[i].metric;
			current_rip_count++;
		      }
		    broadcast_rip_packet();
		    //pthread_mutex_unlock(&crp_mutex);
		    //printf("broadcast 25 rip packets...\n");
		  }
		printf("broadcast green...\n");
		time_prev = time(NULL);
	      }
    }
}

void start_rip_daemon()
{
  pthread_t timer_thread;
   
    gen_request_all();
    broadcast_rip_packet();

    printf("broadcast over in start_rip\n");
    //print_route_table();

    pthread_create(&timer_thread,NULL,timer_routine,NULL);
    
    while(1)
    {
	    printf("begin receiving...\n");
	    //pthread_mutex_lock(&crp_mutex);
	    receive_rip_packet();
	    //pthread_mutex_unlock(&crp_mutex);
	    printf("receive green...\n");
	    close(sockfd);
    }
   
    pthread_join(timer_thread, NULL);
}

void update_routing_table()
{
    time_t time_after = time(NULL);
    int old_pos = 0, new_pos=0;
    int old_route_count = current_route_count;
    //old_pos rember the ending of block that should be removed from routing table
    //new_pos remver the beginning of block that should be removed frome routing table
    int count;//number of entries in the block that should stay in routing table 
    int update = 0;
    while(old_pos < current_route_count)
    {
	count = 0;
	while((time_after-routing_table[old_pos+count].timer) < (time_t)GARBAGE_REMOVE_TIMEOUT 
		&& old_pos+count < current_route_count)
	{
	    //need to be set to invalid

	    if (routing_table[old_pos+count].valid && 
		    (time_after-routing_table[old_pos+count].timer) >= (time_t)CLOCK_TIMEOUT)
	    {
		routing_table[old_pos+count].valid = 0;
		update++;
		
	    }
	    count++;
	}
	if (old_pos+count < current_route_count && old_pos != new_pos)
	{
	  //need to remove bad entries from routing table
	    for (int i=0; i < count; i++)
	    {
		routing_table[new_pos+i].dest.s_addr = routing_table[old_pos+i].dest.s_addr;
		routing_table[new_pos+i].next.s_addr = routing_table[old_pos+i].next.s_addr;
		routing_table[new_pos+i].metric = routing_table[old_pos+i].metric;
		routing_table[new_pos+i].timer = routing_table[old_pos+i].timer;
		routing_table[new_pos+i].valid = routing_table[old_pos+i].valid;
		routing_table[new_pos+i].flag = routing_table[old_pos+i].flag;
	    }
	}
	new_pos += count;
	old_pos += count;
	while((time_after-routing_table[old_pos+count].timer) >= (time_t)GARBAGE_REMOVE_TIMEOUT 
	      && old_pos < current_route_count)
	    old_pos ++;
    }
    current_route_count = new_pos;
    if (old_route_count != new_pos || update > 0)
    {
	printf("--- Route Table Updated ---\n");
	print_routing_table();
    }
}


int main()
{
  init_all();
  printf("init green\n");
  start_rip_daemon();
  return 0;
}