My networking professor handed out a group project to build a virtual token ring network and I thought I would share my findings here. Before you say anything, I know it is not a true token ring network, but it sorta acts like one which was more the goal of the project.
My group partner and I went through several different models, which included; building a virtual DHCP server and virtual cables, telling the program at run time who it’s neighbor was, sending out a broadcast and having the virtual nodes organize themselves into a network, and a few others. We finally settled on pulling out a switch and creating a network of static IPs that we controlled. The program attempts to send to the next IP number from itself and if it cannot find it the token is sent to the first node. An unintended side effect is that we have the ability to add and remove machines at the highest IP number without breaking the ring. The requirement was only that it worked with three machines.
This code is not the cleanest, nor is it in any way awesome, and there are probably a ton of things I can take out of it to make it better, but it runs beautifully on the Dell Mini 10s running Ubuntu that I tested it on with a 5 port Netgear switch. Just make sure your network is in the range 192.168.0.1 and the machines go in sequential order (e.g. 192.168.0.1, 192.168.0.2, 192.168.0.3)
/*
* Virtual Token Ring Network
*
* Networking II
* Spring 2009-2010
* Prof: Xueyi Wang
* Group: Ben Lobaugh, Jake Bodenstab
*
* Project Description: Sorta creates a virtual token
* ring network simulation
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
// Global Constants and Variables
int PORT = 55555, node, s_sockfd , s_clilen, s_n;
struct message{
int sender;
int receiver;
string message;
};
struct token{
int type; // 1 = empty token, 2 = token with data
int valid;
message msg;
int checksum;
int turn;
};
struct sockaddr_in s_serv_addr, s_cli_addr;
// Function Definitions
void getToken(char* token);
void sendToken(char* token);
bool messageExists();
void createServerSocket();
void error(string msg);
int main(int argc, char** argv) {
char* token;
string start_token;
node = atoi(argv[1]);
cout << "Node: " << node << endl << endl;
createServerSocket();
if(node == 1) {
cout << "Start token? (y/n): ";
cin >> start_token;
if(start_token.compare("y") == 0) {
cout << "\nInitializing Token\n";
sendToken(token);
}
}
cout << "**** Ctrl-C Terminates **** \n\n";
while(1) {
getToken(token);
if(token[0] == 2) {
// Token Contains a message
if(token[2] == node) {
// Message is from us. Erase it and change token type to 1
token[2] = -1;
token [3] = -1;
token[4] = -1;
token[0] = 1;
} else if(token[3] == node) {
// Message in token is for us. Display it
cout << "--------------\n";
cout << "From: " << token[2] << endl;
//cout << token.msg.message << endl;
}
} else if(token[0] == 1) {
// Token does not contain a message
if(messageExists()) {
// There is a message to send. Load message into token and change type
// Open file ./message.tok
// Read first line as the receiver
// Rest of file is message
token[0] = 2;
}
} else {
// This token is a type we do not know about
// Don't worry about this token, just forward it
}
sleep(2);
// Send token along it's merry way
sendToken(token);
}
return (EXIT_SUCCESS);
}
void getToken(char* token) {
int newsockfd;
/*
* Create a server socket on PORT
* Listen on socket until message is received
* If message is of type token load it into token
* Close socket
* Return filled token
*/
listen(s_sockfd,5);
s_clilen = sizeof(s_cli_addr);
newsockfd = accept(s_sockfd,
(struct sockaddr *) &s_cli_addr,
(socklen_t*) &s_clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(token,256);
s_n = read(newsockfd,token,255);
if (s_n < 0) error("ERROR reading from socket");
cout << "I've got the token\n";
}
void createServerSocket() {
s_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (s_sockfd < 0)
error("ERROR opening socket");
int on = 1;
if ( setsockopt ( s_sockfd, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 )
error("ERROR setting socket options");
bzero((char *) &s_serv_addr, sizeof(s_serv_addr));
s_serv_addr.sin_family = AF_INET;
s_serv_addr.sin_addr.s_addr = INADDR_ANY;
s_serv_addr.sin_port = htons(PORT);
if (bind(s_sockfd, (struct sockaddr *) &s_serv_addr, sizeof(s_serv_addr)) < 0)
error("ERROR on binding");
}
void sendToken(char* token) {
int to;
string ip = "192.168.0.";
// Start Socket Vars
int sockfd, n;
struct sockaddr_in serv_addr;
struct hostent *server;
// End Socket Vars
// Find the next node to send to
to = node + 1;
std::ostringstream sin;
sin << to;
std::string val = sin.str();
ip.append(val);
/*
* Create socket connection to next node
* Send token
* Close socket
*/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
try {
server = gethostbyname(ip.c_str());
if (server == NULL) {
error("ERROR, no such host\n");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(PORT);
if (connect(sockfd, (struct sockaddr*) &serv_addr,sizeof(serv_addr)) < 0)
throw 1;//("ERROR connecting");
cout << "Token Sent To: 192.168.0." << to << endl << endl;
} catch (int i) {
cout << "Could not contact " << ip << " sending to 192.168.0.1\n\n";
server = gethostbyname("192.168.0.1");
if (server == NULL) {
error("ERROR, no such host\n");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(PORT);
if (connect(sockfd, (struct sockaddr*) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
}
bzero(token,256);
n = write(sockfd,token,strlen(token));
if (n < 0)
error("ERROR writing to socket");
close(sockfd);
unlink(ip.c_str());
}
bool messageExists() {
bool ret = false;
return ret;
}
void error(string msg) {
perror(msg.c_str());
exit(0);
}