Question Re-write the server below as a true web sever using GET command for HTT
ID: 3671102 • Letter: Q
Question
Question
Re-write the server below as a true web sever using GET command for HTTP 1.1 It should accept the Host message. The server should maintain a cache of file recently fetched from the disk and serve requests from cache when possible.
THE TRANSPORT LAYER CHAP. 6
/
* This page contains a client program that can request a file from the server program
* on the next page. The server responds by sending the whole file.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define SERVER PORT 12345 /* arbitrary, but client & server must agree */
#define BUF SIZE 4096 /* block transfer size */
int main(int argc, char **argv)
{
int c, s, bytes;
char buf[BUF SIZE]; /* buffer for incoming file */
struct hostent *h; /* info about server */
struct sockaddr in channel; /* holds IP address */
if (argc != 3) fatal("Usage: client server-name file-name");
h = gethostbyname(argv[1]); /* look up host’s IP address */
if (!h) fatal("gethostbyname failed");
s = socket(PF INET, SOCK STREAM, IPPROTO TCP);
if (s <0) fatal("socket");
memset(&channel, 0, sizeof(channel));
channel.sin family= AF INET;
memcpy(&channel.sin addr.s addr, h->h addr, h->h length);
channel.sin port= htons(SERVER PORT);
c = connect(s, (struct sockaddr *) &channel, sizeof(channel));
if (c < 0) fatal("connect failed");
/
* Connection is now established. Send file name including 0 byte at end. */
write(s, argv[2], strlen(argv[2])+1);
/
* Go get the file and write it to standard output. */
while (1) {
bytes = read(s, buf, BUF SIZE); /* read from socket */
if (bytes <= 0) exit(0); /* check for end of file */
write(1, buf, bytes); /* write to standard output */
}
}
fatal(char *string)
{
printf("%s ", string);
exit(1);
}
Figure 6-6. Client code using sockets. The server code is on the next page.
SEC. 6.1 THE TRANSPORT SERVICE 505
#include <sys/types.h> /* This is the server code */
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define SERVER PORT 12345 /* arbitrary, but client & server must agree */
#define BUF SIZE 4096 /* block transfer size */
#define QUEUE SIZE 10
int main(int argc, char *argv[])
{
int s, b, l, fd, sa, bytes, on = 1;
char buf[BUF SIZE]; /* buffer for outgoing file */
struct sockaddr in channel; /* holds IP address */
/
* Build address structure to bind to socket. */
memset(&channel, 0, sizeof(channel)); /* zero channel */
channel.sin family = AF INET;
channel.sin addr.s addr = htonl(INADDR ANY);
channel.sin port = htons(SERVER PORT);
/
* Passive open. Wait for connection. */
s = socket(AF INET, SOCK STREAM, IPPROTO TCP); /* create socket */
if (s < 0) fatal("socket failed");
setsockopt(s, SOL SOCKET, SO REUSEADDR, (char *) &on, sizeof(on));
b = bind(s, (struct sockaddr *) &channel, sizeof(channel));
if (b < 0) fatal("bind failed");
l = listen(s, QUEUE SIZE); /* specify queue size */
if (l < 0) fatal("listen failed");
/
* Socket is now set up and bound. Wait for connection and process it. */
while (1) {
sa = accept(s, 0, 0); /* block for connection request */
if (sa < 0) fatal("accept failed");
read(sa, buf, BUF SIZE); /* read file name from socket */
/
* Get and return the file. */
fd = open(buf, O RDONLY); /* open the file to be sent back */
if (fd < 0) fatal("open failed");
while (1) {
bytes = read(fd, buf, BUF SIZE); /* read from file */
if (bytes <= 0) break; /* check for end of file */
write(sa, buf, bytes); /* write bytes to socket */
}
close(fd); /* close file */
close(sa); /* close connection */
}
}
Explanation / Answer
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <math.h>
// Sockets includes.
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
// Constants
#define HOSTLEN 256
#define BUFLEN 40960
#define CMDLEN 256
// Cache data structures
char* cache;
int cache_size = 0;
int num_compacts = 0; // Spread number of compactions over total sites visited.
void surf(int argc, char **argv);
void browse(char* host, char* page, int id);
int main()
{
int size=10;
char* surf_arg[10];
surf_arg[0]="./websurf";
surf_arg[1]="-f";
surf_arg[2]="urls.txt";
surf_arg[3]="-s";
surf_arg[4]="1";
surf_arg[5]="-n";
surf_arg[6]="1";
surf_arg[7]="-c";
surf_arg[8]="1";
surf_arg[9]="";
surf(size,surf_arg);
return 0;
}
void surf(int argc, char **argv)
{
// Program arguments
int s, num_websites = 0, page_index;
char filename[HOSTLEN];
FILE* fp;
struct timeval tval;
struct timezone tzone;
// Web host and pages
char host[HOSTLEN];
char **pages;
int num_pages = 0;
// Get program arguments.
for (s=1; s<argc; s++) {
// Filename
if ((strcmp (argv[s],"-f")) == 0) {
s++;
strcpy (filename, argv[s]);
}
// Number of compactions
else if ((strcmp (argv[s],"-c")) == 0) {
s++;
num_compacts = atoi (argv[s]);
}
// Number of websites to randomly visit
else if ((strcmp (argv[s],"-n")) == 0) {
s++;
num_websites = atoi (argv[s]);
}
// Cache size
else if ((strcmp (argv[s],"-s")) == 0) {
s++;
cache_size = atoi (argv[s]);
}
// Print usage
else {
printf ("Usage: ./websurf -f <filename> -s <queue size> -n <# websites to visit> -c <# of compactions> ");
exit (0);
}
}
// Print program arguments
printf ("Filename: %s ", filename);
printf ("Number of websites to access = %i ", num_websites);
printf ("Cache size = %i ", cache_size);
printf ("Number of times to compact memory = %i ", num_compacts);
// Open file and store host and page names into pages array.
fp = fopen (filename, "r+");
if (fp == NULL) {
printf ("Error - could not open URLs file ");
exit (-1);
}
fscanf (fp, "%i %s ", &num_pages, host);
pages = (char**) calloc (num_pages, sizeof(char*));
for (s=0; s<num_pages; s++) {
pages[s] = (char*) calloc (HOSTLEN, sizeof(char));
fscanf (fp, "%s ", pages[s]);
//printf ("URL: %s%s ", host, pages[s]);
}
// Seed random number generator
gettimeofday (&tval, &tzone);
srand48 (tval.tv_usec);
// Start browsing randomly in list of available pages.
for (s=0; s<num_websites; s++) {
page_index = 0; // Get random page index.
printf ("Page index %i URL: %s%s ", page_index, host, pages[page_index]);
browse (host, pages[page_index], page_index);
}
}
/**********************************************************************************/
// Main function where host and page names are initialized, and threads are created.
void browse (char* host, char* page, int id) {
//Socket data structures - Need only 1 socket to browse many pages.
int sckt;
struct hostent *he;
struct sockaddr_in srvaddr;
char cmd[CMDLEN]; // Command line to send to web server
// Webpage data structures
int nread;
char buf[BUFLEN];
char *body;
int temp_fd;
int child;
int result;
char tempfilename[16];
int webpage_size = 0; // Initialize page size to 0
// Child process
int pid;
// create TCP connection to web server
if ((sckt = socket(AF_INET, SOCK_STREAM, 0)) == -1)
perror("socket"), exit(1);
if ((he = gethostbyname(host)) == NULL)
perror("gethostbyname"), exit(1);
//bzero(&srvaddr, sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr.s_addr = *(int *)(he->h_addr_list[0]);
srvaddr.sin_port = htons (80);
if (connect(sckt, (struct sockaddr *)&srvaddr, sizeof(srvaddr)) == -1)
perror("connect"), exit(1);
// create GET request
sprintf(cmd, "GET %s HTTP/1.1 Host: %s ", page, host);
printf ("cmd: %s ", cmd);
// send GET request
if (write(sckt, cmd, strlen(cmd)) != strlen(cmd))
perror("GET write"), exit(1);
// read response
if ((nread = read(sckt, buf, BUFLEN)) < 0)
perror("read"), exit(1);
if (nread >= BUFLEN)
fprintf(stderr, "web: need bigger (HTTP) read buffer "), exit(1);
buf[nread] = 0;
printf("web: nread = %d ", nread);
if (nread < 512) printf("web: response: %s ", buf);
else printf("web: initial chars of response: %.300s ", buf);
// check return code
//if (strncmp(buf, "HTTP/1.1 200 OK", 15))
// fprintf(stderr, "web: GET failed "), exit(1);
// bail out if chunked encoding
if (strstr(buf, "Transfer-Encoding: chunked")) {
fprintf(stderr, "web: can't handle chunked encoding ");
//pthread_exit(NULL);
exit (0);
}
// trim HTTP protocol header from response
if ((body = strstr(buf, " ")) == NULL)
fprintf(stderr, "web: can't find end of HTTP header in response "), exit(1);
body = body + 4;
// create & open temp file
sprintf(tempfilename, "temp%i.html", id);
temp_fd = open (tempfilename, O_CREAT | O_RDWR | O_TRUNC, S_IRWXU);
// if server sent only header: read further response & dump in a loop
webpage_size = 0; // Initialize page size to 0
if (body-buf >= nread) {
do {
if ((nread = read(sckt, buf, BUFLEN)) < 0)
perror("read"), exit(1);
else if (nread == 0) break;
if (nread >= BUFLEN)
fprintf(stderr, "web: need bigger (HTTP) read buffer "), exit(1);
if (write(temp_fd, buf, nread) != nread)
perror("file write"), exit(1);
webpage_size += nread; // Accumulate page size.
} while (nread > 0);
close(temp_fd);
}
// if server sent header & some body: assume it's the whole page & dump it into file
else {
webpage_size = strlen(body);
if (write(temp_fd, body, strlen(body)) != strlen(body))
perror("file write"), exit(1);
close(temp_fd);
}
// Print out size of webpage content
printf ("Webpage size %i ", webpage_size);
// Fork off process to display webpage.
/* pid = fork ();
printf ("Process id %i ", pid);
if (pid == 0) {
// Run Lynx
if (execl("/opt/gnu/bin/lynx", "/opt/gnu/bin/lynx", tempfilename, NULL) < 0)
perror("execl"), exit(1);
// Better to run netscape if possible
//if (execl("/usr/local/bin/netscape", "/usr/local/bin/netscape", tempfilename, NULL) < 0)
// perror("execl"), exit(1);
}
else {
printf ("After forking child process, parent process will now start writing to the file descriptor (pipe or file). ");
} */
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.