HTTPServer.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #include "HTTPServer.h"
  2. using namespace std;
  3. // the terminator logic, run in a separate thread
  4. void *tfunc(void* obj) {
  5. ((HTTPServer*) obj)->RunTerminator();
  6. }
  7. void* sfunc(void* obj) {
  8. ((HTTPServer*) obj)->RunServer();
  9. }
  10. void error(string msg) {
  11. cerr << msg << endl;
  12. exit(1);
  13. }
  14. void msg(string msg) {
  15. cout << msg << endl;
  16. }
  17. HTTPServer::HTTPServer(int port) {
  18. this->portno = port;
  19. }
  20. HTTPServer::~HTTPServer() {
  21. }
  22. void HTTPServer::StartServer() {
  23. // socket(int domain, int type, int protocol)
  24. sockfd = socket(AF_INET, SOCK_STREAM, 0);
  25. if (sockfd < 0)
  26. error("Opening socket");
  27. // clear the struct's memory
  28. bzero((char *) &serv_addr, sizeof (serv_addr));
  29. // setup the host_addr structure
  30. serv_addr.sin_family = AF_INET;
  31. // automatically be filled with current host's IP address which is localhost
  32. serv_addr.sin_addr.s_addr = INADDR_ANY;
  33. // convert short to network port order
  34. serv_addr.sin_port = htons(portno);
  35. // to avoid waiting for limbo connection when debugging
  36. int en = 1;
  37. setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &en, sizeof (int));
  38. // bind(int fd, struct sockaddr *local_addr, socklen_t addr_length)
  39. // This bind() call will bind the socket to the current IP address on our port
  40. if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
  41. error("On binding");
  42. // This listen() function will start filling the backlog queue with clients
  43. // The maximum size for the backlog queue to 1
  44. listen(sockfd, 1);
  45. clilen = sizeof (cli_addr);
  46. // create the server thread
  47. pthread_create(&server, NULL, sfunc, this);
  48. }
  49. void HTTPServer::StartTerminator() {
  50. // create the terminator thread
  51. pthread_create(&terminator, NULL, tfunc, this);
  52. }
  53. void HTTPServer::RunServer() {
  54. msg("Server is online!");
  55. while (true) {
  56. // The accept() function blocks untill the backlog has elements
  57. // It then stores the info of the client socket in newsockfd
  58. int csockn = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
  59. if (csockn < 0)
  60. msg("Failed on accept.");
  61. printf("Incoming connection from %s port %ho\n",
  62. inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
  63. ServerThread* clt = new ServerThread(csockn);
  64. clt->Serve();
  65. aclients.push_front(clt);
  66. }
  67. }
  68. void HTTPServer::RunTerminator() {
  69. while (true) {
  70. sleep(0.01);
  71. time_t now = time(NULL);
  72. int nc = aclients.size();
  73. int ttl = 1 / (double) (nc > 0 ? nc : 1); //in seconds
  74. for (list<ServerThread*>::iterator list_iter = aclients.begin(); list_iter != aclients.end();) {
  75. ServerThread* st = *list_iter;
  76. int runningtime = difftime(now, st->GetStartTime());
  77. if (st->IsMarked() || (runningtime >= ttl && st->Terminate(false))) {
  78. if (st->IsMarked())
  79. cout << "Client on socket " << st->GetSocket() << " self terminated" << endl;
  80. else
  81. cout << "Terminated client on socket " << st->GetSocket() << endl;
  82. delete st;
  83. list_iter = aclients.erase(list_iter);
  84. } else {
  85. list_iter++;
  86. }
  87. }
  88. }
  89. }
  90. void HTTPServer::Stop() {
  91. close(sockfd);
  92. if (server)
  93. pthread_cancel(server);
  94. if (terminator)
  95. pthread_cancel(terminator);
  96. }