118 lines
3.1 KiB
C++
118 lines
3.1 KiB
C++
#include "HTTPServer.h"
|
|
|
|
using namespace std;
|
|
|
|
// the terminator logic, run in a separate thread
|
|
|
|
void *tfunc(void* obj) {
|
|
((HTTPServer*) obj)->RunTerminator();
|
|
}
|
|
|
|
void* sfunc(void* obj) {
|
|
((HTTPServer*) obj)->RunServer();
|
|
}
|
|
|
|
void error(string msg) {
|
|
cerr << msg << endl;
|
|
exit(1);
|
|
}
|
|
|
|
void msg(string msg) {
|
|
cout << msg << endl;
|
|
}
|
|
|
|
HTTPServer::HTTPServer(int port) {
|
|
this->portno = port;
|
|
}
|
|
|
|
HTTPServer::~HTTPServer() {
|
|
}
|
|
|
|
void HTTPServer::StartServer() {
|
|
// socket(int domain, int type, int protocol)
|
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sockfd < 0)
|
|
error("Opening socket");
|
|
|
|
// clear the struct's memory
|
|
bzero((char *) &serv_addr, sizeof (serv_addr));
|
|
|
|
// setup the host_addr structure
|
|
serv_addr.sin_family = AF_INET;
|
|
|
|
// automatically be filled with current host's IP address which is localhost
|
|
serv_addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
// convert short to network port order
|
|
serv_addr.sin_port = htons(portno);
|
|
|
|
// to avoid waiting for limbo connection when debugging
|
|
int en = 1;
|
|
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &en, sizeof (int));
|
|
|
|
// bind(int fd, struct sockaddr *local_addr, socklen_t addr_length)
|
|
// This bind() call will bind the socket to the current IP address on our port
|
|
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
|
|
error("On binding");
|
|
// This listen() function will start filling the backlog queue with clients
|
|
// The maximum size for the backlog queue to 1
|
|
listen(sockfd, 1);
|
|
|
|
clilen = sizeof (cli_addr);
|
|
|
|
// create the server thread
|
|
pthread_create(&server, NULL, sfunc, this);
|
|
}
|
|
|
|
void HTTPServer::StartTerminator() {
|
|
// create the terminator thread
|
|
pthread_create(&terminator, NULL, tfunc, this);
|
|
}
|
|
|
|
void HTTPServer::RunServer() {
|
|
msg("Server is online!");
|
|
while (true) {
|
|
// The accept() function blocks untill the backlog has elements
|
|
// It then stores the info of the client socket in newsockfd
|
|
int csockn = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
|
|
if (csockn < 0)
|
|
msg("Failed on accept.");
|
|
|
|
printf("Incoming connection from %s port %ho\n",
|
|
inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
|
|
ServerThread* clt = new ServerThread(csockn);
|
|
clt->Serve();
|
|
aclients.push_front(clt);
|
|
}
|
|
}
|
|
|
|
void HTTPServer::RunTerminator() {
|
|
while (true) {
|
|
sleep(0.01);
|
|
time_t now = time(NULL);
|
|
int nc = aclients.size();
|
|
int ttl = 1 / (double) (nc > 0 ? nc : 1); //in seconds
|
|
for (list<ServerThread*>::iterator list_iter = aclients.begin(); list_iter != aclients.end();) {
|
|
ServerThread* st = *list_iter;
|
|
int runningtime = difftime(now, st->GetStartTime());
|
|
if (st->IsMarked() || (runningtime >= ttl && st->Terminate(false))) {
|
|
if (st->IsMarked())
|
|
cout << "Client on socket " << st->GetSocket() << " self terminated" << endl;
|
|
else
|
|
cout << "Terminated client on socket " << st->GetSocket() << endl;
|
|
delete st;
|
|
list_iter = aclients.erase(list_iter);
|
|
} else {
|
|
list_iter++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void HTTPServer::Stop() {
|
|
close(sockfd);
|
|
if (server)
|
|
pthread_cancel(server);
|
|
if (terminator)
|
|
pthread_cancel(terminator);
|
|
} |