IC221: Systems Programming (SP14)


Home Policy Calendar Syllabus Resources Piazza

Lab 11: Client Socket Programming

Table of Contents

1 Part 1: myhost

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

int main(int argc, char *argv[]){

  struct addrinfo *result;    //to store results
  struct addrinfo *cur_result;    //to store results

  struct addrinfo hints;      //to indicate information we want

  struct sockaddr_in *saddr;  //to reference address
  struct sockaddr_in6 *saddr6;  //to reference address

  int s; //for error checking


  //TODO: Complete the lab
  //
  // Outline:
  //   - set up the hints
  //   - perform the getaddrinfo()
  //   - iterate the results
  //   - print the resolved ip address
  //   - cleanup the results with freaddrinfo(result)

  memset(&hints,0,sizeof(struct addrinfo));  //zero out hints

  //may use these hints, or not, depending on your solution
  //hints.ai_family = AF_INET6;
  //hints.ai_family = AF_INET; 
  //hints.ai_protocol = IPPROTO_TCP;

  //Convert the hostname to an address
  if( (s = getaddrinfo(argv[1], NULL, &hints, &result)) != 0){
    fprintf(stderr, "getaddrinfo: %s\n",gai_strerror(s));
    exit(1);
  }

  for(cur_result = result; cur_result != NULL; cur_result = cur_result->ai_next){

    if(cur_result->ai_family == AF_INET && cur_result->ai_protocol == IPPROTO_TCP){
      //convert generic socket address to inet socket address
      saddr = (struct sockaddr_in *) cur_result->ai_addr;

      //print the address
      printf("%s has address %s\n", argv[1], inet_ntoa(saddr->sin_addr));

    }

    if(cur_result->ai_family == AF_INET6  && cur_result->ai_protocol == IPPROTO_TCP){
      char str[INET6_ADDRSTRLEN];

      saddr6 = (struct sockaddr_in6 *) cur_result->ai_addr;
      inet_ntop(AF_INET6, &(saddr6->sin6_addr), str, INET6_ADDRSTRLEN);
      //print the address
      printf("%s has IPv6 address %s\n", argv[1], str);

    }



  }

  //free the addrinfo struct
  freeaddrinfo(result);
}

2 Part 2: mywget

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <libgen.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>


#define BUF_SIZE 4096

const char USAGE[]="mywget domain path [port]\n"
  "\n"
  "connect to the web server at domain and port, if provided, and request\n"
  "the file at path. If the file exist, save the file based on the\n"
  "filename of value in the path\n"
  "\n"
  "If domain is not reachable, report error\n";

const char GET[]="GET ";             //start of GET request
const char END_GET[]=" HTTP/1.0\n\n\r\r"; //end of GET request, between is the path

//PASS CODE
const char ACCEPT_200[]="HTTP/1.1 200 OK\n";

//ERROR CODES
const char ERROR_300[]="HTTP/1.1 300 Multiple Choices\n";
const char ERROR_301[]="HTTP/1.1 301 Moved Permanently\n";
const char ERROR_400[]="HTTP/1.1 400 Bad Request\n";
const char ERROR_403[]="HTTP/1.1 403 Forbidden\n";
const char ERROR_404[]="HTTP/1.1 404 Not Found\n";
const char ERROR_500[]="HTTP/1.1 500 Internal Server Error\n";

int main(int argc, char *argv[]){

  short port=80;                 //the port we are connecting on

  struct addrinfo *result;       //to store results
  struct addrinfo hints;         //to indicate information we want

  struct sockaddr_in *saddr_in;  //socket interent address

  int s,n;                       //for error checking

  int sock;                      //socket file descriptor
  int fd;                        //output file





  char response[BUF_SIZE];           //read in BUF_SIZE byte chunks

  if( argc < 3){
    fprintf(stderr, "ERROR: Require domain and path\n");
    fprintf(stderr, "%s", USAGE);
    exit(1);
  }

  //retrieve the port if provided
  if (argc > 3){
    if((port = atoi(argv[3])) == 0){
      fprintf(stderr, "ERROR: invlaid port number\n");
      fprintf(stderr, "%s", USAGE);
      exit(1);
    }
  }


  //TODO Complete the lab
  //
  // Outline:
  //    - lookup domain to get socket address
  //    - add the port to the address
  //    - open and connect the socket
  //    - send the get request for the path
  //    - read the response, check the code
  //    - write the response from server to the basename of the file 
  //    - cleanup by closing files


  //setup our hints
  memset(&hints,0,sizeof(struct addrinfo));  //zero out hints
  hints.ai_family = AF_INET; //we only want IPv4 addresses

  //Convert the hostname to an address
  if( (s = getaddrinfo(argv[1], NULL, &hints, &result)) != 0){
    fprintf(stderr, "ERROR: getaddrinfo: %s: %s\n",gai_strerror(s),argv[1]);
    exit(1);
  }

  //convert generic socket address to inet socket address
  saddr_in = (struct sockaddr_in *) result->ai_addr;


  //set the port
  saddr_in->sin_port = htons(port);


  //open a socket
  if( (sock = socket(AF_INET, SOCK_STREAM, 0))  < 0){
    perror("socket");
    exit(1);
  }

  //connect to the server
  if(connect(sock, (struct sockaddr *) saddr_in, sizeof(*saddr_in)) < 0){
    perror("connect");
    exit(1);
  }

  //send the request
  if(write(sock,GET,strlen(GET)) < 0){
    perror("send");
  }

  if(write(sock,argv[2],strlen(argv[2])) < 0){
    perror("send");
  }


  if(write(sock,END_GET,strlen(END_GET)) < 0){
    perror("send");
  }



  //read initial 
  if((n = read(sock, response, BUF_SIZE)) < 0){
    perror("read");
    exit(1);
  }

  //Check Error Codes
  if(! strncmp(response+9,"300",3)){
    fprintf(stderr, "%s", ERROR_300);
    exit(1);
  }


  if(! strncmp(response+9,"301",3)){
    fprintf(stderr, "%s", ERROR_301);
    exit(1);
  }

  if(! strncmp(response+9,"400",3)){
    fprintf(stderr, "%s", ERROR_400);
    exit(1);
  }

  if(! strncmp(response+9,"403",3)){
    fprintf(stderr, "%s", ERROR_403);
    exit(1);
  }

  if(! strncmp(response+9,"404",3)){
    fprintf(stderr, "%s", ERROR_404);
    exit(1);
  }

  if(! strncmp(response+9,"500",3)){
    fprintf(stderr, "%s", ERROR_500);
    exit(1);
  }

  if(! strncmp(response+9,"200",3)){
    fprintf(stderr, "%s", ACCEPT_200);
  }


  //open file based on basename
  if((fd = open(basename(argv[2]), O_CREAT | O_WRONLY | O_TRUNC, 0640)) < 0){
    perror("open");
    exit(1);
  }

  //write response to stdout
  if(write(fd, response, n) < 0){
    perror("write");
    exit(1);
  }


  //read the response until EOF
  while( (n = read(sock, response, BUF_SIZE)) > 0){

    //write response to stdout
    if(write(fd, response, n) < 0){
      perror("write");
      exit(1);
    }
  }

  if (n<0){
    perror("read");
  }


  //close the socket
  close(sock);
  close(fd);

  return 0; //success
}