Skip to content
Snippets Groups Projects
Commit b26e878e authored by Winston Jodjana's avatar Winston Jodjana
Browse files

Merge Conflict fix

parents 36f1e869 b35a6e9f
No related branches found
No related tags found
No related merge requests found
......@@ -6,9 +6,13 @@
#include <iostream>
#include <cstring>
#include "server_util.h"
#include "threadpool.h"
#include "server_socket.h"
#define BUFFER_SIZE 4096
static const int num_threads = 16;
// given a program name, it prints
// information about its usage.
void Usage(char *progname);
......@@ -18,6 +22,7 @@ int main(int argc, char **argv) {
if (argc != 3)
Usage(argv[0]);
// Parse the port number, and check
// for failure
unsigned short port = 0;
......@@ -48,29 +53,46 @@ int main(int argc, char **argv) {
return EXIT_FAILURE;
}
// TODO: initialize shared data structure
// TODO: modify logic to add threapool
// TODO: use server_socket class
ServerSocket server_socket(port, argv[2]);
ThreadPool tp(num_threads);
/*
1) accept client connection
2) initialize stuff for communication with threadpool
3) read from client and write to thread
4) get back info from thread
*/
ThreadPool tp(kNumThreads);
while (1) {
HttpServerTask *hst = new HttpServerTask(HttpServer_ThrFn);
hst->base_dir = static_file_dir_path_;
hst->indices = &indices_;
if (!socket_.Accept(&hst->client_fd,
&hst->c_addr,
&hst->c_port,
&hst->c_dns,
&hst->s_addr,
&hst->s_dns)) {
// The accept failed for some reason, so quit out of the server.
// (Will happen when kill command is used to shut down the server.)
break;
unsigned char buf[BUFFER_SIZE];
while (1) {
HttpServerTask *hst = new HttpServerTask(HttpServer_ThrFn);
// TODO: change to new fields
hst->base_dir = static_file_dir_path_;
hst->indices = &indices_;
if (!server_socket.Accept(&hst->client_fd,
&hst->c_addr,
&hst->c_port,
&hst->c_dns,
&hst->s_addr,
&hst->s_dns)) {
// The accept failed for some reason, so quit out of the server.
// (Will happen when kill command is used to shut down the server.)
break;
}
//
// The accept succeeded; dispatch it.
tp.Dispatch(hst);
}
// The accept succeeded; dispatch it.
tp.Dispatch(hst);
}
// read from client fd and write to stdout
unsigned char buf[BUFFER_SIZE];
while (1) {
int rlen = WrappedRead(client_fd, buf, BUFFER_SIZE);
// check for reading failure
......
/*
* Copyright ©2019 Justin Hsia. All rights reserved. Permission is
* hereby granted to students registered for University of Washington
* CSE 333 for use solely during Spring Quarter 2019 for purposes of
* the course. No other use, copying, distribution, or modification
* is permitted without prior written consent. Copyrights for
* third-party components of this work must be honored. Instructors
* interested in reusing these course materials should contact the
* author.
*/
#include <stdio.h> // for snprintf()
#include <unistd.h> // for close(), fcntl()
#include <sys/types.h> // for socket(), getaddrinfo(), etc.
#include <sys/socket.h> // for socket(), getaddrinfo(), etc.
#include <arpa/inet.h> // for inet_ntop()
#include <netdb.h> // for getaddrinfo()
#include <errno.h> // for errno, used by strerror()
#include <string.h> // for memset, strerror()
#include <iostream> // for std::cerr, etc.
#include "./server_socket.h"
extern "C" {
#include "libhw1/CSE333.h"
}
ServerSocket::ServerSocket(uint16_t port, char *hostname) {
port_ = port;
listen_sock_fd_ = -1;
host_name_ = hostname;
}
ServerSocket::~ServerSocket() {
// Close the listening socket if it's not zero. The rest of this
// class will make sure to zero out the socket if it is closed
// elsewhere.
if (listen_sock_fd_ != -1)
close(listen_sock_fd_);
listen_sock_fd_ = -1;
}
bool ServerSocket::BindAndListen(int ai_family, int *listen_fd) {
// Use "getaddrinfo," "socket," "bind," and "listen" to
// create a listening socket on port port_. Return the
// listening socket through the output parameter "listen_fd".
// MISSING:
if (ai_family == AF_UNSPEC)
sock_family_ = AF_INET;
else
sock_family_ = ai_family;
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = sock_family_;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_flags |= AI_V4MAPPED;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_canonname = nullptr;
hints.ai_addr = nullptr;
hints.ai_next = nullptr;
std::string port = std::to_string(port_);
struct addrinfo *result;
int res = getaddrinfo(host_name_, port.c_str(), &hints, &result);
// check that getaddrinfo was successful
if (res != 0)
return false;
for (struct addrinfo *rp = result; rp != nullptr; rp = rp->ai_next) {
listen_sock_fd_ = socket(rp->ai_family,
rp->ai_socktype,
rp->ai_protocol);
// if we fail to create a socket, then continue to
// the next returned result, and try again.
if (listen_sock_fd_ == -1) {
listen_sock_fd_ = 0;
continue;
}
// configure the socket, tell the tcp stack to make the
// port we bind available again as soon as we exit.
int optval = 1;
setsockopt(listen_sock_fd_, SOL_SOCKET, SO_REUSEADDR,
&optval, sizeof(optval));
// if we successfully binded to a socket, then exit the loop
if (bind(listen_sock_fd_, rp->ai_addr, rp->ai_addrlen) == 0) {
break;
}
// the bind failed, so we close the socket, and try again with
// the next result
close(listen_sock_fd_);
listen_sock_fd_ = -1;
}
freeaddrinfo(result);
// check if binding was a success,
// if not return false.
if (listen_sock_fd_ == -1)
return false;
// success, tell the OS that we want this to be a listening socket.
if (listen(listen_sock_fd_, SOMAXCONN) != 0) {
close(listen_sock_fd_);
return false;
}
return true;
}
bool ServerSocket::Accept(int *accepted_fd,
std::string *client_addr,
uint16_t *client_port,
std::string *client_dnsname,
std::string *server_addr,
std::string *server_dnsname) {
// Accept a new connection on the listening socket listen_sock_fd_.
// (Block until a new connection arrives.) Return the newly accepted
// socket, as well as information about both ends of the new connection,
// through the various output parameters.
// MISSING:
struct sockaddr_storage caddr;
socklen_t caddr_len = sizeof(caddr);
// accept client connection, close the listening socket if it fails
int client_fd = accept(listen_sock_fd_,
reinterpret_cast<struct sockaddr *>(&caddr),
&caddr_len);
if (client_fd < 0) {
close(listen_sock_fd_);
return false;
}
*accepted_fd = client_fd;
// check if listening socket is IPV4 or IPV6
if (sock_family_ == AF_INET) {
struct sockaddr_in *in4 = reinterpret_cast<struct sockaddr_in *>(&caddr);
char address[INET_ADDRSTRLEN];
// convert the addresss to string
inet_ntop(AF_INET, &(in4->sin_addr), address, INET_ADDRSTRLEN);
// update the client port and addr
*client_port = in4->sin_port;
*client_addr = address;
// get the clientdns and update the return parameter
char clientdns[1024];
if (getnameinfo(reinterpret_cast<struct sockaddr *>(&caddr),
caddr_len, clientdns, 1024, nullptr, 0, 0) == -1)
return false;
*client_dnsname = clientdns;
// get server address, and dnsname.
struct sockaddr_in saddr4;
socklen_t saddr4_len = sizeof(saddr4);
if (getsockname(client_fd,
reinterpret_cast<struct sockaddr *>(&saddr4),
&saddr4_len) == -1)
return false;
// convert server address to string and update return parameter
char saddress[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(saddr4.sin_addr), saddress, INET_ADDRSTRLEN);
*server_addr = saddress;
// get server dns, and update return parameter
char server_dns[1024];
if (getnameinfo(reinterpret_cast<struct sockaddr *>(&saddr4),
saddr4_len, server_dns, 1024, nullptr, 0, 0) == -1)
return false;
*server_dnsname = server_dns;
} else { // sock_family_ == AF_INET6
struct sockaddr_in6 *in6 = reinterpret_cast<struct sockaddr_in6 *>(&caddr);
// update client port return parameter
char address[INET_ADDRSTRLEN];
*client_port = in6->sin6_port;
// convert client address to string, and update return parameter
inet_ntop(AF_INET6, &(in6->sin6_addr), address, INET6_ADDRSTRLEN);
*client_addr = address;
// get client dns name, and update return parameter
char clientdns[1024];
if (getnameinfo(reinterpret_cast<struct sockaddr *>(&caddr),
caddr_len, clientdns, 1024, nullptr, 0, 0) == -1)
return false;
*client_dnsname = clientdns;
// get server address and update return parameter
struct sockaddr_in6 saddr6;
socklen_t saddr6_len = sizeof(saddr6);
if (getsockname(client_fd,
reinterpret_cast<struct sockaddr *>(&saddr6),
&saddr6_len) == -1)
return false;
char saddress[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(saddr6.sin6_addr), saddress, INET6_ADDRSTRLEN);
*server_addr = saddress;
// get server dns and update return parameter
char server_dns[1024];
if (getnameinfo(reinterpret_cast<struct sockaddr *>(&saddr6),
saddr6_len, server_dns, 1024, nullptr, 0, 0) == -1)
return false;
*server_dnsname = server_dns;
}
return true;
}
#ifndef SERVER_SOCKET_H_
#define SERVER_SOCKET_H_
#include <netdb.h> // for AF_UNSPEC, AF_INET, AF_INET6
#include <stdint.h> // for uint16_t, etc.
#include <sys/types.h> // for AF_UNSPEC, AF_INET, AF_INET6
#include <sys/socket.h> // for AF_UNSPEC, AF_INET, AF_INET6
#include <string> // for std::string
// A ServerSocket class abstracts away the messy details of creating a
// TCP listening socket at a specific port and on a (hopefully)
// externally visible IP address. As well, a ServerSocket helps
// customers accept incoming client connections on the listening
// socket.
class ServerSocket {
public:
// This constructor creates a new ServerSocket object and associates
// it with the provided port number. The constructor doesn't create
// a socket yet; it just memorizes the given port.
explicit ServerSocket(uint16_t port, char *hostname);
// The destructor closes the listening socket if it is open.
virtual ~ServerSocket();
// This function causes the ServerSocket to attempt to create a
// listening socket and to bind it to the given port number on
// whatever IP address the host OS recommends for us. The caller
// provides:
//
// - ai_family: whether to create an IPv4, IPv6, or "either" listening
// socket. To specify IPv4, customers pass in AF_INET. To specify
// IPv6, customers pass in AF_INET6. To specify "either" (which
// leaves it up to BindAndListen() to pick, in which case it will
// typically try IPv4 first), customers pass in AF_UNSPEC. AF_INET6
// can handle IPv6 and IPv4 clients on POSIX systems, while AF_UNSPEC
// might pick IPv4 and not be able to accept IPv6 connections.
//
// On failure this function returns false. On success, it returns
// true, sets listen_sock_fd_ to be the file descriptor for the
// listening socket, and also returns (via an output parameter):
//
// - listen_fd: the file descriptor for the listening socket.
bool BindAndListen(int ai_family, int *listen_fd);
// This function causes the ServerSocket to attempt to accept
// an incoming connection from a client. On failure, returns false.
// On success, it returns true, and also returns (via output
// parameters) the following:
//
// - accepted_fd: the file descriptor for the new client connection.
// The customer is responsible for close()'ing this socket when it
// is done with it.
//
// - client_addr: a C++ string object containing a printable
// representation of the IP address the client connected from.
//
// - client_port: a uint16_t containing the port number the client
// connected from.
//
// - client_dnsname: a C++ string object containing the DNS name
// of the client.
//
// - server_addr: a C++ string object containing a printable
// representation of the server IP address for the connection.
//
// - server_dnsname: a C++ string object containing the DNS name
// of the server.
bool Accept(int *accepted_fd,
std::string *client_addr, uint16_t *client_port,
std::string *client_dnsname, std::string *server_addr,
std::string *server_dnsname);
private:
uint16_t port_;
int listen_sock_fd_;
int sock_family_; // either AF_INET or AF_INET6 for ipv4 or ipv6/v4
char *host_name_;
};
#endif // SERVER_SOCKET_H_
......@@ -11,11 +11,13 @@
#include <iostream>
#include <cstring>
const int PATH_MAX = 254;
int Listen(char *portnum) {
// Populate the "hints" addrinfo structure for getaddrinfo().
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET6; // IPv6 (also handles IPv4 clients)
hints.ai_family = AF_INET; // IPv6 (also handles IPv4 clients)
hints.ai_socktype = SOCK_STREAM; // stream
hints.ai_flags = AI_PASSIVE; // use wildcard "INADDR_ANY"
hints.ai_flags |= AI_V4MAPPED; // use v4-mapped v6 if no v6 found
......@@ -125,4 +127,23 @@ int WrappedWrite(int fd, unsigned char *buf, int writelen) {
total += wlen;
}
return total;
}
\ No newline at end of file
}
bool IsPathSafe(string rootdir, string testfile) {
char rootpathbuffer[PATH_MAX], testfilebuffer[PATH_MAX];
if (!realpath(rootdir.c_str(), rootpathbuffer))
return false;
if (!realpath(testfile.c_str(), testfilebuffer))
return false;
// Make sure that testfile is a prefix of rootdir.
if (strlen(testfilebuffer) <= strlen(rootpathbuffer))
return false;
if (strncmp(rootpathbuffer,
testfilebuffer,
strlen(rootpathbuffer)) != 0)
return false;
// It's safe!
return true;
}
#ifndef SERVER_UTIL_H_
#define SERVER_UTIL_H_
#include <cstring>
using namespace std;
// accepts a char*/string representation of a portnum
// it returns a listen file descriptor to use
int Listen(char *portnum);
......@@ -21,4 +25,6 @@ int WrappedRead(int fd, unsigned char *buf, int readlen);
// writelen, this could be because of some unrecoverable error.
int WrappedWrite(int fd, unsigned char *buf, int writelen);
bool IsPathSafe(string rootdir, string testfile);
#endif //SERVER_UTIL_H_
\ No newline at end of file
......@@ -9,6 +9,7 @@ extern "C" {
#include <list> // for std::list
#include "./verify550.h" // For asserts
class ThreadPool {
public:
// Construct a new ThreadPool with a certain number of worker
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment