//*****************************************************************************
//
// Program: vdump -- Programming Project 1
//
// Author: Travis Dillon
//
// Class: CS 444
// Email: tdillon@ace.cs.ohiou.edu
//
// Description: This is a virtual router program, it accepts packets from
// vr_pickup and outputs their contents.
//
// Date: January 07, 2005
//
//*****************************************************************************
#include <stdlib.h>
#include <iostream.h>
#include <vrouter.h>
#define DEFAULT_GROUP 0
#define BUFFER_SIZE 512
#define INTERFACE_NAME_LENGTH 100
using namespace std;
void print_packet(const char buf[], const int& packet_size,
const int& packet_number);
void option_h();
void option_l(lanlist* all_lans, _lan* lan_ptr);
void option_g(int argc, char** argv, unsigned& group, int& i);
void option_i(int argc, char** argv, unsigned& group, int& i,
char*& interface, lanlist* all_lans);
typedef struct _Ethernet
{
unsigned char destination[7];
unsigned char source[7];
unsigned char type[3];
unsigned char data[41];
}Ethernet;
int main(int argc, char *argv[])
{
int i, packet_size(0), packet_number(0);
char buf[BUFFER_SIZE], *interface;
unsigned group = DEFAULT_GROUP;
bool debug_on = false;
lanlist* all_lans = whichlans();
_lan* lan_ptr;
INTERFACE* iface;
if(all_lans == NULL)
{
cout << "whichlans() failed and returned NULL\n";
exit(EXIT_FAILURE);
}
lan_ptr = all_lans -> lan;
interface = lan_ptr -> lname;
for(i=1; i < argc; ++i) //parse the command line
{
if(argv[i][0] != '-') //at this point an argument must have a '-'
{
cout << "Invalid option - \"" << argv[i] << "\".\n";
option_h();
}
switch(argv[i][1])
{
case 'd': debug_on = true; break;
case 'l': option_l(all_lans, lan_ptr); break;
case 'g': option_g(argc, argv, group, i); break;
case 'i': option_i(argc, argv, group, i, interface, all_lans); break;
case 'h': option_h(); break;
default:
{
cout << "Invalid option - \"" << argv[i] << "\".\n";
option_h();
break;
}
}
}
if(debug_on)
{
cout << "interface = " << interface << "\ngroup = " << group << endl;
}
iface = openinterface(interface, group);
if(iface == NULL)
{
cout << "openinterface failed.\n";
exit(EXIT_FAILURE);
}
cout << "Using group " << group << "\nUsing interface '"
<< interface << "'" << flush;
while(true) //let the router run
{
packet_size = readpacket(iface, buf, BUFFER_SIZE);
if(packet_size == -1)
{
cout << "readpacket failed.\n";
exit(EXIT_FAILURE);
}
print_packet(buf, packet_size, ++packet_number);
}
closeinterface(iface);
exit(EXIT_SUCCESS);
}
//****************************************************************************
//
// Function: print_packet
//
// Purpose: Print the destination, source, type, and data for each packet
//
// Parameters: buf - hold the contents of the packet
// packet_size - the number of bytes in the packet
// packet_number - the number of the packet
//
// Calls: none
//
//****************************************************************************
void print_packet(const char buf[], const int& packet_size,
const int& packet_number)
{
Ethernet e_net;
size_t k, one_byte; //one_byte used to ouput characters into hex
for(k = 0; k < 53; ++k) //copy buf contents to e_net
{
if(k < 6) e_net.destination[k] = buf[k];
if(k > 5 && k < 12) e_net.source[k] = buf[k];
if(k > 11 && k < 14) e_net.type[k] = buf[k];
if(k > 13 && k < 53) e_net.data[k] = buf[k];
}
cout << "\n\npacket " << packet_number << " - length "
<< packet_size << " bytes:\n Eth Dest: ";
for(k = 0; k < 6; ++k)
{
one_byte = e_net.destination[k]; //convert to size_t
if(one_byte < 16) cout << '0';
cout << std::hex << one_byte << std::dec; //output in hex
if(k != 5) cout << ":";
}
cout << "\n Eth Src: ";
for(k = 6; k < 12; ++k)
{
one_byte = e_net.source[k]; //convert to size_t
if(one_byte < 16) cout << '0';
cout << std::hex << one_byte << std::dec; //output in hex
if(k != 11) cout << ":";
}
cout << "\n Eth Type: ";
for(k = 12; k < 14; ++k)
{
one_byte = e_net.type[k]; //convert to size_t
cout << std::hex << std::showbase << one_byte //output in hex
<< std::noshowbase << std::dec;
}
cout << endl << " Eth Data:\n ";
for(k = 14; k < 53; ++k)
{
one_byte = e_net.data[k];
if(k == 33) cout << "\n "; //20 bytes per line
else
{
if(one_byte < 16) cout << '0';
cout << std::hex << one_byte << std::dec << " ";
}
}
}
//****************************************************************************
//
// Function: option_h
//
// Purpose: If the -h flag is given in the command line or someone enters
// an invalid command argument, this will print out options.
//
// Parameters: none
//
// Calls: exit
//
//****************************************************************************
void option_h()
{
cout << "-d To print debugging information.\n"
<< "-l List all interfaces and exit.\n"
<< "-g NUM Use group NUM. If NUM is ommitted then " << DEFAULT_GROUP
<< " will be used.\n"
<< "-i IFACE Use interface IFACE. Use first interface"
<< " if IFACE is ommitted.\n"
<< "-h Print a quick summary of the command line arguments"
<< " and exit.\n";
exit(EXIT_SUCCESS);
}
//****************************************************************************
//
// Function: option_l
//
// Purpose: If the -l flag is given in the command line this will print
// all the names and addresses of network devices on a computer.
//
// Parameters: all_lans - linked list that holds all network addresses and
// names of them on the computer
// lan_ptr - pointer to the head of the linked list
//
// Calls: exit
//
//****************************************************************************
void option_l(lanlist* all_lans, _lan* lan_ptr)
{
for(int j(0); j < all_lans -> cnt; ++j)
{
cout << "name = " << lan_ptr -> lname << endl;
cout << "addr = " << lan_ptr -> hwaddr << endl << endl;
lan_ptr = lan_ptr -> next;
}
exit(EXIT_SUCCESS);
}
//****************************************************************************
//
// Function: option_g
//
// Purpose: If the -g NUM flag is given in the command line this will
// change the group to NUM as long as NUM is in [0, 63]
//
// Parameters: argc - number of command line arguments
// argv - the commmand line arguments
// i - position in the command line arguments
//
// Calls: none
//
//****************************************************************************
void option_g(int argc, char** argv, unsigned& group, int& i)
{
if(i < argc - 1 && argv[i + 1][0] != char(45))
{ //true if -g isn't last command and -g has numbers after it
group = argv[++i][0] - 48; //ascii for zero is 48
if(argv[i][1] != '\0') //true if the group is greater than ten
{
group = (group * 10) + (argv[i][1] - 48);
if(argv[i][2] != '\0') //true if the group is greater than 99
{
cout << "INVALID group number. Defaulting to "
<< DEFAULT_GROUP << ".\n";
group = DEFAULT_GROUP;
}
}
}
if(group > 63) //valid range of group numbers is 0 - 63
{
cout << "INVALID group number. Defaulting to " << DEFAULT_GROUP << ".\n";
group = DEFAULT_GROUP;
}
}
//****************************************************************************
//
// Function: option_i
//
// Purpose: If the -i IFACE flag is given in the command line this will
// change the interface name to IFACE if it is valid.
//
// Parameters: argc - number of command line arguments
// argv - the commmand line arguments
// group - the group the packets are sent to
// i - position in the command line arguments
// interface - the name of the interface being used
// all_lans - linked list that holds all network addresses and
// names of them on the computer
//
// Calls: strncmp
//
//****************************************************************************
void option_i(int argc, char** argv, unsigned& group, int& i,
char*& interface, lanlist* all_lans)
{
_lan* temp_lan_ptr = all_lans -> lan;
bool good_iface_name = false;
if(i < argc - 1 && argv[i + 1][0] != char(45)) //check if next arg starts
{ //with a '-'
++i;
for(int j(0); j < all_lans -> cnt; ++j)
{
if(strncmp(temp_lan_ptr -> lname, argv[i], INTERFACE_NAME_LENGTH) == 0)
{ //the given arguemnt to -i is a good one.
good_iface_name = true;
}
temp_lan_ptr = temp_lan_ptr -> next;
}
if(good_iface_name)
{ //the given IFACE is a valid one, let's use it.
interface = argv[i];
}
else
{ //the given argument to -i was invalid so we'll use the first one
cout << "INVALID interface name. Defaulting to " << interface << endl;
}
}
}