Design a webserver using this template: #include <fnmatch.h> #include <errno.h>
ID: 3687970 • Letter: D
Question
Design a webserver using this template:
#include <fnmatch.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#define BACKLOG (10)
void usage(){
fprintf(stderr,"Usage: ./homework5 [port number] [directory to serve] ");
exit(1);
}
/* char* parseRequest(char* request)
* Args: HTTP request of the form "GET /path/to/resource HTTP/1.X"
*
* Return: the resource requested "/path/to/resource"
* 0 if the request is not a valid HTTP request
*
* Does not modify the given request string.
* The returned resource should be free'd by the caller function.
*/
char* parseRequest(char* request) {
//assume file paths are no more than 256 bytes + 1 for null.
char *buffer = malloc(sizeof(char)*257);
memset(buffer, 0, 257);
if(fnmatch("GET * HTTP/1.*", request, 0)) return 0;
sscanf(request, "GET %s HTTP/1.", buffer);
return buffer;
}
/* Your program should take two arguments:
* 1) The port number on which to bind and listen for connections, and
* 2) The directory out of which to serve files.
*/
int main(int argc, char** argv) {
/* For checking return values. */
int retval;
/* Read the port number from the first command line argument. */
if (argc != 3){
usage();
}
int port = atoi(argv[1]);
/* Create a socket to which clients will connect. */
int server_sock = socket(AF_INET6, SOCK_STREAM, 0);
if(server_sock < 0) {
perror("Creating socket failed");
exit(1);
}
/* A server socket is bound to a port, which it will listen on for incoming
* connections. By default, when a bound socket is closed, the OS waits a
* couple of minutes before allowing the port to be re-used. This is
* inconvenient when you're developing an application, since it means that
* you have to wait a minute or two after you run to try things again, so
* we can disable the wait time by setting a socket option called
* SO_REUSEADDR, which tells the OS that we want to be able to immediately
* re-bind to that same port. See the socket(7) man page ("man 7 socket")
* and setsockopt(2) pages for more details about socket options. */
int reuse_true = 1;
retval = setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &reuse_true,
sizeof(reuse_true));
if (retval < 0) {
perror("Setting socket option failed");
exit(1);
}
/* Create an address structure. This is very similar to what we saw on the
* client side, only this time, we're not telling the OS where to connect,
* we're telling it to bind to a particular address and port to receive
* incoming connections. Like the client side, we must use htons() to put
* the port number in network byte order. When specifying the IP address,
* we use a special constant, INADDR_ANY, which tells the OS to bind to all
* of the system's addresses. If your machine has multiple network
* interfaces, and you only wanted to accept connections from one of them,
* you could supply the address of the interface you wanted to use here. */
struct sockaddr_in6 addr; // internet socket address data structure
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port); // byte order is significant
addr.sin6_addr = in6addr_any; // listen to all interfaces
/* As its name implies, this system call asks the OS to bind the socket to
* address and port specified above. */
retval = bind(server_sock, (struct sockaddr*)&addr, sizeof(addr));
if(retval < 0) {
perror("Error binding to port");
exit(1);
}
/* Now that we've bound to an address and port, we tell the OS that we're
* ready to start listening for client connections. This effectively
* activates the server socket. BACKLOG (#defined above) tells the OS how
* much space to reserve for incoming connections that have not yet been
* accepted. */
retval = listen(server_sock, BACKLOG);
if(retval < 0) {
perror("Error listening for connections");
exit(1);
}
while(1) {
/* Declare a socket for the client connection. */
int sock;
char buffer[256];
const char * response = "HTTP/1.0 200 OK hello client! ";
/* Another address structure. This time, the system will automatically
* fill it in, when we accept a connection, to tell us where the
* connection came from. */
struct sockaddr_in remote_addr;
unsigned int socklen = sizeof(remote_addr);
/* Accept the first waiting connection from the server socket and
* populate the address information. The result (sock) is a socket
* descriptor for the conversation with the newly connected client. If
* there are no pending connections in the back log, this function will
* block indefinitely while waiting for a client connection to be made.
* */
sock = accept(server_sock, (struct sockaddr*) &remote_addr, &socklen);
if(sock < 0) {
perror("Error accepting connection");
exit(1);
}
/* At this point, you have a connected socket (named sock) that you can
* use to send() and recv(). */
/* ALWAYS check the return value of send() and recv(). This is example
* code that you must replace. */
/* TODO: collect the request, and keep collecting until you see the
* request separator (a blank line). This is placeholder code. */
recv(sock,buffer,255,0);
/* TODO: once you've received a request, use parseRequest to pull out
* the file that was asked for. */
/* TODO: construct a valid response to that request, and send THE
* ENTIRE THING to the client. This is placeholder code. */
send(sock, response,strlen(response), 0);
/* Tell the OS to clean up the resources associated with that client
* connection, now that we're done with it. */
close(sock);
}
close(server_sock);
}
Explanation / Answer
//function specific for Windows-to be called before invoking call to socket()
int init()
{
WSADATA wsaData;
int iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed: %d ", iResult);
return 1;
}
}
//function specific for windows-to be called after all socket communication is complete
void clean()
{
WSACleanup();
}
int main()
{
while(1)
{
init();
server();
clean();
}
return 0;
}
void server()
{
int sock, connected, bytes_recieved , true = 1;
char send_data [1024] , recv_data[1024];
struct sockaddr_in server_addr,client_addr;
int sin_size;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket");
exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) {
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;
//bzero(&(server_addr.sin_zero),8); --This is for POSIX based systems
memset(&(server_addr.sin_zero),0,8);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))== -1)
{
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1)
{
perror("Listen");
exit(1);
}
printf(" MyHTTPServer waiting on port 8080");
fflush(stdout);
sin_size = sizeof(struct sockaddr_in);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
// printf(" I got a connection from (%s , %d)",
// inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
char kk[9999];
recv(connected,kk,sizeof(kk),0);
printf(" Received:%s",kk);
char xx[9999];
strcpy(xx,"HTTP/1.1 200 OK Content-length: 47 Content-Type: text/html <html><body><H1>Hello Kartik</H1></body></html>");
int c=send(connected,&xx,sizeof(xx),0);
printf(" STATUS:%d",c);
printf(" Sent : %s ",xx);
close(sock);
WSACleanup();
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.