makefile compile both luke and hugo files

This commit is contained in:
hugogogo
2022-07-22 23:37:30 +02:00
12 changed files with 239 additions and 658 deletions

1
.gitignore vendored
View File

@@ -14,3 +14,4 @@ Thumbs.db
ubuntu_tester
ubuntu_cgi_tester
webserv

View File

@@ -1,62 +1,55 @@
NAME = webserv
NAME = webserv
CXX = c++
CXX = c++
CXXFLAGS = -Wall -Wextra #-Werror
CXXFLAGS += $(HEADERS)
CXXFLAGS += -std=c++98
CXXFLAGS += -g
#CXXFLAGS += -O3
CXXFLAGS = -Wall -Wextra -Werror
CXXFLAGS += -std=c++98
CXXFLAGS += -I$(HEADERS_D)
CXXFLAGS += -g
#CXXFLAGS += -O3
VPATH = $(SRCS_D)
#SHELL = /bin/zsh
VPATH = $(DIR_SRCS)
DIR_SRCS = srcs
HEADERS = $(HEADERS_D:%=-I%)
HEADERS_D = headers \
headers_hugo
HEADERS_D = ./srcs
HEADERS = bak__Webserv.hpp
SRCS_D = srcs \
srcs_hugo
SRCS = main.cpp \
Webserv.cpp
SRCS_HUGO = hugo_main.cpp \
hugo_Webserv.cpp
DEPENDENCIES = $(HEADERS:%=$(HEADERS_D)/%)
#SRCS = $(MAIN) Webserv.cpp
SRCS = $(MAIN) bak__Webserv.cpp
#MAIN = main.cpp
#MAIN = main_luke.cpp
MAIN = main_hugo.cpp
#MAIN = main_poll.cpp
#MAIN = main_select.cpp
DIR_OBJS = builds
OBJS = $(SRCS:%.cpp=$(DIR_OBJS)/%.o)
OBJS_D = builds
OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o)
OBJS_HUGO = $(SRCS_HUGO:%.cpp=$(OBJS_D)/%.o)
# --------------------
# ------ RULES -------
# --------------------
all: $(NAME)
hugo: fclean hu_link
$(DIR_OBJS)/%.o: %.cpp | $(DIR_OBJS)
$(OBJS_D)/%.o: %.cpp | $(OBJS_D)
$(CXX) $(CXXFLAGS) -c $< -o $@
$(DIR_OBJS):
$(OBJS_D):
mkdir $@
$(OBJS): $(DEPENDENCIES)
#$(OBJS): $(DEPENDENCIES) Makefile
$(NAME) : $(OBJS)
$(CXX) $(OBJS) -o $(NAME)
$(NAME): $(OBJS)
hu_link: $(OBJS_HUGO)
$(NAME) hu_link:
$(CXX) $^ -o $(NAME)
clean:
rm -f $(OBJS)
rm -rf $(OBJS_D)
fclean: clean
rm -f $(NAME)
re: fclean all
#run: all
.PHONY : all clean fclean re run
.PHONY : all clean fclean re

43
headers/Webserv.hpp Normal file
View File

@@ -0,0 +1,43 @@
#ifndef WEBSERV_HPP
# define WEBSERV_HPP
# include <string>
# include <map>
# include <cerrno> // errno
# include <cstdio> // perror
# include <exception>
# include <stdexcept>
# include <unistd.h> // close
# include <iostream> // cout, cin
# include <cstring> // memset
# include <sys/socket.h> // socket, accept, listen, send, recv, bind, connect, setsockopt, getsockname
# include <netinet/in.h> // sockaddr_in
// # include <netinet/ip.h> // usefull for what ?
# include <arpa/inet.h> // htonl, htons, ntohl, ntohs, inet_addr
# include <poll.h> // poll
# include <fcntl.h> // fcntl
class Webserv
{
public:
Webserv();
// Webserv(Webserv const &src);
~Webserv();
// Webserv &operator=(Webserv const &rhs);
void bind(in_port_t port);
void listen(unsigned int max_connections);
void start();
private:
int _socket_fd;
struct pollfd _poll_s[42]; // 42 PLACEHOLDER
std::map<std::string, std::string> _request;
std::map<std::string, std::string> _response;
};
#endif

View File

@@ -3,7 +3,9 @@
# include <map>
# include <cerrno> // errno
# include <cstdio> // perror
# include <exception>
# include <stdexcept>
# include <unistd.h> // close
// --------------------------------------------
// Verifier si les fonctions sont dispos dans des headers C++

159
srcs/Webserv.cpp Normal file
View File

@@ -0,0 +1,159 @@
#include "Webserv.hpp"
Webserv::Webserv()
{
std::cout << "Server init\n";
_socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
//_socket_fd = ::socket(AF_INET, SOCK_STREAM, 0);
if (_socket_fd == -1)
{
std::perror("err socket(): ");
throw std::runtime_error("Socket init");
}
}
/* Webserv::Webserv(Webserv const &src)
{
} */
Webserv::~Webserv()
{
std::cout << "Server destroyed\n";
}
/* Webserv & Webserv::operator=(Webserv const &rhs)
{
} */
///////////////
// Functions //
void Webserv::bind(in_port_t port)
{
// cast invalid ? how to ?
// const struct sockaddr* cast_test = static_cast<const struct sockaddr*>(addr);
struct sockaddr_in addr;
std::memset(&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = ::htons(port);
addr.sin_addr.s_addr = ::htonl(INADDR_ANY); // htonl useless with 0 value (INADDR_ANY) ?
if (::bind(_socket_fd, (const sockaddr*)&addr, sizeof addr) == -1)
{
std::perror("err bind(): ");
throw std::runtime_error("Socket bind");
}
}
void Webserv::listen(unsigned int max_connections)
{
if (::listen(_socket_fd, max_connections) == -1)
{
std::perror("err listen(): ");
throw std::runtime_error("Socket listen");
}
}
#define BUFSIZE 8192
#define MSG_TEST "Le Webserv / 20 =D\n"
#define MSG_BOUNCE "bounced properly ;)\n" // placeholder
void Webserv::start()
{
struct sockaddr_in addr;
socklen_t addr_len;
int accepted_fd;
char buf[BUFSIZE+1]; // WIP buffer. need to try with std::vector or std::string.
int ret;
int timeout = 3000;
int i = 1;
int nfds = 1;
int ret_nfds;
_poll_s[0].fd = _socket_fd;
_poll_s[0].events = POLLIN;
std::cout << "Server started\n";
int i_loop = 0;
++i_loop;
std::cout << i_loop << "----------\n";
std::cout << "loop poll()\n";
while ( (ret_nfds = ::poll(_poll_s, nfds, timeout)) != -1)
{
i = 1;
while (i < nfds)
{
if (ret_nfds == 0)
{
std::cout << "timeout\n";
::close(_poll_s[i].fd);
_poll_s[i].fd = -1;
--nfds;
}
else if (_poll_s[i].revents & POLLIN) // READ
{
std::cout << "recv()\n";
ret = ::recv(_poll_s[i].fd, buf, BUFSIZE, 0);
if (ret == -1)
{
std::perror("err recv(): ");
if (::send(_poll_s[i].fd, MSG_BOUNCE, sizeof MSG_BOUNCE - 1, 0) == -1)
std::perror("err send(): ");
::close(_poll_s[i].fd);
_poll_s[i].fd = -1;
--nfds;
continue;
}
/*
if (ret == BUFSIZE)
// send error like "request too long" to client
*/
buf[ret] = '\0';
_poll_s[i].events = POLLOUT;
}
else if (_poll_s[i].revents & POLLOUT) // WRITE
{
std::cout << "send()\n";
if (::send(_poll_s[i].fd, buf, ret, 0) == -1) // echo the read
std::perror("err send(): ");
if (::send(_poll_s[i].fd, MSG_TEST, sizeof MSG_TEST - 1, 0) == -1)
std::perror("err send(): ");
::close(_poll_s[i].fd);
_poll_s[i].fd = -1;
--nfds;
}
++i;
}
if ((_poll_s[0].fd == _socket_fd) && (_poll_s[0].revents & POLLIN)) // ACCEPT
{
std::cout << "accept()\n";
addr_len = sizeof addr;
accepted_fd = ::accept(_socket_fd, (sockaddr*)&addr, &addr_len);
if (accepted_fd == -1)
{
std::perror("err accept(): ");
continue;
}
::fcntl(accepted_fd, F_SETFL, O_NONBLOCK);
_poll_s[nfds].fd = accepted_fd;
_poll_s[nfds].events = POLLIN;
++nfds;
}
++i_loop;
std::cout << i_loop << "----------\n";
std::cout << "loop poll()\n";
}
}

View File

@@ -2,7 +2,7 @@
#include <iostream>
#include <exception>
#include <stdexcept>
#include "Webserv.hpp"
#include <Webserv.hpp>
int main(void)
{
@@ -10,9 +10,7 @@ int main(void)
{
Webserv serv;
// https://security.stackexchange.com/questions/169213/how-to-chose-a-port-to-run-an-application-on-localhost
//serv.bind(4040);
serv.bind(4040);
serv.bind(80);
serv.listen(512); // 512 max connections arbitrary
serv.start();
}
@@ -22,4 +20,3 @@ int main(void)
}
return (0);
}

View File

@@ -1,308 +0,0 @@
// https://www.ibm.com/docs/en/i/7.2?topic=designs-using-poll-instead-select
# include <unistd.h> // close
# include <stdlib.h> // exit
# include <iostream> // cout, cin
# include <cerrno> // errno
# include <cstdio> // perror
# include <string.h> // memset
# include <sys/socket.h> // socket, accept, listen, send, recv, bind, connect, setsockopt, getsockname
# include <netinet/in.h> // sockaddr_in
# include <arpa/inet.h> // inet_ntoa, inet_addr, htonl, htons, ntohl, ntohs
# include <poll.h> // poll
# include <fcntl.h> // fcntl
# include <sys/ioctl.h> // ioctl
# define FALSE 0
# define TRUE 1
# define SERVER_PORT 4040
int main ()
{
int len, rc, on = 1;
int listen_sd = -1, new_sd = -1;
int end_server = FALSE, compress_array = FALSE;
int close_conn;
char buffer[80];
struct sockaddr_in addr;
struct pollfd fds[200];
// struct pollfd fds[1];
// struct pollfd fds;
int nfds = 1, current_size = 0, i, j;
// *************************************************************
// * Create an AF_INET stream socket to receive incoming *
// * connections on *
// *************************************************************
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sd < 0)
{
perror("socket() failed");
exit(-1);
}
// *************************************************************
// * Allow socket descriptor to be reuseable *
// *************************************************************
rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
if (rc < 0)
{
perror("setsockopt() failed");
close(listen_sd);
exit(-1);
}
// *************************************************************
// * Set socket to be nonblocking. All of the sockets for *
// * the incoming connections will also be nonblocking since *
// * they will inherit that state from the listening socket. *
// *************************************************************
rc = ioctl(listen_sd, FIONBIO, (char *)&on);
if (rc < 0)
{
perror("ioctl() failed");
close(listen_sd);
exit(-1);
}
// *************************************************************
// * Bind the socket *
// *************************************************************
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
// memcpy(&addr.sin_addr, &inaddr_any, sizeof(inaddr_any));
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(SERVER_PORT);
rc = bind(listen_sd, (struct sockaddr *)&addr, sizeof(addr));
if (rc < 0)
{
perror("bind() failed");
close(listen_sd);
exit(-1);
}
// *************************************************************
// * Set the listen back log *
// *************************************************************
rc = listen(listen_sd, 32);
if (rc < 0)
{
perror("listen() failed");
close(listen_sd);
exit(-1);
}
// *************************************************************
// * Initialize the pollfd structure *
// *************************************************************
memset(fds, 0 , sizeof(fds));
// *************************************************************
// * Set up the initial listening socket *
// *************************************************************
fds[0].fd = listen_sd;
fds[0].events = POLLIN;
// *************************************************************
// * Loop waiting for incoming connects or for incoming data *
// * on any of the connected sockets. *
// *************************************************************
do
{
// ***********************************************************
// * Call poll() *
// ***********************************************************
poll(fds, nfds, -1);
// ***********************************************************
// * One or more descriptors are readable. Need to *
// * determine which ones they are. *
// ***********************************************************
current_size = nfds;
for (i = 0; i < current_size; i++)
{
// *********************************************************
// * Loop through to find the descriptors that returned *
// * POLLIN and determine whether it's the listening *
// * or the active connection. *
// *********************************************************
if(fds[i].revents == 0)
continue;
// *********************************************************
// * If revents is not POLLIN, it's an unexpected result, *
// * log and end the server. *
// *********************************************************
if(fds[i].revents != POLLIN)
{
printf(" Error! revents = %d\n", fds[i].revents);
end_server = TRUE;
break;
}
if (fds[i].fd == listen_sd)
{
// *******************************************************
// * Listening descriptor is readable. *
// *******************************************************
printf(" Listening socket is readable\n");
// *******************************************************
// * Accept all incoming connections that are *
// * queued up on the listening socket before we *
// * loop back and call poll again. *
// *******************************************************
do
{
// *****************************************************
// * Accept each incoming connection. If *
// * accept fails with EWOULDBLOCK, then we *
// * have accepted all of them. Any other *
// * failure on accept will cause us to end the *
// * server. *
// *****************************************************
new_sd = accept(listen_sd, NULL, NULL);
if (new_sd < 0)
{
if (errno != EWOULDBLOCK)
{
perror(" accept() failed");
end_server = TRUE;
}
break;
}
// *****************************************************
// * Add the new incoming connection to the *
// * pollfd structure *
// *****************************************************
printf(" New incoming connection - %d\n", new_sd);
fds[nfds].fd = new_sd;
fds[nfds].events = POLLIN;
nfds++;
// *****************************************************
// * Loop back up and accept another incoming *
// * connection *
// *****************************************************
} while (new_sd != -1);
}
// *********************************************************
// * This is not the listening socket, therefore an *
// * existing connection must be readable *
// *********************************************************
else
{
printf(" Descriptor %d is readable\n", fds[i].fd);
close_conn = FALSE;
// *******************************************************
// * Receive all incoming data on this socket *
// * before we loop back and call poll again. *
// *******************************************************
do
{
// *****************************************************
// * Receive data on this connection until the *
// * recv fails with EWOULDBLOCK. If any other *
// * failure occurs, we will close the *
// * connection. *
// *****************************************************
rc = recv(fds[i].fd, buffer, sizeof(buffer), 0);
if (rc < 0)
{
if (errno != EWOULDBLOCK)
{
perror(" recv() failed");
close_conn = TRUE;
}
break;
}
// *****************************************************
// * Check to see if the connection has been *
// * closed by the client *
// *****************************************************
if (rc == 0)
{
printf(" Connection closed\n");
close_conn = TRUE;
break;
}
// *****************************************************
// * Data was received *
// *****************************************************
len = rc;
printf(" %d bytes received\n", len);
// *****************************************************
// * Echo the data back to the client *
// *****************************************************
rc = send(fds[i].fd, buffer, len, 0);
if (rc < 0)
{
perror(" send() failed");
close_conn = TRUE;
break;
}
} while(TRUE);
// *******************************************************
// * If the close_conn flag was turned on, we need *
// * to clean up this active connection. This *
// * clean up process includes removing the *
// * descriptor. *
// *******************************************************
if (close_conn)
{
close(fds[i].fd);
fds[i].fd = -1;
compress_array = TRUE;
}
} // End of existing connection is readable
} // End of loop through pollable descriptors
// ***********************************************************
// * If the compress_array flag was turned on, we need *
// * to squeeze together the array and decrement the number *
// * of file descriptors. We do not need to move back the *
// * events and revents fields because the events will always*
// * be POLLIN in this case, and revents is output. *
// ***********************************************************
if (compress_array)
{
compress_array = FALSE;
for (i = 0; i < nfds; i++)
{
if (fds[i].fd == -1)
{
for(j = i; j < nfds; j++)
{
fds[j].fd = fds[j+1].fd;
}
i--;
nfds--;
}
}
}
} while (end_server == FALSE); // End of serving running.
// *************************************************************
// * Clean up all of the sockets that are open *
// *************************************************************
for (i = 0; i < nfds; i++)
{
if(fds[i].fd >= 0)
close(fds[i].fd);
}
}

View File

@@ -1,306 +0,0 @@
// https://www.ibm.com/docs/en/i/7.2?topic=designs-example-nonblocking-io-select
# include <unistd.h> // close
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <sys/ioctl.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <netinet/in.h>
# include <errno.h>
#define SERVER_PORT 4040
#define TRUE 1
#define FALSE 0
int main ()
{
int i, len, rc;
int on = 1;
int listen_sd, max_sd, new_sd;
int desc_ready, end_server = FALSE;
int close_conn;
char buffer[80];
struct sockaddr_in6 addr;
struct timeval timeout;
fd_set master_set, working_set;
/*************************************************************/
/* Create an AF_INET6 stream socket to receive incoming */
/* connections on */
/*************************************************************/
listen_sd = socket(AF_INET6, SOCK_STREAM, 0);
// listen_sd = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (listen_sd < 0)
{
perror("socket() failed");
exit(-1);
}
/*************************************************************/
/* Allow socket descriptor to be reuseable */
/*************************************************************/
rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
if (rc < 0)
{
perror("setsockopt() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Set socket to be nonblocking. All of the sockets for */
/* the incoming connections will also be nonblocking since */
/* they will inherit that state from the listening socket. */
/*************************************************************/
rc = ioctl(listen_sd, FIONBIO, (char *)&on);
if (rc < 0)
{
perror("ioctl() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Bind the socket */
/*************************************************************/
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
addr.sin6_port = htons(SERVER_PORT);
rc = bind(listen_sd,
(struct sockaddr *)&addr, sizeof(addr));
if (rc < 0)
{
perror("bind() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Set the listen back log */
/*************************************************************/
rc = listen(listen_sd, 32);
if (rc < 0)
{
perror("listen() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Initialize the master fd_set */
/*************************************************************/
FD_ZERO(&master_set);
max_sd = listen_sd;
FD_SET(listen_sd, &master_set);
/*************************************************************/
/* Initialize the timeval struct to 3 minutes. If no */
/* activity after 3 minutes this program will end. */
/*************************************************************/
timeout.tv_sec = 3 * 60;
timeout.tv_usec = 0;
/*************************************************************/
/* Loop waiting for incoming connects or for incoming data */
/* on any of the connected sockets. */
/*************************************************************/
do
{
/**********************************************************/
/* Copy the master fd_set over to the working fd_set. */
/**********************************************************/
memcpy(&working_set, &master_set, sizeof(master_set));
/**********************************************************/
/* Call select() and wait 3 minutes for it to complete. */
/**********************************************************/
printf("\nWaiting on select()...\n");
rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout);
/**********************************************************/
/* Check to see if the select call failed. */
/**********************************************************/
if (rc < 0)
{
perror(" select() failed");
break;
}
/**********************************************************/
/* Check to see if the 3 minute time out expired. */
/**********************************************************/
if (rc == 0)
{
printf(" select() timed out. End program.\n");
break;
}
/**********************************************************/
/* One or more descriptors are readable. Need to */
/* determine which ones they are. */
/**********************************************************/
desc_ready = rc;
for (i=0; i <= max_sd && desc_ready > 0; ++i)
{
/*******************************************************/
/* Check to see if this descriptor is ready */
/*******************************************************/
if (FD_ISSET(i, &working_set))
{
/****************************************************/
/* A descriptor was found that was readable - one */
/* less has to be looked for. This is being done */
/* so that we can stop looking at the working set */
/* once we have found all of the descriptors that */
/* were ready. */
/****************************************************/
desc_ready -= 1;
/****************************************************/
/* Check to see if this is the listening socket */
/****************************************************/
if (i == listen_sd)
{
printf("\n Listening socket is readable\n");
/*************************************************/
/* Accept all incoming connections that are */
/* queued up on the listening socket before we */
/* loop back and call select again. */
/*************************************************/
do
{
/**********************************************/
/* Accept each incoming connection. If */
/* accept fails with EWOULDBLOCK, then we */
/* have accepted all of them. Any other */
/* failure on accept will cause us to end the */
/* server. */
/**********************************************/
new_sd = accept(listen_sd, NULL, NULL);
if (new_sd < 0)
{
if (errno != EWOULDBLOCK)
{
perror(" accept() failed");
end_server = TRUE;
}
break;
}
/**********************************************/
/* Add the new incoming connection to the */
/* master read set */
/**********************************************/
printf(" New incoming connection - %d\n", new_sd);
FD_SET(new_sd, &master_set);
if (new_sd > max_sd)
max_sd = new_sd;
/**********************************************/
/* Loop back up and accept another incoming */
/* connection */
/**********************************************/
} while (new_sd != -1);
}
/****************************************************/
/* This is not the listening socket, therefore an */
/* existing connection must be readable */
/****************************************************/
else
{
printf("\n Descriptor %d is readable\n", i);
close_conn = FALSE;
/*************************************************/
/* Receive all incoming data on this socket */
/* before we loop back and call select again. */
/*************************************************/
do
{
/**********************************************/
/* Receive data on this connection until the */
/* recv fails with EWOULDBLOCK. If any other */
/* failure occurs, we will close the */
/* connection. */
/**********************************************/
rc = recv(i, buffer, sizeof(buffer), 0);
if (rc < 0)
{
if (errno != EWOULDBLOCK)
{
perror(" recv() failed");
close_conn = TRUE;
}
break;
}
/**********************************************/
/* Check to see if the connection has been */
/* closed by the client */
/**********************************************/
if (rc == 0)
{
printf(" Connection closed\n");
close_conn = TRUE;
break;
}
/**********************************************/
/* Data was received */
/**********************************************/
len = rc;
printf(" %d bytes received\n", len);
/**********************************************/
/* Echo the data back to the client */
/**********************************************/
rc = send(i, buffer, len, 0);
if (rc < 0)
{
perror(" send() failed");
close_conn = TRUE;
break;
}
} while (TRUE);
/*************************************************/
/* If the close_conn flag was turned on, we need */
/* to clean up this active connection. This */
/* clean up process includes removing the */
/* descriptor from the master set and */
/* determining the new maximum descriptor value */
/* based on the bits that are still turned on in */
/* the master set. */
/*************************************************/
if (close_conn)
{
close(i);
FD_CLR(i, &master_set);
if (i == max_sd)
{
while (FD_ISSET(max_sd, &master_set) == FALSE)
max_sd -= 1;
}
}
} /* End of existing connection is readable */
} /* End of if (FD_ISSET(i, &working_set)) */
} /* End of loop through selectable descriptors */
} while (end_server == FALSE);
/*************************************************************/
/* Clean up all of the sockets that are open */
/*************************************************************/
for (i=0; i <= max_sd; ++i)
{
if (FD_ISSET(i, &master_set))
close(i);
}
}

View File

@@ -1,5 +1,5 @@
#include "bak__Webserv.hpp"
#include "hugo_Webserv.hpp"
Webserv::Webserv()
{

View File

@@ -2,7 +2,7 @@
#include <iostream>
#include <exception>
#include <stdexcept>
#include "Webserv.hpp"
#include "hugo_Webserv.hpp"
int main(void)
{

BIN
webserv

Binary file not shown.