📄 clilib.c
字号:
#include "stdhead.h"#include "clilib.h"#include "parse.h"void write_to_log (char * str, int time_flag){ extern int event_log_fd; time_t curr_time; int time_length; char *str_curr_time; if (time_flag) { curr_time = time (&curr_time); str_curr_time = ctime (&curr_time); write (event_log_fd, str_curr_time, strlen(str_curr_time)); write (event_log_fd, "\t", 1); } if ((write (event_log_fd, str, strlen (str))) == -1) printf ("Failed to log event.\n"); if (time_flag) write (event_log_fd, "\n", 1);}// Build message linked-list from character buffervoid build_linked_list (char *m, int len, struct DHCP_MESSAGE *dhcp_message){ int index = 0, i; struct OPTIONS *opt; dhcp_message -> u_msg_type.buffer[0] = m[index++]; for (i = 2; i >= 0; i--) dhcp_message -> u_trans_id.buffer[i] = m[index++]; dhcp_message -> u_trans_id.buffer[3] = 0; opt = (struct OPTIONS *) malloc (sizeof (struct OPTIONS)); read_option (m, index, len, opt); dhcp_message -> opt = opt;}void print_linked_list_contents (struct DHCP_MESSAGE *dhcp_message){ struct OPTIONS *q; struct DUID *d; struct DUID1 *d1; struct DUID2 *d2; struct DUID3 *d3; struct IA *ia; struct IA_ADDRESS *ia_addr; struct PREFERENCE *preference; struct STATUS_CODE *sc_ptr; int i; char name[64]; printf ("Message type = %d\n", dhcp_message -> u_msg_type.msg_type); printf ("Transaction ID = %d\n\n", dhcp_message -> u_trans_id.trans_id); q = dhcp_message -> opt; if (!q) { printf ("No options defined!\n"); return; } do { switch (q -> u_opt_code.opt_code) { case OPTION_CLIENTID : case OPTION_SERVERID : //printf ("Option type = %d\n", q -> u_opt_code.opt_code); //printf ("DUID length = %d\n", q -> u_opt_len.opt_len); d = q -> opt_data; //printf ("DUID type = %d\n", d -> u_duid_type.duid_type); if (d -> u_duid_type.duid_type == 1) { d1 = d -> duid_type; //printf ("Time = %d\n", d1 -> u_time.time); //printf ("Hardware type = %d\nHardware address = ", d1 -> u_haddr_type.haddr_type); for (i = 0; i < 6; i++) { printf ("%x", d1 -> link_layer_address[i]); if (i != 5) printf (":"); } //printf ("\n\n"); } else if (d -> u_duid_type.duid_type == 2) { d2 = d -> duid_type; //printf ("Identifier length = %d\nIdentifier = ", d2 -> u_identifier_length.identifier_length); //for (i = 0; i < d2 -> u_identifier_length.identifier_length; i++) // printf ("%d", d2 -> identifier[i]); // printf ("\nDomain name = "); //for (i = 0; i < d2 -> domain_name_len; i++) // printf ("%c", d2 -> domain_name[i]); } else if (d -> u_duid_type.duid_type == 3) { d3 = d -> duid_type; // printf ("Hardware type = %d\nHardware address = ", d3 -> u_haddr_type.haddr_type); for (i = 0; i < 6; i++) { printf ("%x", d3 -> link_layer_address[i]); if (i != 5) printf (":"); } printf ("\n\n"); } q = d -> opt; break; case OPTION_IA : // printf ("Option type = IA option\n"); // printf ("option length = %d\n", q -> u_opt_len.opt_len); ia = q -> opt_data; // printf ("IAID = %x\n", ia -> u_iaid.iaid); // printf ("T1 = %d\n", ia -> u_t1.t1); // printf ("T2 = %d\n", ia -> u_t2.t2); // printf ("Status code for IA = %d\n\n", ia -> status); q = ia -> opt; break; case OPTION_IAADDR : // printf ("Option type = IA address option\n"); // printf ("option length = %d\n", q -> u_opt_len.opt_len); ia_addr = q -> opt_data; // printf ("Temporary address bit = %d\n", ia_addr -> t_bit); // printf ("Address status = %d\n", ia_addr -> addr_status); // printf ("Prefix length of the address = %d\n", ia_addr -> prefix_length); printf ("IPv6 Address = %s\n", inet_ntop (AF_INET6, ia_addr -> addr, name, 64)); printf ("Preferred lifetime = %d\n" , ia_addr -> u_pref_lifetime.pref_lifetime); printf ("Valid lifetime = %d\n", ia_addr -> u_valid_lifetime.valid_lifetime); q = ia_addr -> opt; break; case OPTION_PREFERENCE : // printf ("Option type = Preference Option\n"); // printf ("Option length = %d\n", q -> u_opt_len.opt_len); preference = q -> opt_data; // printf ("Preference value = %d\n\n", preference -> preference_value); q = preference -> opt; break; case OPTION_STATUS_CODE : // printf ("Option type = Status code\n"); // printf("Option length = %d\n",q->u_opt_len.opt_len); sc_ptr = q->opt_data; // printf( "Status code = %d\nStatus message =",sc_ptr->u_status_code.status_code); //for(i=0; i < q->u_opt_len.opt_len -2; i++) // printf("%c", sc_ptr->message[i]); // printf("\n\n"); q=sc_ptr->opt; break; default : printf ("Invalid option type\n\n"); q = 0; return; } } while (q);}// This function returns the generated random number in between -0.1 and +0.1float generate_rand (){ time_t t1; // call srand with the current time as the seed srand (time (&t1)); // Return a random vakue between -0.1 and +0.1 return ((float)((rand()%200)-100)/1000.0);}// This function returns a random number in between the defined constants.int calculate_initial_delay (){ time_t t1; int random; // call srand with the current time as the seed srand (time (&t1)); // Calculate and return a random number between MAX_SOL_DELAY and MIN_SOL_DELAY random = rand () % (MAX_SOL_DELAY); if (random < (MIN_SOL_DELAY)) random += (MIN_SOL_DELAY); return random;}/* This function calculates the timeout upon the expiry of which theretransmission is to be done. */float calculate_retransmission_timeout (float RTprev, float mrt){ float rt = ((2.0 * RTprev) + (generate_rand () * RTprev)); if (mrt != 0) while (rt > mrt) rt = mrt + generate_rand () * mrt; return rt;}/* This function checks whether that particular option exists in the linked list. It returns 1on success and 0 on failure. */int check_for_option (int option, struct DHCP_MESSAGE *dhcp_msg_ptr){ struct OPTIONS * opt; struct DUID *duid_ptr; struct IA *ia_ptr; struct IA_ADDRESS * iaaddr_ptr; struct STATUS_CODE * status_ptr; struct PREFERENCE * preference; // Move to the first option node opt= dhcp_msg_ptr->opt; // Until there are no moer options in the message while ( opt !=0) { // If the required option is found then return 1 if (opt->u_opt_code.opt_code == option) return 1; // Depending on the option code switch(opt->u_opt_code.opt_code) { case OPTION_CLIENTID : case OPTION_SERVERID : // Move to the next node duid_ptr = (struct DUID *) opt -> opt_data; opt = duid_ptr->opt; break; case OPTION_IA : // Move to the next node ia_ptr= (struct IA *) opt -> opt_data; opt= ia_ptr->opt; break; case OPTION_IAADDR : // Move to the next node iaaddr_ptr=(struct IA_ADDRESS *) opt -> opt_data; opt=iaaddr_ptr->opt; break; case OPTION_STATUS_CODE : // Move to the next node status_ptr=(struct STATUS_CODE *) opt -> opt_data; opt=status_ptr->opt; break; case OPTION_PREFERENCE : // Move to the next node preference = (struct PREFERENCE *) opt -> opt_data; opt = preference -> opt; break; default : opt = 0; break; } } return 0;} int check_for_status (struct DHCP_MESSAGE *dhcp_msg_ptr){ struct OPTIONS *options_ptr; struct DUID *duid_ptr; struct IA *ia_ptr; struct IA_ADDRESS * iaaddr_ptr; struct STATUS_CODE * status_ptr; struct PREFERENCE * preference_ptr; // Move to the first option node options_ptr= dhcp_msg_ptr->opt; // Until there are no moer options in the message while (options_ptr !=0) { // Depending on the option code switch(options_ptr -> u_opt_code.opt_code) { case OPTION_CLIENTID : case OPTION_SERVERID : // Move to the next node duid_ptr = (struct DUID *) options_ptr -> opt_data; options_ptr = duid_ptr->opt; break; case OPTION_IA : // Move to the next node ia_ptr= (struct IA *) options_ptr -> opt_data; options_ptr = ia_ptr->opt; break; case OPTION_IAADDR : // Move to the next node iaaddr_ptr=(struct IA_ADDRESS *) options_ptr -> opt_data; options_ptr = iaaddr_ptr->opt; break; case OPTION_STATUS_CODE : // Move to the next node status_ptr=(struct STATUS_CODE *) options_ptr -> opt_data; return (status_ptr -> u_status_code.status_code); case OPTION_PREFERENCE : // Move to the next node preference_ptr = (struct PREFERENCE *) options_ptr -> opt_data; options_ptr = preference_ptr -> opt; break; default : options_ptr = 0; break; } } return -1;}/* This function checks the validity of the message being passed to it.It return 1 on success and 0 on failure */int check_message (struct DHCP_MESSAGE *dhcp_message_ptr, int recv_type, int sent_type){ struct OPTIONS *options_ptr; extern int g_trans_id; int status; // Check whether the received message is of the right type if (dhcp_message_ptr->u_msg_type.msg_type != recv_type) return 0; // Checks whether the transaction id of the received message has the same // transaction is as that sent to same server before a reply is obtained // from the server if (dhcp_message_ptr->u_trans_id.trans_id != g_trans_id) return 0; switch (dhcp_message_ptr->u_msg_type.msg_type) { case ADVERTISE : if ((status = check_for_status (dhcp_message_ptr)) != -1) if (status != Success) return 0; if (!check_for_option (OPTION_SERVERID, dhcp_message_ptr)) return 0; if (!check_for_option (OPTION_IA, dhcp_message_ptr)) return 0; if (!check_for_option (OPTION_IAADDR, dhcp_message_ptr)) return 0; break; case REPLY : if ((status = check_reply_message (dhcp_message_ptr, sent_type)) == 0) return 0; break; } return 1;}// This function waits for a response from the server after the initial transmission// of a message has been done. The function struct DHCP_MESSAGE ** wait_until_response (int sfd, int cfd, float irt, float mrt, int mrc, int sent_type, int recv_type, char *buff, int size, int *msg_count){ char name [64]; // Stores the client state extern int g_state; // Server and Client socket structures extern struct sockaddr_in6 sa, ca; extern struct DHCP_MESSAGE * reply_for_request; // count keeps track of message retransmissions // valid is used for checking message validity int count = 0, n, message_valid; // variable for storing message received from the server struct DHCP_MESSAGE **msg_arr_ptr = 0, **p; // pointer to the message array // Calculate the initial retransmission time float rt = calculate_retransmission_timeout (SOL_IRT, mrt); // Used for detecting activity on a socket fd_set readfds, testfds; // Used to set the retransmission timeout struct timeval timeout; // Used to receive the response from the server char reply[MIN_MESSAGE_SIZE]; // pointer to a DHCP_MESSAGE struct DHCP_MESSAGE *dhcp_message_ptr; u_int32_t renewal_timer, rebind_timer, valid_lifetime_timer; time_t start, end; // Set the length of the server and client socket structures socklen_t sl = sizeof (sa); socklen_t cl = sizeof (ca); // Set the server response message count to zero *msg_count = 0; // Clear the file descriptor set variables FD_ZERO (&readfds); // Set the client socket in the file descriptor set FD_SET (cfd, &readfds); // If Maximum retransmission count is zero then set mrc to infinity. if (!mrc) mrc = INFINITY; // Set the retransmission time timeout.tv_sec = 0; timeout.tv_usec = rt * MEGA; if (g_state == RENEWING || g_state == REBINDING) { get_timers (reply_for_request, &renewal_timer, &rebind_timer, &valid_lifetime_timer); time (&start); } while (count < mrc) { // Initialize the file descriptor set testfds = readfds; // Start the retransmission timeout and wait for activity on the scokets write_to_log ("Waiting for server response", 1); select (cfd+1, &testfds, 0, 0, &timeout); // If it is time to retrasmit if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { if (g_state == RENEWING) { time (&end); if (end-start >= rebind_timer-renewal_timer) return 0; } else if (g_state == REBINDING) { time (&end); if (end-start >= valid_lifetime_timer-rebind_timer) return 0; } // If there are no replies from the server then break out and return a null pointer write_to_log ("Wait for server response timed out.", 1); if (*msg_count > 0) { write_to_log ("\tResponse messages have been received. Exiting retransmission scheme.", 0); break; } write_to_log ("\tNo response messages have been received. Continuing in the retransmission scheme...", 0); // Increment the retransmission count count++; printf ("Sending %d %d time\n", sent_type, count); // Retransmit the client message write_to_log ("Retransmitting message...", 1); sendto (sfd, buff, size, 0, (struct sockaddr *) &sa, sl); // Calculate the new Retransmission timeout rt = calculate_retransmission_timeout (rt, mrt); // Set the new retransmission timeout timeout.tv_sec = 0; timeout.tv_usec = rt * MEGA; printf ("The new retransmission timeout is %f\n", rt); } // If activity is detected on the client receiving scoket else if (FD_ISSET (cfd, &testfds)) { // Receive the server message into the reply buffer n = recvfrom (cfd, reply, MIN_MESSAGE_SIZE, 0, (struct sockaddr *) &ca, &cl); write_to_log ("Server response received from ", 1); write_to_log ((char *) inet_ntop (AF_INET6, &ca.sin6_addr, name, 64), 0); // Allocate memory for a DHCP_MESSAGE dhcp_message_ptr = (struct DHCP_MESSAGE *) malloc (sizeof (struct DHCP_MESSAGE)); // Build the linked list for the server response message build_linked_list (reply, n, dhcp_message_ptr); // Check for validity of the server response message write_to_log ("Checking message validity ....", 1); message_valid = check_message (dhcp_message_ptr, recv_type, sent_type); // Announce arrival of server response message printf ("%d message received.\n", recv_type); // Check for message validity if (message_valid) { // Allocate an array of pointers for the dhcp message. (*msg_count)++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -