Write a program in C that accepts a port number as a command
line argument, and starts an HTTP server. This server should
constantly accept() connections, read requests of the form
GET /path HTTP/1.1\r\n\r\n
read the file indicated by /path, and send it over the "connect"
file descriptor returned by the call to accept().
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include "csapp.h"
#include <pthread.h>
#include <string.h>
#define MAX_CACHE_SIZE 1049000
#define MAX_OBJECT_SIZE 102400
#ifdef BIT32
typedef unsigned long long aint;
#else
typedef unsigned long aint;
#endif
static const char *user_agent = "User-Agent: Mozilla/5.0 (X11; Linux i686; rv:1.9.2.3) Gecko/20100423 Firefox/3.6.3\r\n";
static const char *accept_encoding = "Accept-Encoding: gzip, deflate\r\n";
static const char *accept_0 = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
int proxy(int fd);
int open_clientfd_safe(char *hostname, int port);
int parse_uri(char *uri, char *hostname, int *port);
int read_request(rio_t *rp, char *buf_request, char *hostname, int *port, char *uri);
void *thread(void *vargp);
void initial();
void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg);
sem_t mutex;
static int set_num, line_num;
static void init();
static int loaddata(char *tag, char *response);
static void storedata(char *response, char *tag);
static void pop_usage(int *array, int key, int len);
struct cache_line
{
int valid;
char *tag;
char *block;
};
struct cache_set
{
struct cache_line *line;
int *usage;
};
struct cache
{
struct cache_set *set;
};
static struct cache c;
int main(int argc,char **argv)
{
int listenfd, *connfd, port;
unsigned clientlen;
//struct hostent *hp;
struct sockaddr_in clientaddr;
//char *haddrp;
pthread_t tid;
/* Check command line args */
if (argc != 2)
{
fprintf(stderr, "usage: %s <port>\n", argv[0]);
exit(1);
}
port = atoi(argv[1]);
//ignore sigpipe
signal(SIGPIPE, SIG_IGN);
//initialization
initial();
listenfd = Open_listenfd(port);
while(1)
{
connfd = malloc(sizeof(int));
clientlen = sizeof(clientaddr);
*connfd = accept(listenfd, (SA *)&clientaddr, &clientlen);
//hp = Gethostbyaddr((const char *) & clientaddr.sin_addr.s_addr,sizeof(clientaddr.sin_addr.s_addr),AF_INET);
//haddrp = inet_ntoa(clientaddr.sin_addr);
printf("Build new connection! Connfd:%d\n", *connfd);
pthread_create(&tid, NULL, thread, connfd);
}
}
/* Initialization*/
static void init()
{
int i, j;
c.set = malloc(sizeof (struct cache_set) * set_num);
for (i = 0; i < set_num; i++)
{
c.set[i].line = malloc(sizeof (struct cache_line) * line_num);
c.set[i].usage = malloc(sizeof (int) * line_num);
for (j = 0; j < line_num; j++)
{
c.set[i].usage[j] = j;
c.set[i].line[j].valid = 0;
c.set[i].line[j].tag = malloc(MAXLINE);
c.set[i].line[j].block = malloc(MAX_OBJECT_SIZE);
}
}
}
void initial()
{
sem_init(&mutex, 0, 1);
set_num = 1;
line_num = 10;
init();
}
static void pop_usage(int *array, int key, int len)
{
int i, j;
for(i = 0; i < len; i++)
{
if(array[i] == key)
break;
}
for(j = i; j > 0; j--)
{
array[j] = array[j - 1];
}
array[0] = key;
}
static int loaddata(char *tag, char *response)
{
aint set_index = 0;
int i;
for(i = 0; i < line_num; i++)
{
if(c.set[set_index].line[i].valid == 1 && (strcmp(c.set[set_index].line[i].tag, tag) == 0))
{
pop_usage(c.set[set_index].usage,i,line_num);
strcpy(response, c.set[set_index].line[i].block);
break;
}
}
if(i == line_num)
{
return 0;
}
else
{
return 1;
}
}
static void storedata(char *response,char *tag)
{
aint set_index = 0;
int lru;
lru = c.set[set_index].usage[line_num - 1];
strcpy(c.set[set_index].line[lru].tag, tag);
strcpy(c.set[set_index].line[lru].block, response);
if(c.set[set_index].line[lru].valid == 0)
{
c.set[set_index].line[lru].valid = 1;
}
pop_usage(c.set[set_index].usage, lru, line_num);
}
/* Thread*/
void *thread(void *vargp)
{
int connfd = *((int *)vargp);
pthread_detach(pthread_self());
free(vargp);
proxy(connfd);
close(connfd);
return NULL;
}
/*open_clientfd function */
int open_clientfd_safe(char *hostname, int port)
{
int clientfd;
struct hostent *hp;
struct sockaddr_in serveraddr;
if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1; /* Check error */
/* Fill in the server’s IP address and port */
P(&mutex);
if ((hp = gethostbyname(hostname)) == NULL)
return -2; /* Check error */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)hp->h_addr_list[0], (char *)&serveraddr.sin_addr.s_addr, hp->h_length);
serveraddr.sin_port = htons(port);
V(&mutex);
/* Establish a connection with the server */
if (connect(clientfd, (SA *) &serveraddr, sizeof(serveraddr)) < 0)
return -1;
return clientfd;
}
/*
* proxy - serve as a proxy to handle one HTTP request/response transaction
*/
int proxy(int connfd)
{
int port, serverfd, len, response_len;
char buf_request[MAX_OBJECT_SIZE], buf_response[MAX_OBJECT_SIZE], hostname[MAXLINE], cache_response[MAX_OBJECT_SIZE], uri[MAXLINE];
rio_t rio_client, rio_server;
/* reset the buffer */
memset(buf_request, 0, sizeof(buf_request));
memset(buf_response, 0, sizeof(buf_response));
memset(hostname, 0, sizeof(hostname));
memset(cache_response, 0, sizeof(cache_response));
memset(uri, 0, sizeof(uri));
/* Read request line and headers */
rio_readinitb(&rio_client, connfd);
printf("read_request in!\n");
if(read_request(&rio_client, buf_request, hostname, &port, uri) < 0)
return -1;
printf("read_request out!\n");
printf("uri:%s\thostname:%s\tport:%d\n", uri, hostname, port);
printf("buf_request: %s\n", buf_request);
if((loaddata(uri, cache_response)) == 1)
{
printf("Cache hit!\n");
if(rio_writen(connfd, cache_response, sizeof(cache_response)) < 0)
{
fprintf(stderr, "cache response error\n");
return -1;
}
/*reset the buffer*/
memset(cache_response, 0, sizeof(cache_response));
}
else
{
printf("Cache miss!\n");
/*send request to real server*/
if((serverfd = open_clientfd_safe(hostname, port)) < 0)
{
fprintf(stderr, "open serverfd error\n");
return -1;
}
rio_readinitb(&rio_server, serverfd);
if(rio_writen(serverfd, buf_request, strlen(buf_request)) < 0)
{
printf("buf_request error:\n%s\n", buf_request);
fprintf(stderr, "rio_writen send request error\n");
close(serverfd);
return -1;
}
/*receive from server and send back to the client */
memset(cache_response, 0, sizeof(cache_response));
response_len = 0;
while((len = rio_readnb(&rio_server, buf_response, sizeof(buf_response))) > 0)
{
printf("hostname:%s\tport:%d\nbuf_response:%s\n", hostname, port, buf_response);
strcat(cache_response, buf_response);
response_len += len;
if(rio_writen(connfd, buf_response, len) < 0)
{
printf("buf_response error:%s\nlen:%d\n%s\n", strerror(errno), len, buf_response);
fprintf(stderr, "rio_writen send response error\n");
close(serverfd);
return -1;
}
/* reset the buffer*/
memset(buf_response, 0, sizeof(buf_response));
}
if(response_len <= MAX_OBJECT_SIZE)
storedata(uri, cache_response);
close(serverfd);
}
return 0;
}
/*
* read_request - read and parse HTTP request headers
*/
int read_request(rio_t *rp, char *buf_request, char *hostname, int *port, char *uri)
{
char buf[MAXLINE], method[MAXLINE];
memset(buf, 0, sizeof(buf));
memset(method, 0, sizeof(method));
/* request line */
if(rio_readlineb(rp, buf, MAXLINE) <= 0)
return -1;
printf("buf: %s\n", buf);
sscanf(buf, "%s %s", method, uri);
/* get hostname and port information*/
parse_uri(uri, hostname, port);
/* fill in request for real server */
sprintf(buf_request, "%s %s HTTP/1.0\r\n", method, uri);
printf("buf_request: %s\n", buf_request);
if(rio_readlineb(rp, buf, MAXLINE) < 0)
{
printf("rio_readlineb fail!\n");
return -1;
}
while(strcmp(buf, "\r\n"))
{
printf("buf: %s\n", buf);
if(strcmp(buf, "\n") == 0)
{
printf("bufn \n");
}
if(strcmp(buf, "\r") == 0)
{
printf("bufr \n");
}
if(strstr(buf, "Host"))
{
strcat(buf_request, "Host: ");
strcat(buf_request, hostname);
strcat(buf_request, "\r\n");
}
else if(strstr(buf, "Accept:"))
strcat(buf_request, accept_0);
else if(strstr(buf, "Proxy-Connection:"))
strcat(buf_request, "Proxy-Connection: close\r\n");
else if(strstr(buf, "User-Agent:"))
strcat(buf_request, user_agent);
else if(strstr(buf, "Accept-Encoding:"))
strcat(buf_request, accept_encoding);
else if(strstr(buf, "Connection:"))
strcat(buf_request, "Connection: close\r\n");
else if(!strstr(buf, "Cookie:"))
/*add addtional header except above headers*/
strcat(buf_request, buf);
memset(buf, 0, sizeof(buf));
if(rio_readlineb(rp, buf, MAXLINE) < 0)
{
fprintf(stderr, "rio_readlineb read request error\n");
return -1;
}
}
strcat(buf_request, "\r\n");
return 0;
}
/*
* parse_uri - parse URI into hostname and port args
*/
int parse_uri(char *uri, char *hostname, int *port)
{
char *ps, *pe, *phost;
char *uricp = malloc(strlen(uri) + 1);
strncpy(uricp, uri, strlen(uri));
/* start pointer */
if((ps = strstr(uricp, "http://")) == NULL)
return -1;
ps += strlen("http://");
/* end pointer */
if((pe = strstr(ps, "/")) == NULL)
return -1;
*pe = '\0';
/*if hostname contains port*/
phost = strsep(&ps, ":");
if(ps == NULL)
*port = 80;
else
*port = atoi(ps);
strncpy(hostname, phost, strlen(phost));
return 0;
}
/*
* clienterror - returns an error message to the client
*/
void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg)
{
char buf[MAXLINE], body[MAXBUF];
memset(buf, 0, sizeof(buf));
memset(buf, 0, sizeof(body));
/* Build the HTTP response body */
sprintf(body, "<html><title>Tiny Error</title>");
sprintf(body, "%s<body bgcolor=""ffffff"">\r\n", body);
sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg);
sprintf(body, "%s<p>%s: %s\r\n", body, longmsg, cause);
sprintf(body, "%s<hr><em>The Tiny Web server</em>\r\n", body);
/* Print the HTTP response */
sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);
rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Content-type: text/html\r\n");
rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body));
rio_writen(fd, buf, strlen(buf));
rio_writen(fd, body, strlen(body));
}
Write a program in C that accepts a port number as a command line argument, and...
Using network sockets, write a C program called client that receives three command-line arguments in the form: client host port file and sends a request to a web server. The command-line arguments are hostRepresents the web server to connect to port Represents the port number where a request is sent. Normally an HTTP request is sent over port 80, but this format allows for custom ports file Represents the file requested from the web server Your program should create a...
Project Description In this project, you will be developing a multithreaded Web server and a simple web client. The Web server and Web client communicate using a text-based protocol called HTTP (Hypertext Transfer Protocol). Requirements for the Web server The server is able to handle multiple requests concurrently. This means the implementation is multithreaded. In the main thread, the server listens to a specified port, e.g., 8080. Upon receiving an HTTP request, the server sets up a TCP connection to...
[loops] Write a java program that accepts a number, as command line argument and prints out “Hello, World!” that many times using a for loop. E.g. if the input number is 3, the program outputs: Hello, World! Hello, World! Hello, World! Keep it simple, please use the argument, not interact with the console. Thanks
You shall write a very basic web server in Javascript
that will run via nodejs.
Your project shall include the following line: var paul
= require('/homes/paul/HTML/CS316/p3_req.js');
Your project will accept HTTP requests via URLs in the following
format:
/[a-zA-Z0-9_]*.cgi
Here are the steps you must perform for .cgi URLs: 1) call http .createserver(myprocess) my process() is a function you will write to process requests from the user via their browser 2) create a mylisten() function that takes the following parameters:...
Complete the Java command line application. The application accepts a URL from the command line. This application should then make a HTTP request to “GET” the HTML page for that URL, then print the HTTP header as well as the HTML for the page to the console. You must use the Java “socket” class to do all network I/O with the webserver. Yes, I’m aware this is on Stack Overflow, but you must understand how this works, as you will...
Assignment One program will be the update server and the other will be the update client. Here is how the two programs should interact with each other: Server 1. the server starts up and reads the version number in the data.bin file and stores it in memory. 2. The server binds to a port and awaits connections. Client 1. The client starts up and it will first read the version number found within it's own data.bin file. 2. The client...
In C write a program that must accept one argument from the command line. The argument is the name of the file containing the processes (for example: processes.csv).This file is comma-separated with three columns (process ID, arrival time and burst time) with each row for an individual process. You can assume that this file will have a maximum of 10 processes. For example Input: processes.csv ProcessID,Arrival Time,Burst Time 0,1,3 1,0,5 2,9,8 3,10,6 Where the first element is processes, the second...
Write a bash script question.sh that accepts one command line argument which is supposed to be a positive integer n. The script should print all odd integers from 1 through n. Write a C or C++ program question.c(pp) to read from stdin as many integers as there are available and then print the squares of all these integers. You should test your code by “./question.sh <n> | ./question” assuming the compiled C/C++ program is question. See the following for a...
This is in C. For this assignment we will write a simple database server. We will be creating a simple database of student records, so let’s describe these first. The format of a student record is as follows: typedef struct student { char lname[ 10 ], initial, fname[ 10 ]; unsigned long SID; float GPA; } SREC; Part One – the Server We will create a database server. The job of the server is to accept a...
1. Write a complete C++ program named “CheckAmount” that accepts command line arguments. It checks whether there is a command line argument of “-amount” followed by an amount number. It will print out that number amount. For all other cases, it will print out -1. For example, if you run this program with correct arguments as follows, it will print out 1.99, 0.75 and 1.1 respectively CheckAmount -amount 1.99 CheckAmount -help -amount 0.75 CheckAmount -help -check -amount 1.1 -verbose And...