socket.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /**
  2. \file socket.cpp
  3. \author Seung Geol Choi
  4. \copyright ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
  5. Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
  6. This program is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU Lesser General Public License as published
  8. by the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. ABY is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. \brief Socket Implementation
  17. */
  18. #include "socket.h"
  19. #include "utils.h"
  20. #include <cstdint>
  21. #include <cstring>
  22. #include <iostream>
  23. #include <boost/asio/connect.hpp>
  24. #include <boost/asio/io_context.hpp>
  25. #include <boost/asio/ip/address.hpp>
  26. #include <boost/asio/ip/tcp.hpp>
  27. #include <boost/asio/ip/v6_only.hpp>
  28. #include <boost/asio/read.hpp>
  29. #include <boost/asio/write.hpp>
  30. using boost::asio::ip::tcp;
  31. struct CSocket::CSocketImpl {
  32. CSocketImpl(std::shared_ptr<boost::asio::io_context> io_context,
  33. tcp::socket&& socket)
  34. : io_context(io_context), socket(std::move(socket)),
  35. acceptor(*io_context)
  36. {
  37. }
  38. CSocketImpl()
  39. : io_context(std::make_shared<boost::asio::io_context>()),
  40. socket(*io_context), acceptor(*io_context)
  41. {}
  42. std::shared_ptr<boost::asio::io_context> io_context;
  43. tcp::socket socket;
  44. tcp::acceptor acceptor;
  45. };
  46. CSocket::CSocket(bool verbose)
  47. : impl_(std::make_unique<CSocketImpl>()), send_count_(0), recv_count_(0),
  48. verbose_(verbose)
  49. {}
  50. CSocket::~CSocket() {
  51. Close();
  52. }
  53. uint64_t CSocket::getSndCnt() const {
  54. std::lock_guard<std::mutex> lock(send_count_mutex_);
  55. return send_count_;
  56. }
  57. uint64_t CSocket::getRcvCnt() const {
  58. std::lock_guard<std::mutex> lock(recv_count_mutex_);
  59. return recv_count_;
  60. }
  61. void CSocket::ResetSndCnt() {
  62. std::lock_guard<std::mutex> lock(send_count_mutex_);
  63. send_count_ = 0;
  64. }
  65. void CSocket::ResetRcvCnt() {
  66. std::lock_guard<std::mutex> lock(recv_count_mutex_);
  67. recv_count_ = 0;
  68. }
  69. bool CSocket::Socket() {
  70. return true;
  71. }
  72. void CSocket::Close() {
  73. impl_->socket.close();
  74. }
  75. std::string CSocket::GetIP() const {
  76. boost::system::error_code ec;
  77. auto endpoint = impl_->socket.local_endpoint(ec);
  78. if (ec) {
  79. return "";
  80. }
  81. return endpoint.address().to_string();
  82. }
  83. uint16_t CSocket::GetPort() const {
  84. boost::system::error_code ec;
  85. auto endpoint = impl_->socket.local_endpoint(ec);
  86. if (ec) {
  87. return 0;
  88. }
  89. return endpoint.port();
  90. }
  91. bool CSocket::Bind(const std::string& ip, uint16_t port) {
  92. boost::system::error_code ec;
  93. boost::asio::ip::address address;
  94. if (ip.empty()) {
  95. // Use "::" if no address is given
  96. address = boost::asio::ip::address_v6();
  97. } else {
  98. // Try to parse given address
  99. address = boost::asio::ip::make_address(ip, ec);
  100. if (ec) {
  101. if (verbose_) {
  102. std::cerr << "make_address failed: " << ec.message() << "\n";
  103. std::cerr << "with argument: " << ip << "\n";
  104. }
  105. return false;
  106. }
  107. }
  108. tcp::endpoint endpoint(address, port);
  109. impl_->acceptor.open(endpoint.protocol(), ec);
  110. if (ec) {
  111. if (verbose_) {
  112. std::cerr << "acceptor socket open failed: " << ec.message() << "\n";
  113. std::cerr << "endpoint: " << endpoint << "\n";
  114. }
  115. return false;
  116. }
  117. // Use dual stack IPv4 and IPv6
  118. if (endpoint.protocol() == tcp::v6()) {
  119. boost::asio::ip::v6_only opt(false);
  120. impl_->acceptor.set_option(opt, ec);
  121. if (ec) {
  122. if (verbose_) {
  123. std::cerr << "acceptor disable option IPPROTO_IPV6/IP_V6ONLY failed: "
  124. << ec.message() << "\n";
  125. }
  126. return false;
  127. }
  128. }
  129. // Set socket options
  130. boost::asio::socket_base::reuse_address opt_reuse_addr(true);
  131. tcp::no_delay opt_tcp_no_delay(true);
  132. impl_->acceptor.set_option(opt_reuse_addr, ec);
  133. if (ec) {
  134. if (verbose_) {
  135. std::cerr << "acceptor set option SO_REUSEADDR failed: " << ec.message() << "\n";
  136. std::cerr << "endpoint: " << endpoint << "\n";
  137. }
  138. return false;
  139. }
  140. impl_->acceptor.set_option(opt_tcp_no_delay, ec);
  141. if (ec) {
  142. if (verbose_) {
  143. std::cerr << "acceptor set option TCP_NODELAY failed: " << ec.message() << "\n";
  144. std::cerr << "endpoint: " << endpoint << "\n";
  145. }
  146. return false;
  147. }
  148. impl_->acceptor.bind(endpoint, ec);
  149. if (ec) {
  150. if (verbose_) {
  151. std::cerr << "bind failed: " << ec.message() << "\n";
  152. std::cerr << "endpoint: " << endpoint << "\n";
  153. }
  154. return false;
  155. }
  156. return true;
  157. }
  158. bool CSocket::Listen(int backlog) {
  159. boost::system::error_code ec;
  160. impl_->acceptor.listen(backlog);
  161. if (ec) {
  162. if (verbose_) {
  163. std::cerr << "listen failed: " << ec.message() << "\n";
  164. std::cerr << "endpoint: " << impl_->acceptor.local_endpoint() << "\n";
  165. }
  166. return false;
  167. }
  168. return true;
  169. }
  170. std::unique_ptr<CSocket> CSocket::Accept() {
  171. boost::system::error_code ec;
  172. auto socket = impl_->acceptor.accept(ec);
  173. if (ec) {
  174. if (verbose_) {
  175. std::cerr << "accept failed: " << ec.message() << "\n";
  176. std::cerr << "endpoint: " << impl_->acceptor.local_endpoint() << "\n";
  177. }
  178. return nullptr;
  179. }
  180. auto csocket = std::make_unique<CSocket>();
  181. csocket->impl_ = std::make_unique<CSocketImpl>(impl_->io_context, std::move(socket));
  182. return csocket;
  183. }
  184. bool CSocket::Connect(const std::string& host, uint16_t port) {
  185. boost::system::error_code ec;
  186. tcp::resolver resolver(*impl_->io_context);
  187. auto endpoints = resolver.resolve(host, std::to_string(port), ec);
  188. if (ec) {
  189. if (verbose_) {
  190. std::cerr << "resolve failed: " << ec.message() << "\n";
  191. }
  192. return false;
  193. }
  194. boost::asio::connect(impl_->socket, endpoints, ec);
  195. if (ec) {
  196. if (verbose_) {
  197. std::cerr << "connect failed: " << ec.message() << "\n";
  198. }
  199. return false;
  200. }
  201. tcp::no_delay opt_tcp_no_delay(true);
  202. impl_->socket.set_option(opt_tcp_no_delay, ec);
  203. if (ec) {
  204. if (verbose_) {
  205. std::cerr << "socket set option TCP_NODELAY failed: " << ec.message() << "\n";
  206. }
  207. return false;
  208. }
  209. return true;
  210. }
  211. size_t CSocket::Receive(void* buf, size_t bytes) {
  212. boost::system::error_code ec;
  213. auto bytes_transferred =
  214. boost::asio::read(impl_->socket, boost::asio::buffer(buf, bytes), ec);
  215. if (ec && verbose_) {
  216. std::cerr << "read failed: " << ec.message() << "\n";
  217. }
  218. {
  219. std::lock_guard<std::mutex> lock(recv_count_mutex_);
  220. recv_count_ += bytes_transferred;
  221. }
  222. return bytes_transferred;
  223. }
  224. size_t CSocket::Send(const void* buf, size_t bytes) {
  225. boost::system::error_code ec;
  226. auto bytes_transferred =
  227. boost::asio::write(impl_->socket, boost::asio::buffer(buf, bytes), ec);
  228. if (ec && verbose_) {
  229. std::cerr << "write failed: " << ec.message() << "\n";
  230. }
  231. {
  232. std::lock_guard<std::mutex> lock(send_count_mutex_);
  233. send_count_ += bytes_transferred;
  234. }
  235. return bytes_transferred;
  236. }