tcpserver.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /**
  2. * Copyright (c) 2021 Paul-Louis Ageneau
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "tcpserver.hpp"
  19. #include "internals.hpp"
  20. #if RTC_ENABLE_WEBSOCKET
  21. #ifdef _WIN32
  22. #include <winsock2.h>
  23. #else
  24. #include <arpa/inet.h>
  25. #include <fcntl.h>
  26. #include <unistd.h>
  27. #endif
  28. namespace rtc::impl {
  29. TcpServer::TcpServer(uint16_t port) {
  30. PLOG_DEBUG << "Initializing TCP server";
  31. listen(port);
  32. }
  33. TcpServer::~TcpServer() { close(); }
  34. shared_ptr<TcpTransport> TcpServer::accept() {
  35. while (true) {
  36. std::unique_lock lock(mSockMutex);
  37. if (mSock == INVALID_SOCKET)
  38. break;
  39. struct pollfd pfd[2];
  40. pfd[0].fd = mSock;
  41. pfd[0].events = POLLIN;
  42. mInterrupter.prepare(pfd[1]);
  43. lock.unlock();
  44. int ret = ::poll(pfd, 2, -1);
  45. lock.lock();
  46. if (mSock == INVALID_SOCKET)
  47. break;
  48. if (ret < 0) {
  49. if (sockerrno == SEINTR || sockerrno == SEAGAIN) // interrupted
  50. continue;
  51. else
  52. throw std::runtime_error("Failed to wait for socket connection");
  53. }
  54. if (pfd[0].revents & POLLNVAL || pfd[0].revents & POLLERR) {
  55. throw std::runtime_error("Error while waiting for socket connection");
  56. }
  57. if (pfd[0].revents & POLLIN) {
  58. struct sockaddr_storage addr;
  59. socklen_t addrlen = sizeof(addr);
  60. socket_t incomingSock = ::accept(mSock, (struct sockaddr *)&addr, &addrlen);
  61. if (incomingSock != INVALID_SOCKET) {
  62. return std::make_shared<TcpTransport>(incomingSock, nullptr); // no state callback
  63. } else if (sockerrno != SEAGAIN && sockerrno != SEWOULDBLOCK) {
  64. PLOG_ERROR << "TCP server failed, errno=" << sockerrno;
  65. throw std::runtime_error("TCP server failed");
  66. }
  67. }
  68. }
  69. PLOG_DEBUG << "TCP server closed";
  70. return nullptr;
  71. }
  72. void TcpServer::close() {
  73. std::unique_lock lock(mSockMutex);
  74. if (mSock != INVALID_SOCKET) {
  75. PLOG_DEBUG << "Closing TCP server socket";
  76. ::closesocket(mSock);
  77. mSock = INVALID_SOCKET;
  78. mInterrupter.interrupt();
  79. }
  80. }
  81. void TcpServer::listen(uint16_t port) {
  82. PLOG_DEBUG << "Listening on port " << port;
  83. struct addrinfo hints = {};
  84. hints.ai_family = AF_UNSPEC;
  85. hints.ai_socktype = SOCK_STREAM;
  86. hints.ai_protocol = IPPROTO_TCP;
  87. hints.ai_flags = AI_ADDRCONFIG;
  88. struct addrinfo *result = nullptr;
  89. if (::getaddrinfo(nullptr, std::to_string(port).c_str(), &hints, &result))
  90. throw std::runtime_error("Resolution failed for local address");
  91. try {
  92. static const auto find_family = [](struct addrinfo *ai_list, int family) {
  93. struct addrinfo *ai = ai_list;
  94. while (ai && ai->ai_family != family)
  95. ai = ai->ai_next;
  96. return ai;
  97. };
  98. struct addrinfo *ai;
  99. if ((ai = find_family(result, AF_INET6)) == NULL &&
  100. (ai = find_family(result, AF_INET)) == NULL)
  101. throw std::runtime_error("No suitable address family found");
  102. std::unique_lock lock(mSockMutex);
  103. PLOG_VERBOSE << "Creating TCP server socket";
  104. // Create socket
  105. mSock = ::socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
  106. if (mSock == INVALID_SOCKET)
  107. throw std::runtime_error("TCP server socket creation failed");
  108. // Listen on both IPv6 and IPv4
  109. const sockopt_t disabled = 0;
  110. if (ai->ai_family == AF_INET6)
  111. ::setsockopt(mSock, IPPROTO_IPV6, IPV6_V6ONLY,
  112. reinterpret_cast<const char *>(&disabled), sizeof(disabled));
  113. // Set non-blocking
  114. ctl_t b = 1;
  115. if (::ioctlsocket(mSock, FIONBIO, &b) < 0)
  116. throw std::runtime_error("Failed to set socket non-blocking mode");
  117. // Bind socket
  118. if (::bind(mSock, ai->ai_addr, ai->ai_addrlen) < 0) {
  119. PLOG_WARNING << "TCP server socket binding on port " << port
  120. << " failed, errno=" << sockerrno;
  121. throw std::runtime_error("TCP server socket binding failed");
  122. }
  123. // Listen
  124. const int backlog = 10;
  125. if (::listen(mSock, backlog) < 0) {
  126. PLOG_WARNING << "TCP server socket listening failed, errno=" << sockerrno;
  127. throw std::runtime_error("TCP server socket listening failed");
  128. }
  129. if (port != 0) {
  130. mPort = port;
  131. } else {
  132. struct sockaddr_storage addr;
  133. socklen_t addrlen = sizeof(addr);
  134. if (::getsockname(mSock, reinterpret_cast<struct sockaddr *>(&addr), &addrlen) < 0)
  135. throw std::runtime_error("getsockname failed");
  136. switch (addr.ss_family) {
  137. case AF_INET:
  138. mPort = ntohs(reinterpret_cast<struct sockaddr_in *>(&addr)->sin_port);
  139. break;
  140. case AF_INET6:
  141. mPort = ntohs(reinterpret_cast<struct sockaddr_in6 *>(&addr)->sin6_port);
  142. break;
  143. default:
  144. throw std::logic_error("Unknown address family");
  145. }
  146. }
  147. } catch (...) {
  148. freeaddrinfo(result);
  149. if (mSock != INVALID_SOCKET) {
  150. ::closesocket(mSock);
  151. mSock = INVALID_SOCKET;
  152. }
  153. throw;
  154. }
  155. freeaddrinfo(result);
  156. }
  157. } // namespace rtc::impl
  158. #endif