#include "declarations.h" /* * Global Variables * The Server socket descriptor : serverfd * Server address structure : skaddr * Identification : identification * Buffer to store the request : buff * The size of the request : msg_size */ int serverfd = -1; struct sockaddr_in skaddr; short identification; unsigned char buff [MAX_MSG_SIZE]; static int msg_size = -1; /* * Function Declarations */ /* * constructs the request from the hostname passed as a parameter. the * second parameter passed to this function is the buffer in which the * request should be stored. */ int construct_request (char *, char []); /* * Skips the question field in the header of the response. * Arguments: * Buff: The buffer in which the response is stored * index: The pointer to the starting point in the buffer */ void skip_question( char *, int *); /* * Prints out the addresses based on the last argument passed to this * function. The function iterates over resource records. * Arguments: * 1. char * buff : The buffer that contains the response * 2. int * index : The index at which reading should begin in the * buffer * 3. int numiter : The number of iterations/resource records * 4. int type : The type of the query (0: Auth, 1: Ans, 2: Addrr) */ void output_addresses( char *, int *, int, int); /* * Initializes a connection to the server. The code connects to a server * so that all error conditions will be communicated back to the client. * Argument: 1. The name of the server to connect to! This method is * called every time a new name server is returned so that the socket * can be connected to a new server! */ void connect_to_server(char* ); /* * High level Parser for the response from the name server. This method * calls skip_question, output_addresses and other response related * functions... * Arguments: 1. The response from the server in a buffer */ void parse_response( char [] ); /* * Handles the alarm conditions... Simply returns after printing a * message */ void signal_handler(); /* * The function that is the starting point for the recursion. If the * numanswers = 0 and additional rrs is > 0, this function is called. */ void callnextserver( char *, int *, int, int); /* * Initializes the client by creating a socket to the server and * calling connect_to_server */ void init_client ( char * url) { //Create the socket /* create a socket IP protocol family (PF_INET) UDP protocol (SOCK_DGRAM) */ //The value of protocol should be IPPROTO_UDP signal ( SIGALRM, signal_handler); if ( ( serverfd = socket( PF_INET, SOCK_DGRAM, 0 )) < 0) { printf("Problem creating socket\n"); exit(1); } connect_to_server( url); } void connect_to_server(char* url) { struct hostent *hostptr; /* * fill in an address structure that will be used to specify the address of the server we want to connect to address family is IP (AF_INET) server IP address is found by calling gethostbyname with the name of the server (entered on the command line) * */ //You need this because the address needs to be put into the socket bzero( &skaddr, sizeof( skaddr)); skaddr.sin_family = AF_INET; alarm( WAIT_TIME); if ( (hostptr = gethostbyname( url)) == NULL) { //somehow, this doesn't give an error. The error occurs only in a //read! fprintf(stderr, "Error getting the host name... Using the ip address!\n"); if( ( skaddr.sin_addr.s_addr = inet_addr(url)) == -1) { fprintf(stderr, "Invalid IP address: %s\n",url); alarm(0); exit ( 1); } } else { //The gethostbyname function worked! memcpy( &skaddr.sin_addr.s_addr, hostptr->h_addr, hostptr->h_length); } alarm (0); //memcpy( &skaddr.sin_addr.s_addr, hostptr->h_addr, hostptr->h_length); //memcpy avoids the memory leads that can otherwise occur free( hostptr); skaddr.sin_port = htons( DNS_PORT); /* * We have now created the socket. All we need to now do is write to * the server and see what happens! */ //Addendum: One should connect the UDP socket for two reasons: //1. It gives better performace (partridge and park) //2. ICMP port unreachable errors are returned to the socket if it is //connected. This gives a better picture of what exactly occured when //the serverdid not return a message... //3. Even though we are connecting the socket, an alarm should be //implemented so that the recvfrom does not halt because of a lost //reply from the server. if( connect( serverfd, (struct sockaddr *) &skaddr, sizeof( skaddr)) == -1) { printf("An error occured ... \n"); printf ( "The error was : \n%s\n", strerror( errno)); } return; } void retrieve_address( char * hostname) { unsigned char read_buff [MAX_MSG_SIZE]; int num_read; int i; bzero( read_buff, sizeof( read_buff)); //The socket has been created... //Now just check if the socket is not equal to -1 and if it is //connected to a valid server, in short, if init_client has been //called if( serverfd == -1 || skaddr.sin_port != htons( DNS_PORT)) { printf( "You need to call init_client before calling this function... Bummer!\n"); return; } //Talk to the server now... Send the request! if( (hostname != NULL) && (msg_size == -1)) msg_size = construct_request( hostname, buff); //send request //if( (i = sendto( serverfd, buff, msg_size, 0, (struct sockaddr *) &skaddr, sizeof( skaddr))) < 0) { if( (i = write( serverfd, buff, msg_size)) < 0) { printf( "Error occured!\n"); printf( "%s\n", strerror( errno)); exit( 1); } printf( "%d = num written\n", i); //read response for( i = 0; i < NUM_RETRIES; i++) { //get the buff now! signal ( SIGALRM, signal_handler); alarm(WAIT_TIME); num_read = read ( serverfd, read_buff, MAX_MSG_SIZE); //num_read = recvfrom ( serverfd, read_buff, MAX_MSG_SIZE, 0, NULL, NULL); if(num_read < 0) { if( errno == EINTR) { perror( "Error in read... I think server timed out!\n"); printf ( "%s\n", strerror ( errno)); printf( " Retrying...%d \n", i); alarm(0); continue; } else { printf( "Error in read... Exiting\n"); exit( 1); } } else { printf( "%d = num bytes read\n", num_read); alarm(0); break; } if(num_read > MAX_MSG_SIZE) { perror( "The size of the response is greater than 512.\nI am not going to use TCP to get a response... \n"); exit( 1); } } if ( i == NUM_RETRIES) { printf( "Retried too many times. Server not responding...\n"); exit( 1); } /* for( i = 0; i < num_read; i++) { putchar( read_buff[i]); } putchar( '\n'); */ parse_response( read_buff); //print out response } //char * construct_request (char * hostname) { //This will not work... I will return the value of a local variable and //that will not reach the calling function (the stack is killed!!) int construct_request (char * hostname, char buff[]) { char * tmp; int length; int currentIndex = 0; unsigned char c = 0x0; int i = 0; unsigned short flag = 1; short htons1 = htons(1); //, htons = htons(0); short temp = 0; //Initialize the message to be all zeros bzero( buff, sizeof( buff)); //Create the id identification = strlen( hostname); temp = htons(identification); memcpy( buff + currentIndex, & temp, 2); currentIndex += 2; //Create the flag! //If I set this, the server does the recursion for me. I //am going to send you two versions... flag <<= 8; //printf("%d = flag\n", flag); temp = htons(flag); memcpy( buff + currentIndex, &temp, 2); currentIndex += 2; //Question Count memcpy ( buff + currentIndex, &htons1, 2); currentIndex += 2; //Answer Count buff[currentIndex ++] = 0; buff[currentIndex ++] = 0; //Authority RECS buff[currentIndex ++] = 0; buff[currentIndex ++] = 0; //Additional RRs buff[currentIndex ++] = 0; buff[currentIndex ++] = 0; /* * Done with the HEADER. Now to create the QUESTION! */ //Encode the address: //The address is of the form www.cs.rpi.edu //Assign currentIndex to 2 tmp = strtok( hostname, "."); do { length = strlen( tmp); if (length > 63) { printf (" you have requested the url of an invalid hostname \n