File indexing completed on 2025-01-30 09:33:41
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
0012 #define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/detail/config.hpp>
0019
0020 #if !defined(BOOST_ASIO_NO_IOSTREAM)
0021
0022 #include <streambuf>
0023 #include <vector>
0024 #include <boost/asio/basic_socket.hpp>
0025 #include <boost/asio/basic_stream_socket.hpp>
0026 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
0027 #include <boost/asio/detail/memory.hpp>
0028 #include <boost/asio/detail/throw_error.hpp>
0029 #include <boost/asio/io_context.hpp>
0030
0031 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
0032 && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
0033 # include <boost/asio/detail/deadline_timer_service.hpp>
0034 #else
0035
0036 # include <boost/asio/steady_timer.hpp>
0037 #endif
0038
0039
0040 #include <boost/asio/detail/push_options.hpp>
0041
0042 namespace boost {
0043 namespace asio {
0044 namespace detail {
0045
0046
0047
0048 class socket_streambuf_io_context
0049 {
0050 protected:
0051 socket_streambuf_io_context(io_context* ctx)
0052 : default_io_context_(ctx)
0053 {
0054 }
0055
0056 shared_ptr<io_context> default_io_context_;
0057 };
0058
0059
0060
0061
0062
0063
0064 class socket_streambuf_buffers
0065 {
0066 protected:
0067 socket_streambuf_buffers()
0068 : get_buffer_(buffer_size),
0069 put_buffer_(buffer_size)
0070 {
0071 }
0072
0073 enum { buffer_size = 512 };
0074 std::vector<char> get_buffer_;
0075 std::vector<char> put_buffer_;
0076 };
0077
0078 }
0079
0080 #if !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)
0081 #define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL
0082
0083
0084 template <typename Protocol,
0085 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
0086 && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
0087 typename Clock = boost::posix_time::ptime,
0088 typename WaitTraits = time_traits<Clock>>
0089 #else
0090
0091 typename Clock = chrono::steady_clock,
0092 typename WaitTraits = wait_traits<Clock>>
0093 #endif
0094
0095 class basic_socket_streambuf;
0096
0097 #endif
0098
0099
0100 #if defined(GENERATING_DOCUMENTATION)
0101 template <typename Protocol,
0102 typename Clock = chrono::steady_clock,
0103 typename WaitTraits = wait_traits<Clock>>
0104 #else
0105 template <typename Protocol, typename Clock, typename WaitTraits>
0106 #endif
0107 class basic_socket_streambuf
0108 : public std::streambuf,
0109 private detail::socket_streambuf_io_context,
0110 private detail::socket_streambuf_buffers,
0111 #if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
0112 private basic_socket<Protocol>
0113 #else
0114 public basic_socket<Protocol>
0115 #endif
0116 {
0117 private:
0118
0119
0120 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
0121 && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
0122 typedef WaitTraits traits_helper;
0123 #else
0124
0125 typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
0126 #endif
0127
0128
0129 public:
0130
0131 typedef Protocol protocol_type;
0132
0133
0134 typedef typename Protocol::endpoint endpoint_type;
0135
0136
0137 typedef Clock clock_type;
0138
0139 #if defined(GENERATING_DOCUMENTATION)
0140
0141 typedef typename WaitTraits::time_type time_type;
0142
0143
0144 typedef typename WaitTraits::time_point time_point;
0145
0146
0147 typedef typename WaitTraits::duration_type duration_type;
0148
0149
0150 typedef typename WaitTraits::duration duration;
0151 #else
0152 # if !defined(BOOST_ASIO_NO_DEPRECATED)
0153 typedef typename traits_helper::time_type time_type;
0154 typedef typename traits_helper::duration_type duration_type;
0155 # endif
0156 typedef typename traits_helper::time_type time_point;
0157 typedef typename traits_helper::duration_type duration;
0158 #endif
0159
0160
0161 basic_socket_streambuf()
0162 : detail::socket_streambuf_io_context(new io_context),
0163 basic_socket<Protocol>(*default_io_context_),
0164 expiry_time_(max_expiry_time())
0165 {
0166 init_buffers();
0167 }
0168
0169
0170 explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s)
0171 : detail::socket_streambuf_io_context(0),
0172 basic_socket<Protocol>(std::move(s)),
0173 expiry_time_(max_expiry_time())
0174 {
0175 init_buffers();
0176 }
0177
0178
0179 basic_socket_streambuf(basic_socket_streambuf&& other)
0180 : detail::socket_streambuf_io_context(other),
0181 basic_socket<Protocol>(std::move(other.socket())),
0182 ec_(other.ec_),
0183 expiry_time_(other.expiry_time_)
0184 {
0185 get_buffer_.swap(other.get_buffer_);
0186 put_buffer_.swap(other.put_buffer_);
0187 setg(other.eback(), other.gptr(), other.egptr());
0188 setp(other.pptr(), other.epptr());
0189 other.ec_ = boost::system::error_code();
0190 other.expiry_time_ = max_expiry_time();
0191 other.init_buffers();
0192 }
0193
0194
0195 basic_socket_streambuf& operator=(basic_socket_streambuf&& other)
0196 {
0197 this->close();
0198 socket() = std::move(other.socket());
0199 detail::socket_streambuf_io_context::operator=(other);
0200 ec_ = other.ec_;
0201 expiry_time_ = other.expiry_time_;
0202 get_buffer_.swap(other.get_buffer_);
0203 put_buffer_.swap(other.put_buffer_);
0204 setg(other.eback(), other.gptr(), other.egptr());
0205 setp(other.pptr(), other.epptr());
0206 other.ec_ = boost::system::error_code();
0207 other.expiry_time_ = max_expiry_time();
0208 other.put_buffer_.resize(buffer_size);
0209 other.init_buffers();
0210 return *this;
0211 }
0212
0213
0214 virtual ~basic_socket_streambuf()
0215 {
0216 if (pptr() != pbase())
0217 overflow(traits_type::eof());
0218 }
0219
0220
0221
0222
0223
0224
0225
0226
0227 basic_socket_streambuf* connect(const endpoint_type& endpoint)
0228 {
0229 init_buffers();
0230 ec_ = boost::system::error_code();
0231 this->connect_to_endpoints(&endpoint, &endpoint + 1);
0232 return !ec_ ? this : 0;
0233 }
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244 template <typename... T>
0245 basic_socket_streambuf* connect(T... x)
0246 {
0247 init_buffers();
0248 typedef typename Protocol::resolver resolver_type;
0249 resolver_type resolver(socket().get_executor());
0250 connect_to_endpoints(resolver.resolve(x..., ec_));
0251 return !ec_ ? this : 0;
0252 }
0253
0254
0255
0256
0257
0258
0259 basic_socket_streambuf* close()
0260 {
0261 sync();
0262 socket().close(ec_);
0263 if (!ec_)
0264 init_buffers();
0265 return !ec_ ? this : 0;
0266 }
0267
0268
0269 basic_socket<Protocol>& socket()
0270 {
0271 return *this;
0272 }
0273
0274
0275
0276
0277
0278
0279 const boost::system::error_code& error() const
0280 {
0281 return ec_;
0282 }
0283
0284 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0285
0286
0287
0288
0289
0290
0291 const boost::system::error_code& puberror() const
0292 {
0293 return error();
0294 }
0295
0296
0297
0298
0299
0300
0301
0302 time_point expires_at() const
0303 {
0304 return expiry_time_;
0305 }
0306 #endif
0307
0308
0309
0310
0311
0312
0313 time_point expiry() const
0314 {
0315 return expiry_time_;
0316 }
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327 void expires_at(const time_point& expiry_time)
0328 {
0329 expiry_time_ = expiry_time;
0330 }
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341 void expires_after(const duration& expiry_time)
0342 {
0343 expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
0344 }
0345
0346 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0347
0348
0349
0350
0351
0352 duration expires_from_now() const
0353 {
0354 return traits_helper::subtract(expires_at(), traits_helper::now());
0355 }
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367 void expires_from_now(const duration& expiry_time)
0368 {
0369 expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
0370 }
0371 #endif
0372
0373 protected:
0374 int_type underflow()
0375 {
0376 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
0377 ec_ = boost::asio::error::operation_not_supported;
0378 return traits_type::eof();
0379 #else
0380 if (gptr() != egptr())
0381 return traits_type::eof();
0382
0383 for (;;)
0384 {
0385
0386 if (traits_helper::less_than(expiry_time_, traits_helper::now()))
0387 {
0388 ec_ = boost::asio::error::timed_out;
0389 return traits_type::eof();
0390 }
0391
0392
0393 if (!socket().native_non_blocking())
0394 socket().native_non_blocking(true, ec_);
0395 detail::buffer_sequence_adapter<mutable_buffer, mutable_buffer>
0396 bufs(boost::asio::buffer(get_buffer_) + putback_max);
0397 detail::signed_size_type bytes = detail::socket_ops::recv(
0398 socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);
0399
0400
0401 if (bytes > 0)
0402 {
0403 setg(&get_buffer_[0], &get_buffer_[0] + putback_max,
0404 &get_buffer_[0] + putback_max + bytes);
0405 return traits_type::to_int_type(*gptr());
0406 }
0407
0408
0409 if (bytes == 0)
0410 {
0411 ec_ = boost::asio::error::eof;
0412 return traits_type::eof();
0413 }
0414
0415
0416 if (ec_ != boost::asio::error::would_block
0417 && ec_ != boost::asio::error::try_again)
0418 return traits_type::eof();
0419
0420
0421 if (detail::socket_ops::poll_read(
0422 socket().native_handle(), 0, timeout(), ec_) < 0)
0423 return traits_type::eof();
0424 }
0425 #endif
0426 }
0427
0428 int_type overflow(int_type c)
0429 {
0430 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
0431 ec_ = boost::asio::error::operation_not_supported;
0432 return traits_type::eof();
0433 #else
0434 char_type ch = traits_type::to_char_type(c);
0435
0436
0437 const_buffer output_buffer;
0438 if (put_buffer_.empty())
0439 {
0440 if (traits_type::eq_int_type(c, traits_type::eof()))
0441 return traits_type::not_eof(c);
0442 output_buffer = boost::asio::buffer(&ch, sizeof(char_type));
0443 }
0444 else
0445 {
0446 output_buffer = boost::asio::buffer(pbase(),
0447 (pptr() - pbase()) * sizeof(char_type));
0448 }
0449
0450 while (output_buffer.size() > 0)
0451 {
0452
0453 if (traits_helper::less_than(expiry_time_, traits_helper::now()))
0454 {
0455 ec_ = boost::asio::error::timed_out;
0456 return traits_type::eof();
0457 }
0458
0459
0460 if (!socket().native_non_blocking())
0461 socket().native_non_blocking(true, ec_);
0462 detail::buffer_sequence_adapter<
0463 const_buffer, const_buffer> bufs(output_buffer);
0464 detail::signed_size_type bytes = detail::socket_ops::send(
0465 socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);
0466
0467
0468 if (bytes > 0)
0469 {
0470 output_buffer += static_cast<std::size_t>(bytes);
0471 continue;
0472 }
0473
0474
0475 if (ec_ != boost::asio::error::would_block
0476 && ec_ != boost::asio::error::try_again)
0477 return traits_type::eof();
0478
0479
0480 if (detail::socket_ops::poll_write(
0481 socket().native_handle(), 0, timeout(), ec_) < 0)
0482 return traits_type::eof();
0483 }
0484
0485 if (!put_buffer_.empty())
0486 {
0487 setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
0488
0489
0490 if (traits_type::eq_int_type(c, traits_type::eof()))
0491 return traits_type::not_eof(c);
0492
0493
0494 *pptr() = ch;
0495 pbump(1);
0496 }
0497
0498 return c;
0499 #endif
0500 }
0501
0502 int sync()
0503 {
0504 return overflow(traits_type::eof());
0505 }
0506
0507 std::streambuf* setbuf(char_type* s, std::streamsize n)
0508 {
0509 if (pptr() == pbase() && s == 0 && n == 0)
0510 {
0511 put_buffer_.clear();
0512 setp(0, 0);
0513 sync();
0514 return this;
0515 }
0516
0517 return 0;
0518 }
0519
0520 private:
0521
0522 basic_socket_streambuf(const basic_socket_streambuf&) = delete;
0523 basic_socket_streambuf& operator=(
0524 const basic_socket_streambuf&) = delete;
0525
0526 void init_buffers()
0527 {
0528 setg(&get_buffer_[0],
0529 &get_buffer_[0] + putback_max,
0530 &get_buffer_[0] + putback_max);
0531
0532 if (put_buffer_.empty())
0533 setp(0, 0);
0534 else
0535 setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
0536 }
0537
0538 int timeout() const
0539 {
0540 int64_t msec = traits_helper::to_posix_duration(
0541 traits_helper::subtract(expiry_time_,
0542 traits_helper::now())).total_milliseconds();
0543 if (msec > (std::numeric_limits<int>::max)())
0544 msec = (std::numeric_limits<int>::max)();
0545 else if (msec < 0)
0546 msec = 0;
0547 return static_cast<int>(msec);
0548 }
0549
0550 template <typename EndpointSequence>
0551 void connect_to_endpoints(const EndpointSequence& endpoints)
0552 {
0553 this->connect_to_endpoints(endpoints.begin(), endpoints.end());
0554 }
0555
0556 template <typename EndpointIterator>
0557 void connect_to_endpoints(EndpointIterator begin, EndpointIterator end)
0558 {
0559 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
0560 ec_ = boost::asio::error::operation_not_supported;
0561 #else
0562 if (ec_)
0563 return;
0564
0565 ec_ = boost::asio::error::not_found;
0566 for (EndpointIterator i = begin; i != end; ++i)
0567 {
0568
0569 if (traits_helper::less_than(expiry_time_, traits_helper::now()))
0570 {
0571 ec_ = boost::asio::error::timed_out;
0572 return;
0573 }
0574
0575
0576 typename Protocol::endpoint ep(*i);
0577 socket().close(ec_);
0578 socket().open(ep.protocol(), ec_);
0579 if (ec_)
0580 continue;
0581
0582
0583 if (!socket().native_non_blocking())
0584 socket().native_non_blocking(true, ec_);
0585 detail::socket_ops::connect(socket().native_handle(),
0586 ep.data(), ep.size(), ec_);
0587
0588
0589 if (!ec_)
0590 return;
0591
0592
0593 if (ec_ != boost::asio::error::in_progress
0594 && ec_ != boost::asio::error::would_block)
0595 continue;
0596
0597
0598 if (detail::socket_ops::poll_connect(
0599 socket().native_handle(), timeout(), ec_) < 0)
0600 continue;
0601
0602
0603 int connect_error = 0;
0604 size_t connect_error_len = sizeof(connect_error);
0605 if (detail::socket_ops::getsockopt(socket().native_handle(), 0,
0606 SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_)
0607 == detail::socket_error_retval)
0608 return;
0609
0610
0611 ec_ = boost::system::error_code(connect_error,
0612 boost::asio::error::get_system_category());
0613 if (!ec_)
0614 return;
0615 }
0616 #endif
0617 }
0618
0619
0620 static time_point max_expiry_time()
0621 {
0622 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
0623 && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
0624 return boost::posix_time::pos_infin;
0625 #else
0626
0627 return (time_point::max)();
0628 #endif
0629
0630 }
0631
0632 enum { putback_max = 8 };
0633 boost::system::error_code ec_;
0634 time_point expiry_time_;
0635 };
0636
0637 }
0638 }
0639
0640 #include <boost/asio/detail/pop_options.hpp>
0641
0642 #endif
0643
0644 #endif