gint get_seconds_for_today (void) { TIME time; struct tm *tm_today; tm_today = get_tm_struct(); time.hour = tm_today->tm_hour; time.minute = tm_today->tm_min; time.second = tm_today->tm_sec; return time_to_seconds (&time); }
int main(int argc, char**argv) { //Iterator int i; //Port number int port; //Host file string hostfile; //count of messages to be sent int count; //Delivery queue map<Key,DM*> delivery_queue; //Delivered Messages vector<Key> delivered_queue; //Map to store Hostname to IP address map<string,string> host_to_id; //Map to store Hostname to id map<string,int> hostname_to_id; //Map to maintain retransmission info map<string,bool> host_retransmit_info; //buffer to hold a recieved message char *mesg = (char *)malloc(sizeof(AckMessage)); if(argc < 7) { kprintf("Usage: "); kprintf("proj2 -p port -h hostfile -c count"); exit(EXIT_FAILURE); } for(i=0;i<argc;i++) { string arg = argv[i]; if(arg == "-p") { if(argv[i+1]) { string temp = argv[i+1]; port = atoi(temp.c_str()); if(port == 0 || port <=1024) { kprintf("Invalid port. Please specify a port greater than 1024"); exit(EXIT_FAILURE); } i = i + 1; } else { kprintf("Please specify port number"); exit(EXIT_FAILURE); } } if(arg == "-h") { if(argv[i+1]) { hostfile = argv[i+1]; i = i + 1; } else { kprintf("Please specify host file"); exit(EXIT_FAILURE); } } if(arg == "-c") { if(argv[i+1]) { string temp = argv[i+1]; count = atoi(temp.c_str()); i = i + 1; if(count < 0) { kprintf("Number of messages to be multicast must be greater than zero"); exit(EXIT_FAILURE); } } else { kprintf("Please specify number of messages to be multicast"); exit(EXIT_FAILURE); } } } kprintf("Port: ",port); kprintf("Hostfile: ",hostfile); kprintf("Count: ",count); ifstream hostfile_stream(hostfile.c_str()); string hostname; int host_id = 0; if(hostfile_stream.is_open()) { while(hostfile_stream.good()) { getline(hostfile_stream,hostname); if(!hostname.empty()) { hostname_to_id[hostname] = host_id++; //Get IP address struct hostent *hp; hp = gethostbyname(hostname.c_str()); if(!hp) { kprintf(" not found ",hostname); exit(EXIT_FAILURE); } if((inet_ntoa(*(struct in_addr *)hp->h_addr_list[0]))) { string s_local(inet_ntoa(*(struct in_addr *)hp->h_addr_list[0])); kprintf(s_local.c_str()); if(s_local.find("127") != 0) { host_to_id[hostname] = s_local; host_retransmit_info[s_local] = false; } else { host_to_id[hostname] = string(inet_ntoa(*(struct in_addr *)hp->h_addr_list[1])); host_retransmit_info[string(inet_ntoa(*(struct in_addr *)hp->h_addr_list[1]))] = false; } } else { host_to_id[hostname] = string(inet_ntoa(*(struct in_addr *)hp->h_addr_list[1])); host_retransmit_info[string(inet_ntoa(*(struct in_addr *)hp->h_addr_list[1]))] = false; } kprintf(hostname.c_str()); } } hostfile_stream.close(); } else { kprintf("Unable to read host file"); exit(EXIT_FAILURE); } kprintf("Size is: ",host_to_id.at("xinu01.cs.purdue.edu")); //get my hostname char myhostname[HOSTNAME_LEN]; gethostname(myhostname,HOSTNAME_LEN); string myhostname_str(myhostname); host_retransmit_info[host_to_id[myhostname_str]] = true; //Iterator for sending messages int iter=0; //Seq numbers to be maintained throughout int max_last_proposed_seq_num=0; int last_proposed_seq_num = 0; //Socket variables int sockfd,n; struct sockaddr_in servaddr,cliaddr; socklen_t lensock; sockfd = socket(AF_INET,SOCK_DGRAM,0); if(sockfd == -1) { kprintf("Could not create socket"); exit(EXIT_FAILURE); } bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(port); int bval = bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); if(bval==-1) { kprintf("Bind failed\n"); exit(EXIT_FAILURE); } //Multiset to maintain all the sequence numbers recieved in Acks multiset<int> ackmultiset; //infinite loop for the protocol while(1) { //Send message to all other hosts/processes only if iter<count if(iter<count) { DataMessage *init_dm = (DataMessage *)malloc(sizeof(DataMessage)); init_dm->type = TYPE_DM; init_dm->sender = hostname_to_id[myhostname_str]; //Get sender ID kprintf("Sender ID: ",init_dm->sender); init_dm->msg_id = iter; init_dm->data = iter; host_network(init_dm); for(map<string,string>::iterator it = host_to_id.begin();it != host_to_id.end();++it) { if(host_retransmit_info[it->second.c_str()] == false) { cliaddr.sin_family = AF_INET; cliaddr.sin_addr.s_addr = inet_addr(it->second.c_str()); cliaddr.sin_port = htons(port); int rval = sendto(sockfd,init_dm,sizeof(DataMessage),0,(struct sockaddr *)&cliaddr,sizeof(cliaddr)); kprintf("Sent message ",it->second.c_str()); } } network_host(init_dm); Key current_srch_key (last_proposed_seq_num,hostname_to_id[myhostname_str]); //Add the sent message to your queue if it does not already exist if(delivery_queue.find(current_srch_key) == delivery_queue.end()) { DM* sent_msg = (DM*)malloc(sizeof(DM)); sent_msg->deliverable = false; sent_msg->seq_num = ++max_last_proposed_seq_num; sent_msg->data_msg = init_dm; Key current_key (sent_msg->seq_num,hostname_to_id[myhostname_str]); last_proposed_seq_num = max_last_proposed_seq_num; //Add the sent message to your queue delivery_queue[current_key] = sent_msg; kprintf("Inserted in delivery queue",current_key.seq); } } //Start Recieving messages here //start ack timer struct timeval time_ack,time_curr_ack; get_now(&time_ack); while(time_to_seconds(&time_ack,get_now(&time_curr_ack)) <= UDP_RETRANSMIT_TIMER) { socklen_t lensock = sizeof(cliaddr); if((n = recvfrom(sockfd,mesg,sizeof(AckMessage),MSG_DONTWAIT,(struct sockaddr *)&cliaddr,&lensock)) > 0) { //Get the type by converting from network to host uint32_t* recv_type = (uint32_t*)malloc(sizeof(uint32_t)); memcpy(recv_type,mesg,sizeof(uint32_t)); int type = *recv_type; type = ntohl(type); kprintf("Recieved Type",type); if(type == TYPE_ACK) { AckMessage* ack_mesg = (AckMessage*)mesg; network_host(ack_mesg); int sender = hostname_to_id[myhostname_str]; if(ack_mesg->receiver == sender && iter == ack_mesg->msg_id) { //Mark Ack recieved string ip = string(inet_ntoa(cliaddr.sin_addr)); if(host_retransmit_info.find(ip) != host_retransmit_info.end()) { host_retransmit_info[ip] = true; kprintf("Marked true for ip ",ip.c_str()); } } ackmultiset.insert(ack_mesg->proposed_seq); } else if(type == TYPE_DM) { //Check if it is delivered DataMessage* dm_mesg = (DataMessage*) mesg; network_host(dm_mesg); int msg_id = dm_mesg->msg_id; int sender = dm_mesg->sender; bool delivered = false; for(vector<Key>:: iterator it=delivered_queue.begin();it!=delivered_queue.end();++it) { if((*it).seq == msg_id && (*it).pid == sender) { delivered = true; } } //Check if in ready queue bool inreadyqueue = false; for(map<Key,DM*>:: iterator it=delivery_queue.begin();it!=delivery_queue.end();it++) { if((it->second)->data_msg->msg_id == msg_id && (it->second)->data_msg->sender == sender) inreadyqueue = true; } //if not in ready queue or delivered if(delivered == false && inreadyqueue == false) { //Send Ack AckMessage* ack_mesg = (AckMessage*)malloc(sizeof(AckMessage)); ack_mesg->type = TYPE_ACK; ack_mesg->sender = hostname_to_id[myhostname_str]; ack_mesg->msg_id = msg_id; ack_mesg->proposed_seq = ++max_last_proposed_seq_num; ack_mesg->receiver = sender; host_network(ack_mesg); //Send ack to the sender string ip = string(inet_ntoa(cliaddr.sin_addr)); cliaddr.sin_family = AF_INET; cliaddr.sin_addr.s_addr = inet_addr(ip.c_str()); cliaddr.sin_port = htons(port); int rval = sendto(sockfd,ack_mesg,sizeof(AckMessage),0,(struct sockaddr *)&cliaddr,sizeof(cliaddr)); kprintf("Sent Ack to ",ip.c_str()); //Store in Queue ******************** string current_hostname; for(map<string,string>:: iterator it=host_to_id.begin(); it!=host_to_id.end(); it++) { if((it->second).compare(ip) == 0) current_hostname = it->first; } DataMessage *init_dm = (DataMessage *)malloc(sizeof(DataMessage)); init_dm->type = TYPE_DM; init_dm->sender = hostname_to_id[current_hostname]; init_dm->msg_id = msg_id; init_dm->data = dm_mesg->data; DM* sent_msg = (DM*)malloc(sizeof(DM)); sent_msg->deliverable = false; sent_msg->seq_num = max_last_proposed_seq_num; sent_msg->data_msg = init_dm; Key current_key (sent_msg->seq_num,hostname_to_id[current_hostname]); last_proposed_seq_num = max_last_proposed_seq_num; //Add the sent message to your queue delivery_queue[current_key] = sent_msg; kprintf("Inserted in delivery queue",current_key.seq); } } else if(type == TYPE_SEQ_MSG) { SeqMessage* seq_mesg = (SeqMessage*)mesg; network_host(seq_mesg); int msg_id = seq_mesg->msg_id; int sender = seq_mesg->sender; //Search in delivery queue for the corresponding message for(map<Key,DM*>:: iterator it=delivery_queue.begin();it!=delivery_queue.end();it++) { if((it->second)->data_msg->msg_id == msg_id && (it->second)->data_msg->sender == sender) { (it->second)->deliverable = true; (it->second)->seq_num = seq_mesg->final_seq; } } max_last_proposed_seq_num = seq_mesg->final_seq; deliver_messages(&delivery_queue,&delivered_queue,hostname_to_id[myhostname_str]); kprintf("Got final seq message", seq_mesg->msg_id); } } } //go for next message if(check(host_retransmit_info)) { kprintf("After check"); //Get the maximum sequence number recieved int max = *(ackmultiset.rbegin()); kprintf("Max is",max); //Update the max proposed seq num for next message if(max_last_proposed_seq_num < max) max_last_proposed_seq_num = max; //Build the final seq message SeqMessage* final_seq_msg = (SeqMessage *)malloc(sizeof(SeqMessage)); final_seq_msg->type = TYPE_SEQ_MSG; final_seq_msg->sender = hostname_to_id[myhostname_str]; final_seq_msg->msg_id = iter; final_seq_msg->final_seq = max; host_network(final_seq_msg); //send it to everyone for(map<string,string>::iterator it = host_to_id.begin();it != host_to_id.end();++it) { if(myhostname_str.compare(it->first) !=0) { cliaddr.sin_family = AF_INET; cliaddr.sin_addr.s_addr = inet_addr(it->second.c_str()); cliaddr.sin_port = htons(port); int rval = sendto(sockfd,final_seq_msg,sizeof(SeqMessage),0,(struct sockaddr *)&cliaddr,sizeof(cliaddr)); kprintf("Sent final sequence message ",it->second.c_str()); } } int msg_id_srch = iter; int sender = hostname_to_id[myhostname_str]; //update the message in delivery queue with the final sequence number for(map<Key,DM*>:: iterator it = delivery_queue.begin();it != delivery_queue.end();++it) { if(it->second->data_msg->sender == sender && it->second->data_msg->msg_id == msg_id_srch) { //Prepare new message DM* updatedDM = (DM*)malloc(sizeof(DM)); updatedDM->data_msg = it->second->data_msg; updatedDM->deliverable = true; updatedDM->seq_num = max; //erase the old msg delivery_queue.erase(it); //Prepare new key Key updated_key(max,sender); //Update queue delivery_queue[updated_key] = updatedDM; kprintf("Found the message and marked deliverable and updated sequence number too",updatedDM->seq_num); } } //deliver messages deliver_messages(&delivery_queue,&delivered_queue,hostname_to_id[myhostname_str]); iter++; //Reinitialize for new message host_retransmit_info = reinit(host_retransmit_info,host_to_id[myhostname_str]); //Reinitialize ack multiset ackmultiset = reinit_set(ackmultiset); } } }
int main( int argc, char **argv ) { /* Options with their defaults */ unsigned short opt_buffer = DEFAULT_BUFFER; unsigned short opt_daemon = 0; unsigned short opt_debug = 0; char *opt_filename = NULL; unsigned short opt_port = DEFAULT_PORT; unsigned short opt_reply = 0; int option; /* Program logic */ unsigned short debug_counter = DEFAULT_LOOPS; int client_length; int recv_bytes; int status; static char tcp_options_text[MAX_TCPOPT]; /* Our process ID and Session ID */ pid_t pid, sid; /* We won't run as root */ /* if ( geteuid() == 0 ) { fprintf(stderr,"This program is not intended to run as superuser.\n"); fprintf(stderr,"Please use a non-privileged user instead.\n"); exit(EXIT_FAILURE); }* /* Parse options */ while ( (option = getopt(argc, argv, "b:dD:f:hrp:")) != -1 ) { switch ( option ) { case 'b': opt_buffer = (unsigned short)( strtoul( optarg, NULL, 10 ) ); if ( opt_buffer < MIN_BUFFER ) { opt_buffer = MIN_BUFFER; } break; case 'd': opt_daemon = 1; break; case 'D': opt_debug = (unsigned short)( strtoul( optarg, NULL, 10 ) ); break; case 'f': opt_filename = optarg; break; case 'h': puts("Welcome to tcpsnoop!\\" "Usage: tcpsnoop [-d] [-D debuglevel] [-f filename] [-h] [-p tcpport] [-b buffersize]"); exit(EXIT_SUCCESS); break; case 'p': opt_port = (unsigned short)( strtoul( optarg, NULL, 10 ) ); if ( opt_port < 1024 ) { fprintf(stderr,"We can't bind to port %u! It is privileged.\n",opt_port); exit(EXIT_FAILURE); } break; case 'r': opt_reply = 1; break; } } if ( opt_filename == NULL ) { opt_filename = (char *)default_filename; } /* Check for debug level. */ if ( opt_debug > 0 ) { printf("Welcome to debug level %d!\n\\" "Will listen on port %u and write to file %s.\n\\" "Will allocate %u bytes for TCP buffer\n", opt_debug,opt_port,opt_filename,opt_buffer); /* We don't allow daemon mode when debug mode is active, no * matter whether the daemon option is present or not. * */ opt_daemon = 0; } if ( opt_daemon != 0 ) { syslog( LOG_DAEMON | LOG_INFO, "Starting daemon mode."); } /* Check if we should go into daemon mode */ if ( opt_daemon != 0 ) { /* Fork and get a PID. */ pid = fork(); /* Check if forking was successful */ if ( pid < 0 ) { fprintf(stderr,"fork() failed!\n"); exit(EXIT_FAILURE); } if ( pid > 0 ) { syslog( LOG_DAEMON | LOG_INFO, "Got PID %u.", pid ); exit(EXIT_SUCCESS); } } /* Set umask */ umask(022); /* Here we open logs and files we probably need */ /* * */ openlog( SYSLOG_IDENTITY, LOG_PID, LOG_DAEMON ); statistics = fopen( opt_filename, "a+" ); if ( statistics == NULL ) { if ( opt_debug > 0 ) { fprintf(stderr,"Could not open statistics file: %s\n",strerror(errno)); } else { syslog( LOG_DAEMON | LOG_CRIT, "Could not open statistics file: %s", strerror(errno) ); exit(EXIT_FAILURE); } } /* Create a new SID for the child process */ if ( opt_daemon != 0 ) { sid = setsid(); if (sid < 0) { /* Could not aquire new SID. */ syslog( LOG_DAEMON | LOG_CRIT, "%s", "Could not aquire new SID." ); exit(EXIT_FAILURE); } /* Close standard file descriptors since daemons don't do standard * I/O. They need to use log files or syslog instead */ fclose(stdout); fclose(stdin); fclose(stderr); set_signal_handlers(); } /* Prepare TCP socket. */ tcp_socket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); if ( tcp_socket == -1 ) { /* Could not open socket. */ if ( opt_debug > 0 ) { fprintf(stderr,"Could not open TCP socket: %s\n",strerror(errno)); } else { syslog( LOG_DAEMON | LOG_CRIT, "Could not open TCP socket: %s", strerror(errno) ); } exit(EXIT_FAILURE); } else { /* Bind to any address on local machine */ server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = inet_addr("10.0.1.2"); server_address.sin_port = htons(opt_port); memset((void *)&(server_address.sin_zero), '\0', 8); status = bind( tcp_socket, (struct sockaddr *)&server_address, sizeof(server_address) ); if ( status == 0 ) { /* We can now listen for incoming connections. We only allow a backlog of one * connection */ status = listen( tcp_socket, 1 ); if ( status != 0 ) { /* Cannot listen on socket. */ if ( opt_debug > 0 ) { fprintf(stderr,"Cannot listen on socket: %s\n",strerror(errno)); } else { syslog( LOG_DAEMON | LOG_CRIT, "Cannot listen on socket: %s", strerror(errno) ); } exit(EXIT_FAILURE); } } else { /* Cannot bind to socket. */ if ( opt_debug > 0 ) { fprintf(stderr,"Cannot bind to socket: %s\n",strerror(errno)); } else { syslog( LOG_DAEMON | LOG_CRIT, "Cannot bind to socket: %s", strerror(errno) ); } exit(EXIT_FAILURE); } } /* Allocate Buffer for TCP stream data. * (We store it temporarily only since we act as an TCP sink.) */ tcp_buffer = malloc(opt_buffer); if ( tcp_buffer == NULL ) { if ( opt_debug > 0 ) { fprintf(stderr,"Can't allocate buffer for TCP temporary memory.\n"); } else { syslog( LOG_DAEMON | LOG_CRIT, "Can't allocate buffer for TCP temporary memory.\n" ); } exit(EXIT_FAILURE); } /* Our main loop where we wait for (a) TCP connection(s). */ if ( opt_debug > 0 ) { puts("Entering main loop."); } while ( debug_counter > 0 ) { client_length = sizeof(client_address); tcp_work_socket = accept( tcp_socket, (struct sockaddr *)&client_address, (socklen_t *)&client_length ); /* Get time for counting milliseconds. */ get_now( &time_start, opt_debug ); /* As soon as we got a connection, we deal with the incoming data by using * a second socket. We only read as much as opt_buffer bytes. */ if ( (recv_bytes = recv( tcp_work_socket, tcp_buffer, opt_buffer, 0 ) ) > 0 ) { /* Fill tcp_info structure with data to get the TCP options and the client's * name. */ tcp_info_length = sizeof(tcp_info); if ( getsockopt( tcp_work_socket, SOL_IP, TCP_INFO, (void *)&tcp_info, (socklen_t *)&tcp_info_length ) == 0 ) { memset((void *)tcp_options_text, 0, MAX_TCPOPT); decode_tcp_options(tcp_options_text,tcp_info.tcpi_options); if ( opt_debug > 0 ) { printf("Got a new connection from client %s.\n",inet_ntoa(client_address.sin_addr)); } else { syslog( LOG_DAEMON | LOG_INFO, "Received connection from client at address %s.", inet_ntoa(client_address.sin_addr)); } /* Write some statistics and start of connection to log file. */ fprintf(statistics,"# Received connection from %s (AdvMSS %u, PMTU %u, options (%0.X): %s)\n", inet_ntoa(client_address.sin_addr), tcp_info.tcpi_advmss, tcp_info.tcpi_pmtu, tcp_info.tcpi_options, tcp_options_text ); } } while ( (recv_bytes = recv( tcp_work_socket, tcp_buffer, opt_buffer, 0 ) ) > 0 ) { if ( opt_debug > 0 ) { printf("\nReceived %d bytes on socket.\n",recv_bytes); } /* Measure time in order to create time intervals. */ get_now( &time_now, opt_debug ); /* Fill tcp_info structure with data */ tcp_info_length = sizeof(tcp_info); if ( getsockopt( tcp_work_socket, SOL_TCP, TCP_INFO, (void *)&tcp_info, (socklen_t *)&tcp_info_length ) == 0 ) { if ( opt_debug > 0 ) { printf("snd_cwnd: %u\nsnd_ssthresh: %u\nrcv_ssthresh: %u\nrtt: %u\nrtt_var: %u\n", tcp_info.tcpi_snd_cwnd, tcp_info.tcpi_snd_ssthresh, tcp_info.tcpi_rcv_ssthresh, tcp_info.tcpi_rtt, tcp_info.tcpi_rttvar ); } fprintf(statistics,"%.6f %u %u %u %u %u %u %u %u %u %u %u %u\n", time_to_seconds( &time_start, &time_now ), tcp_info.tcpi_last_data_sent, tcp_info.tcpi_last_data_recv, tcp_info.tcpi_snd_cwnd, tcp_info.tcpi_snd_ssthresh, tcp_info.tcpi_rcv_ssthresh, tcp_info.tcpi_rtt, tcp_info.tcpi_rttvar, tcp_info.tcpi_unacked, tcp_info.tcpi_sacked, tcp_info.tcpi_lost, tcp_info.tcpi_retrans, tcp_info.tcpi_fackets ); if ( fflush(statistics) != 0 ) { if ( opt_debug > 0 ) { fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno) ); } else { syslog( LOG_DAEMON | LOG_CRIT, "Cannot flush buffers: %s", strerror(errno) ); } } /* Send reply text via TCP connection */ if ( opt_reply != 0 ) { reply_size = snprintf( reply_string, REPLY_MAXLENGTH, "rcv_ssthresh %u\n", tcp_info.tcpi_rcv_ssthresh ); if ( reply_size > 0 ) { if ( send( tcp_work_socket, (void *)reply_string, reply_size, MSG_DONTWAIT ) == -1 ) { if ( opt_debug > 0 ) { fprintf(stderr, "Reply size %u didn't match: %s\n", reply_size, strerror(errno) ); } else { syslog( LOG_DAEMON | LOG_ERR, "Reply size %u didn't match: %s", reply_size, strerror(errno) ); } } } } } } close(tcp_work_socket); fprintf(statistics,"# Closed connection from %s.\n",inet_ntoa(client_address.sin_addr)); if ( fflush(statistics) != 0 ) { if ( opt_debug > 0 ) { fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno) ); } else { syslog( LOG_DAEMON | LOG_CRIT, "Cannot flush buffers: %s", strerror(errno) ); } } if ( opt_debug > 0 ) { debug_counter--; printf("Closed connection. Decrementing debug counter to %u.\n\n",debug_counter); } else { syslog( LOG_DAEMON | LOG_INFO, "Closed connection from %s", inet_ntoa(client_address.sin_addr)); } sleep(DEFAULT_SLEEP); } /* That's a happy ending. */ exit(EXIT_SUCCESS); }