/* * httpclient - an example HTTP client. * * Makes a connection to the given host/port and issue GET for the given file. * * usage: httpclient hostname port filename * * David Kotz - May 2016, May 2017 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> // read, write, close #include <strings.h> // bcopy, bzero #include <netdb.h> // socket-related structures #include "file.h" // readfilep /**************** external functions ****************/ // for some reason, when compiling with -c11 I need to declare this function. extern FILE *fdopen(int fd, const char *mode); /**************** file-local constants and functions ****************/ static void parse_args(const int argc, char *argv[], char **program, char **hostname, int *port, char **filename); static FILE *connect_to(const char *hostname, const int port); /**************** main() ****************/ int main(const int argc, char *argv[]) { char *program; // this program's name char *hostname; // server hostname int port; // server port char *filename; // filename to get // parse arguments - exit on error parse_args(argc, argv, &program, &hostname, &port, &filename); // open connection - exit on error FILE *comm_fp = connect_to(hostname, port); // prepare and send HTTP request const char *httpformat = "GET %s HTTP/1.1\nHOST: %s\n\n"; if (fprintf(comm_fp, httpformat, filename, hostname) < 0) { perror("writing on stream socket"); exit(6); } // ensure stdio buffer is flushed to socket fflush(comm_fp); // read and print the server's response char *response = readfilep(comm_fp); if (response != NULL) { puts(response); free(response); } fclose(comm_fp); // implicitly calls close(comm_sock); return 0; } /* ********************************************************* */ static void parse_args(const int argc, char *argv[], char **program, char **hostname, int *port, char **filename) { // check arguments *program = argv[0]; if (argc != 4) { fprintf(stderr, "usage: %s hostname port filename\n", *program); exit(1); } else { // we really should check the args more carefully. *hostname = argv[1]; *port = atoi(argv[2]); *filename = argv[3]; } } /* ********************************************************* */ static FILE * connect_to(const char *hostname, const int port) { // Look up the hostname specified on command line struct hostent *hostp = gethostbyname(hostname); if (hostp == NULL) { fprintf(stderr, "unknown host '%s'\n", hostname); exit(3); } // Initialize fields of the server address struct sockaddr_in server; // address of the server server.sin_family = AF_INET; bcopy(hostp->h_addr_list[0], &server.sin_addr, hostp->h_length); server.sin_port = htons(port); // Create socket (a file descriptor) int comm_sock = socket(AF_INET, SOCK_STREAM, 0); if (comm_sock < 0) { perror("opening socket"); exit(2); } // And connect that socket to that server if (connect(comm_sock, (struct sockaddr *) &server, sizeof(server)) < 0) { perror("connecting stream socket"); exit(3); } // to make it easier to work with, switch to stdio FILE *comm_fp = fdopen(comm_sock, "r+"); if (comm_fp == NULL) { fprintf(stderr, "error converting socket to FILE*\n"); exit(4); } return comm_fp; }