tcpserver.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. static const auto find_family = [](struct addrinfo *ai_list, int family) {
  92. struct addrinfo *ai = ai_list;
  93. while (ai && ai->ai_family != family)
  94. ai = ai->ai_next;
  95. return ai;
  96. };
  97. struct addrinfo *ai;
  98. if ((ai = find_family(result, AF_INET6)) == NULL && (ai = find_family(result, AF_INET)) == NULL)
  99. throw std::runtime_error("No suitable address family found");
  100. try {
  101. std::unique_lock lock(mSockMutex);
  102. PLOG_VERBOSE << "Creating TCP server socket";
  103. // Create socket
  104. mSock = ::socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
  105. if (mSock == INVALID_SOCKET)
  106. throw std::runtime_error("TCP server socket creation failed");
  107. // Listen on both IPv6 and IPv4
  108. const sockopt_t disabled = 0;
  109. if (ai->ai_family == AF_INET6)
  110. ::setsockopt(mSock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&disabled,
  111. sizeof(disabled));
  112. // Set non-blocking
  113. ctl_t b = 1;
  114. if (::ioctlsocket(mSock, FIONBIO, &b) < 0)
  115. throw std::runtime_error("Failed to set socket non-blocking mode");
  116. // Bind socket
  117. if (::bind(mSock, ai->ai_addr, ai->ai_addrlen) < 0) {
  118. PLOG_WARNING << "TCP server socket binding on port " << port
  119. << " failed, errno=" << sockerrno;
  120. throw std::runtime_error("TCP server socket binding failed");
  121. }
  122. // Listen
  123. const int backlog = 10;
  124. if (::listen(mSock, backlog) < 0) {
  125. PLOG_WARNING << "TCP server socket listening failed, errno=" << sockerrno;
  126. throw std::runtime_error("TCP server socket listening failed");
  127. }
  128. if (port != 0) {
  129. mPort = port;
  130. } else {
  131. struct sockaddr_storage addr;
  132. socklen_t addrlen = sizeof(addr);
  133. if (::getsockname(mSock, reinterpret_cast<struct sockaddr *>(&addr), &addrlen) < 0)
  134. throw std::runtime_error("getsockname failed");
  135. switch (addr.ss_family) {
  136. case AF_INET:
  137. mPort = ntohs(reinterpret_cast<struct sockaddr_in *>(&addr)->sin_port);
  138. break;
  139. case AF_INET6:
  140. mPort = ntohs(reinterpret_cast<struct sockaddr_in6 *>(&addr)->sin6_port);
  141. break;
  142. default:
  143. throw std::logic_error("Unknown address family");
  144. }
  145. }
  146. } catch (...) {
  147. freeaddrinfo(result);
  148. if (mSock != INVALID_SOCKET) {
  149. ::closesocket(mSock);
  150. mSock = INVALID_SOCKET;
  151. }
  152. throw;
  153. }
  154. freeaddrinfo(result);
  155. }
  156. } // namespace rtc::impl
  157. #endif