I have lots of Drytek > Vigor 2700,2800 routers on the public net. I manage this networks and since this type of routers has Log support I write an application on my linux box to collect those logs.
The routers are sending UDP datagrams to a configurable address and port. Each datagram has one status message. My program collects each datagram from several routers and put them into log files.
The message datagrams has a three digit code on the beginning of the stream. Each code belongs to a different type of status info.
My program is running and the logs are ok. I just want to put it on the production server and before I do so I want to make my code comply with the basic rules of programming.
I am not experienced programmer so I know that in my code there can be lots of mistakes. This is why I need a help and comments of experienced programmers.
I simplify my code to be as short as possible.
char buf1[128];
char buf2[128];
char buf3[128];
int DisplayUpdate() {
// Creating the file streams for different kind of log types
// There are 3 major data types for output: adsl status, local user
// connections and other
// adsl status - sends periodically info about the up and download
// speeds and the technical parameters of the ADSL link
// local user - notifies each activity from the local network to the public
// There are other types of data which are not interesting for me now
// Like: PPOE, VPN, Router Config Access, Rebooting of router...
// Each data type has its three digit code at the stream beginning, based
// upon this number I separate the logs
ofstream adslstatus1("ADSL_status1.log", ios::app);
ofstream adslstatus2 ...
ofstream localuser1("Local_user1.log", ios::app);
ofstream localuser2 ...
ofstream other1("other1.log", ios::app);
ofstream other2 ...
// ADSL status
for(int readline1=1; readline1<5; readline1++)
{
if(buf1[readline1]=='1') {
// The three digit code 174 is for ADSL status
if(buf1[readline1+1]=='7') {
if(buf1[readline1+2]=='4') {
adslstatus1 << "router 1: ";
// We don't show the ADSL status on the screen for now
// therefor each cout is commented out, maybe later it will be
// choosable option to show different info on the screen
// cout << "router 1: ";
for(int printline1=5; printline1<20; printline1++) {
// Writes the date into the Log.
adslstatus1 << buf1[printline1];
// cout << buf1[printline1];
}
adslstatus1 << " > ";
// cout << " > ";
for(int printline1=41; printline1<128; printline1++) {
// Writes the status data into the Log
adslstatus1 << buf1[printline1];
// cout << buf1[printline1];
}
adslstatus1 << endl;
// cout << endl;
}
}
}
}
// Each router has its own Log. For now it supports 3 routers. I have now
// upto 10 routers outside which I want to Log.
// ADSL Status roter 2
// This loop is repeated for router 2 and 3
// And same kind of loop for type codes 150 - localuser connection info
// 150 for router 2 and 3
// 166 - PPOE and VPN and same loop type for router 2 and 3
for(int readline1=1; readline1<5; readline1++)
....
// Exiting Display update function
return 1;
}
[B]MAIN Function[/B]
[B]int main(int argc, char *argv[])
{[/B]
// Creating the log collectors address structs - my_addr1,2,3 for 3
// routers and the client address structs their_addr1,2,3.
// We create the polling struct for each listening socket - ufds.
[B]struct sockaddr_in my_addr1, my_addr2, my_addr3;
struct sockaddr_in their_addr1, their_addr2, their_addr3;
struct pollfd ufds[3];[/B]
// Creating variables for the address size.
[B]socklen_t sin_size1, sin_size2, sin_size3, fromlen1, fromlen2, fromlen3;
int byte_count1, byte_count2, byte_count3;[/B]
[B]int sockfd1, sockfd2, sockfd3, new_fd1, new_fd2, new_fd3;[/B]
// Setting the address values in addresse structures. The ports
// where the server listens for incoming log datagrams for each
// router different and the IP address of our own socket
[B]my_addr1.sin_family = AF_INET;
my_addr1.sin_port = htons(11111);
my_addr1.sin_addr.s_addr = inet_addr("192.168.1.5");
memset(my_addr1.sin_zero, '\0', sizeof my_addr1.sin_zero);[/B]
// Same for router 2 and 3
[B]my_addr2.sin_family = AF_INET;
my_addr2.sin_port = htons(11112);
my_addr2.sin_addr.s_addr = inet_addr("192.168.1.5");
memset(my_addr2.sin_zero, '\0', sizeof my_addr2.sin_zero);[/B]
[B]my_addr3.sin_family = AF_INET;[/B]
...
// Creating sockets
[B]sockfd1 = socket(PF_INET, SOCK_DGRAM, 0);
sockfd2 and 3 ...[/B]
// Binding the sockets to addresses
[B]bind(sockfd1, (struct sockaddr *)&my_addr1, sizeof my_addr1);
bind(sockfd2, 3 ...
[/B]
// Setting them to listen and poll with the queue of 10 waiting
// connections for each socket, router
[B]listen(sockfd1, 10);
listen(sockfd2 ...[/B]
// Size of each address struct
[B]
sin_size1 = sizeof their_addr1;
sin_size2 ...[/B]
// accepting connections
[B]new_fd1 = accept(sockfd1, (struct sockaddr *)&their_addr1, &sin_size1);
new_fd2 ...[/B]
// Ok, each datagram is going into the main log file, so we create
// the file stream for them
[B]ofstream log("router.log", ios::app);[/B]
// As we are listening on more sockets and the received data are
// randomly arriving we need to poll for activity on them.
// The rv is the temporrary returnvalue which is tested and based on
// the status the poll function returns which connection has news
// for us We set the fd socket descriptor for each polling ufds structure.
[B]int rv;
ufds[0].fd = sockfd1;
ufds[0].events = POLLIN;
ufds[1].fd [/B] ... // Same for 2 and 3
[B]for(int b=0;b<2;b++) // Eternal loop for receiving datagrams
{[/B]
// We clear the buffers where we will store the received data. Three
// 128 char big buffers will be good for now.
[B] for(int c=0;c<128;c++) {
buf1[c] = ' ';
buf2[c] = ' ';
buf3[c] = ' ';
}[/B]
// And so we call the poll function which returnes the rv descriptor
// to let us know which shocket gets data.
// The poll function has 3 sockets for checking and one second -
// 1000 ms - to timeout for each socket. This can be later less.
[B]rv = poll(ufds, 3, 1000);
if (rv == -1) {[/B]
[B]} else if(rv == 0) {[/B]
// printf("... router timeout occured ...\n");
[B]} else {[/B]
// We are intrested for POLLIN signal on each socket so when
// the .revents member gets POLLIN the socket has data for us
// After this we can call the recvfrom function for the particular
// socket We put the data into the actual buffer buf1,2,3, and imediatelly
// write it into the main log file.
[B]if (ufds[0].revents & POLLIN) {
byte_count1 = recvfrom(sockfd1, buf1, 128, MSG_OOB, (struct sockaddr *)&their_addr1, &fromlen1);
log << "router 1: ";
for(int a=0;a<128;a++) {
log << buf1[a];
}
log << endl;
}
if (ufds[1].revents & POLLIN) [/B] .... // same for 2 and 3
// We fill the logical status values, b=0 for the main loop,
[B]b=0;[/B]
// And call the DisplayUpdate function to print the received data to
// the screen and process them into separate Log files
// now separating them to groups of kind.
[B]DisplayUpdate();
}
return EXIT_SUCCESS;
}[/B]
// End of Main function
I know there should be a lots of error checks but please remind me each of them and I will put them in.
It is possible that I will redesigne the whole code because of:
Put the possibilitie of configuration the ports, addresses the number of routers
And for displaying data on the screen choose a summary display and each router separately.
Thanks for ANY suggestion...