Skip to content

Commit

Permalink
fixed modules and finished http server
Browse files Browse the repository at this point in the history
  • Loading branch information
abdo643-HULK committed Dec 22, 2021
1 parent 82e6a88 commit c954fd6
Show file tree
Hide file tree
Showing 25 changed files with 305 additions and 740 deletions.
2 changes: 1 addition & 1 deletion EX1/cpp/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ enum class IpAddrKind : int {
/**
* The Buffer size for all the char arrays
*/
constexpr u16 BUFFER_SIZE = 1024;
constexpr u16 BUFFER_SIZE = 2048;

/**
* prints error message
Expand Down
3 changes: 2 additions & 1 deletion EX1/cpp/server_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ int main(int _argc, char *_argv[]) {
break;
}
case ServerType::TcpHttp: {
// TcpHttpServer server;
TcpHttpServer server(IpAddrKind::V4, port);
server.startRequestHandler();
cout << "Not implemented yet" << endl;
break;
}
Expand Down
167 changes: 167 additions & 0 deletions EX1/cpp/servers/TcpHttpServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,170 @@
//

#include "TcpHttpServer.hpp"

using namespace std;

TcpHttpServer::TcpHttpServer(const IpAddrKind _addressKind, const int _port, const int _optval) :
mIpVersion(_addressKind),
mServerFd(initializeSocket(_port, _optval)),
mShutdown(false) {
memset(mThreadPool, -1, sizeof(mThreadPool));
}

sockaddr *TcpHttpServer::setIp(int _port, sockaddr_storage *_address) {
if (mIpVersion == IpAddrKind::V6) {
const auto addr = reinterpret_cast<sockaddr_in6 *const>(_address);
memset(addr, 0, sizeof(sockaddr_in6));
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(_port);
#ifdef IN6ADDR_ANY_INIT
addr->sin6_addr = IN6ADDR_ANY_INIT;
#else
addr->sin6_addr = IN6ADDR_ANY;
#endif
return reinterpret_cast<sockaddr *>(addr);
}

const auto addr = reinterpret_cast<sockaddr_in *const>(_address);
memset(addr, 0, sizeof(sockaddr_in));
addr->sin_family = AF_INET;
addr->sin_port = htons(_port);
addr->sin_addr.s_addr = htonl(INADDR_ANY);

return reinterpret_cast<sockaddr *>(addr);
}


int TcpHttpServer::initializeSocket(int _port, int _optval) {
const auto serverFd = socket(static_cast<int>(mIpVersion), SOCK_STREAM, 0);

if (serverFd < 0) {
errorExit("SOCKET ERROR", SOCKET_ERROR);
}

sockaddr_storage serverAddress;

const sockaddr *server = setIp(_port, &serverAddress);
const int addressSize = mIpVersion == IpAddrKind::V4 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);

if (bind(serverFd, server, addressSize) < 0) {
errorExit("SOCKET BINDING ERROR", SOCKET_BIND_ERROR, serverFd);
}

if (setsockopt(serverFd,
SOL_SOCKET,
SO_REUSEADDR,
reinterpret_cast<const char *>(&_optval),
sizeof(_optval)) < 0) {
errorExit("SETSOCKOPT ERROR", SOCKET_OPT_ERROR, serverFd);
}

if (listen(serverFd, 10) < 0) {
errorExit("SOCKET LISTEN ERROR", SOCKET_LISTEN_ERROR, serverFd);
}

cout << "Listening..." << endl;

return serverFd;
}

void *TcpHttpServer::clientCommunication(void *const _parameter) {
const auto params = (ClientCommunicationParams *) _parameter;
const auto clientFd = params->clientFd;
const auto server = params->server;

const auto detachRet = pthread_detach(pthread_self());
if (detachRet != 0) {
errorExit("ERROR DETACHING THREADS", THREAD_ERROR, clientFd);
}

constexpr char echoMsg[] = "BROWSER REQUEST:";
constexpr char htmlBodyFormat[] = "<h1>%s</h1><br> <p>%s</p>";
constexpr auto msgSize = BUFFER_SIZE - sizeof(htmlBodyFormat) - sizeof(echoMsg);

char msg[msgSize] = "\0";
const auto status = recv(clientFd, msg, BUFFER_SIZE, 0);

if (status == -1) {
errorExit("NO MSG RECEIVED", NO_MSG_ERROR, clientFd);
} else if (status == 0) {
cout << "CLIENT CLOSED" << endl;
close(clientFd);
return nullptr;
}

char htmlBody[BUFFER_SIZE] = "\0";
snprintf(htmlBody, sizeof(htmlBody), htmlBodyFormat, echoMsg, msg);

const auto htmlResponse = string() + HTML_START + htmlBody + HTML_END;
const auto contentLength = "Content-Length: " + to_string(htmlResponse.length()) + "\n\n";

const auto responseHeader = HTTP_HEADER + contentLength;

const auto sendHeaderRet = send(clientFd, responseHeader.c_str(), responseHeader.length(), 0);
if (sendHeaderRet == -1) errorExit("ERROR SENDING DATA", THREAD_ERROR, clientFd);

const auto sendHtmlRet = send(clientFd, htmlResponse.c_str(), htmlResponse.length(), 0);
if (sendHtmlRet == -1) errorExit("ERROR SENDING DATA", THREAD_ERROR, clientFd);

memset(&msg, 0, msgSize);
memset(&htmlBody, 0, BUFFER_SIZE);

cout << "CLOSING CLIENT" << endl;
shutdown(clientFd, SHUT_RDWR);
close(clientFd);

if (params->counter >= 10) {
server->shutdownServer();
}

delete params;

return nullptr;
}

void TcpHttpServer::startRequestHandler() {
sockaddr_storage clientAddress;
memset(&clientAddress, 0, sizeof(sockaddr_storage));

const socklen_t size = mIpVersion == IpAddrKind::V4 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);

int i = 0;

while (!mShutdown) {
const int clientFd = accept(mServerFd,
reinterpret_cast<sockaddr *>(&clientAddress),
const_cast<socklen_t *>(&size));

if (clientFd == -1) continue;

const bool ret = printClientInfo(mIpVersion, &clientAddress);
if (!ret) continue;

auto parameter = new ClientCommunicationParams();
parameter->clientFd = clientFd;
parameter->server = this;
parameter->counter = i;

if (pthread_create(&mThreadPool[i++],
nullptr,
clientCommunication,
parameter) != 0) {
printError("ERROR CREATING THREAD");
}
}
}

void TcpHttpServer::shutdownServer() {
cout << "CLOSING SERVER" << endl;
shutdown(mServerFd, SHUT_RDWR);
mShutdown = true;
}

TcpHttpServer::~TcpHttpServer() {
cout << "SERVER SHUTTING DOWN" << endl;
for (unsigned long i: mThreadPool) {
i != -1 && pthread_cancel(i);
}
close(mServerFd);
}
107 changes: 106 additions & 1 deletion EX1/cpp/servers/TcpHttpServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,117 @@
#ifndef EX1_TCPHTTPSERVER_HPP
#define EX1_TCPHTTPSERVER_HPP

#include <cstring>
#include "shared.hpp"
#include "../errors.hpp"

constexpr auto HTTP_HEADER = "";
constexpr auto HTTP_HEADER = "HTTP/1.1 200 OK\nContent-Type: text/html; charset=utf-8\n";

constexpr auto HTML_START = "<!DOCTYPE html>\n"
"<html lang=\"en\">\n"
"\t<head>\n"
"\t\t<meta charset=\"utf-8\" />\n"
"\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n"
"\t\t<title>BROWSER REQUEST</title>\n"
"\t</head>\n"
"\t<body>\n";

constexpr auto HTML_END = "\t</body>\n"
"</html>";

/**
* This HTTP-Server supports either IPv4 or IPv6.
* The Server also supports multithreading and returns
* the client header
*/
class TcpHttpServer {
private:
/**
* The struct is only here to provide the
* thread with the needed parameters
*/
struct ClientCommunicationParams {
/**
* Holds the Client file descriptor from the accept function
* to be able to send and receive messages
*/
int clientFd;

/**
* A reference to the server to call shutdown
*/
TcpHttpServer *server;

int counter;
};

/**
* The selected Ip-Version
*/
const IpAddrKind mIpVersion;

/**
* Holds the Server file descriptor from the socket function
*/
int mServerFd;

/**
* Toggles the loop to shut down
*/
bool mShutdown;

/**
* Holds the created Threads
*/
pthread_t mThreadPool[THREAD_COUNT];

/**
* Creates the Sockaddr of the selected Ip Version
*
* @param _port the port the struct has to include
* @param _address the address to convert
* @return the struct of the selected version cast as an `sockaddr`
*/
sockaddr *setIp(int _port, sockaddr_storage *_address);

/**
* Binds the socket and starts listening
*
* @param _port the port to bind to and run the server on
* @param _optval the `optval` for `setsockopt`
*/
int initializeSocket(int _port, int _optval = 1);

/**
*
* @param _parameter
* @return
*/
static void *clientCommunication(void *_parameter);

/**
* Shuts down the server descriptor and
* toggles mShutdown
*/
void shutdownServer();

public:
/**
* Sets the IP-Version and initializes all the member properties
*/
explicit TcpHttpServer(IpAddrKind _addressKind, int _port, int _optval = 1);

/**
* Accepts the client and puts them into a thread.
* The request loop uses the `mShutdown` to kill it or
* keep it alive
*/
void startRequestHandler();

/**
* closes the serverFd and the threads
*/
~TcpHttpServer();
};


Expand Down
14 changes: 5 additions & 9 deletions EX2/.idea/EX2.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 0 additions & 16 deletions EX2/.idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 0 additions & 8 deletions EX2/.idea/modules/EX2.iml

This file was deleted.

Loading

0 comments on commit c954fd6

Please sign in to comment.