abstractServer.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #include "abstractServer.hpp"
  2. namespace cpr {
  3. void AbstractServer::SetUp() {
  4. Start();
  5. }
  6. void AbstractServer::TearDown() {
  7. Stop();
  8. }
  9. void AbstractServer::Start() {
  10. should_run = true;
  11. serverThread = std::make_shared<std::thread>(&AbstractServer::Run, this);
  12. serverThread->detach();
  13. std::unique_lock<std::mutex> server_lock(server_mutex);
  14. server_start_cv.wait(server_lock);
  15. }
  16. void AbstractServer::Stop() {
  17. should_run = false;
  18. std::unique_lock<std::mutex> server_lock(server_mutex);
  19. server_stop_cv.wait(server_lock);
  20. }
  21. static void EventHandler(mg_connection* conn, int event, void* event_data, void* context) {
  22. switch (event) {
  23. case MG_EV_READ:
  24. case MG_EV_WRITE:
  25. /** Do nothing. Just for housekeeping. **/
  26. break;
  27. case MG_EV_POLL:
  28. /** Do nothing. Just for housekeeping. **/
  29. break;
  30. case MG_EV_CLOSE:
  31. /** Do nothing. Just for housekeeping. **/
  32. break;
  33. case MG_EV_ACCEPT:
  34. /* Initialize HTTPS connection if Server is an HTTPS Server */
  35. static_cast<AbstractServer*>(context)->acceptConnection(conn);
  36. break;
  37. case MG_EV_CONNECT:
  38. /** Do nothing. Just for housekeeping. **/
  39. break;
  40. case MG_EV_HTTP_CHUNK: {
  41. /** Do nothing. Just for housekeeping. **/
  42. } break;
  43. case MG_EV_HTTP_MSG: {
  44. AbstractServer* server = static_cast<AbstractServer*>(context);
  45. server->OnRequest(conn, static_cast<mg_http_message*>(event_data));
  46. } break;
  47. default:
  48. break;
  49. }
  50. }
  51. void AbstractServer::Run() {
  52. // Setup a new mongoose http server.
  53. memset(&mgr, 0, sizeof(mg_mgr));
  54. initServer(&mgr, EventHandler);
  55. // Notify the main thread that the server is up and runing:
  56. server_start_cv.notify_all();
  57. // Main server loop:
  58. while (should_run) {
  59. // NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers)
  60. mg_mgr_poll(&mgr, 100);
  61. }
  62. // Shutdown and cleanup:
  63. timer_args.clear();
  64. mg_mgr_free(&mgr);
  65. // Notify the main thread that we have shut down everything:
  66. server_stop_cv.notify_all();
  67. }
  68. static const std::string base64_chars =
  69. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  70. "abcdefghijklmnopqrstuvwxyz"
  71. "0123456789+/";
  72. /**
  73. * Decodes the given BASE64 string to a normal string.
  74. * Source: https://gist.github.com/williamdes/308b95ac9ef1ee89ae0143529c361d37
  75. **/
  76. std::string AbstractServer::Base64Decode(const std::string& in) {
  77. std::string out;
  78. std::vector<int> T(256, -1);
  79. for (size_t i = 0; i < 64; i++)
  80. T[base64_chars[i]] = static_cast<int>(i);
  81. int val = 0;
  82. int valb = -8;
  83. for (unsigned char c : in) {
  84. if (T[c] == -1) {
  85. break;
  86. }
  87. val = (val << 6) + T[c];
  88. valb += 6;
  89. if (valb >= 0) {
  90. out.push_back(char((val >> valb) & 0xFF));
  91. valb -= 8;
  92. }
  93. }
  94. return out;
  95. }
  96. // Sends error similar like in mongoose 6 method mg_http_send_error
  97. // https://github.com/cesanta/mongoose/blob/6.18/mongoose.c#L7081-L7089
  98. void AbstractServer::SendError(mg_connection* conn, int code, std::string& reason) {
  99. std::string headers{"Content-Type: text/plain\r\nConnection: close\r\n"};
  100. mg_http_reply(conn, code, headers.c_str(), reason.c_str());
  101. }
  102. // Checks whether a pointer to a connection is still managed by a mg_mgr.
  103. // This check tells whether it is still possible to send a message via the given connection
  104. // Note that it is still possible that the pointer of an old connection object may be reused by mongoose.
  105. // In this case, the active connection might refer to a different connection than the one the caller refers to
  106. bool AbstractServer::IsConnectionActive(mg_mgr* mgr, mg_connection* conn) {
  107. mg_connection* c{mgr->conns};
  108. while (c) {
  109. if (c == conn) {
  110. return true;
  111. }
  112. c = c->next;
  113. }
  114. return false;
  115. }
  116. uint16_t AbstractServer::GetRemotePort(const mg_connection* conn) {
  117. return (conn->rem.port >> 8) | (conn->rem.port << 8);
  118. }
  119. uint16_t AbstractServer::GetLocalPort(const mg_connection* conn) {
  120. return (conn->loc.port >> 8) | (conn->loc.port << 8);
  121. }
  122. } // namespace cpr