Advertisement
Guest User

UdpConnection.h and UdpConnection.cpp

a guest
Apr 30th, 2012
213
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.32 KB | None | 0 0
  1. /*
  2.  * UdpConnection.h
  3.  *
  4.  *  Created on: 2011-02-25
  5.  *      Author: cdunphy
  6.  */
  7.  
  8. // Portions Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  9. //
  10. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  11. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  12. //
  13. #ifndef DATAGRAMCONNECTION_H_
  14. #define DATAGRAMCONNECTION_H_
  15.  
  16. #include "AsioConnection.h"
  17.  
  18. #include <boost/lexical_cast.hpp>
  19.  
  20. namespace shaw_rsc
  21. {
  22.  
  23. struct UdpException: public std::runtime_error
  24. {
  25.     UdpException(const std::string& msg) : std::runtime_error(msg) { }
  26. };
  27.  
  28. /*
  29.  * This is the concrete class that manages UDP connections.
  30.  */
  31. class UdpConnection: public AsioConnection
  32. {
  33. public:
  34.     /*
  35.      * Use this constructor for clients (connecting to a remote socket).
  36.      */
  37.     UdpConnection(
  38.         const std::string& _host,
  39.         const std::string& _port,
  40.         int r_timeout,
  41.         Mode mode
  42.     ) : AsioConnection(0, r_timeout),
  43.             socket(io_service),
  44.             remote_endpoint(),
  45.             host(_host),
  46.             port(_port)
  47.     {
  48.         check_deadline();
  49.         connect(mode);
  50.     }
  51.  
  52.     std::size_t write(const DataBuffer& data);
  53.     std::size_t read(DataBuffer& data);
  54.     const std::string str() const;
  55.  
  56. private:
  57.  
  58.     void connect(Mode mode);
  59.     void check_deadline();
  60.  
  61.     boost::asio::ip::udp::socket socket;
  62.     boost::asio::ip::udp::endpoint remote_endpoint;
  63.     std::string host;
  64.     std::string port;
  65. };
  66.  
  67. }
  68.  
  69. #endif /* DATAGRAMCONNECTION_H_ */
  70.  
  71.  
  72. /*
  73.  * UdpConnection.cpp
  74.  *
  75.  *  Created on: 2011-02-25
  76.  *      Author: cdunphy
  77.  */
  78.  
  79. #include "UdpConnection.h"
  80.  
  81. using std::string;
  82. using std::endl;
  83. using std::stringstream;
  84. using std::exception;
  85.  
  86. using boost::asio::buffer;
  87. using boost::asio::ip::udp;
  88. using boost::system::error_code;
  89. using boost::system::system_error;
  90. using boost::asio::deadline_timer;
  91. using boost::bind;
  92. using boost::lexical_cast;
  93.  
  94. namespace shaw_rsc
  95. {
  96.  
  97. size_t UdpConnection::write(const DataBuffer& data)
  98. {
  99.     size_t bytes_written = 0;
  100.  
  101.     /*
  102.      * Check to see if the socket is bad before writing
  103.      */
  104.     if (error &&
  105.             error.value() != boost::asio::error::operation_aborted &&
  106.             error.value() != boost::asio::error::timed_out &&
  107.             error != boost::asio::error::try_again)
  108.         throw UdpException(error.message());
  109.  
  110.     socket.async_send_to(buffer(data), remote_endpoint,
  111.                          strand.wrap(bind(&AsioConnection::handle_send, this, _1, _2,
  112.                                           &error, &bytes_written)));
  113.  
  114.     do
  115.     {
  116.         strand.get_io_service().run_one();
  117.     }
  118.     while (error == boost::asio::error::would_block
  119.             || error == boost::asio::error::try_again);
  120.  
  121.     if (error)
  122.     {
  123.         if (error.value() == boost::asio::error::operation_aborted
  124.                 || error.value() == boost::asio::error::timed_out)
  125.             throw SocketTimeoutException(error.message());
  126.         else
  127.             throw UdpException(error.message());
  128.     }
  129.  
  130.     reset_deadline();
  131.     return bytes_written;
  132. }
  133.  
  134. size_t UdpConnection::read(DataBuffer& data)
  135. {
  136.     /*
  137.     * Check to see if the socket is bad before writing
  138.     */
  139.     if (error &&
  140.             error.value() != boost::asio::error::operation_aborted &&
  141.             error.value() != boost::asio::error::timed_out &&
  142.             error != boost::asio::error::try_again)
  143.         throw UdpException(error.message());
  144.  
  145.     data.clear();
  146.  
  147.     /*
  148.      * Reset the deadline timer to expire according
  149.      * to the configured read timeout.
  150.      */
  151.     deadline.expires_from_now(read_timeout);
  152.  
  153.     size_t bytes_read = 0;
  154.     boost::array<char, BUF_SIZE> buff;
  155.  
  156.     error = boost::asio::error::would_block;
  157.     socket.async_receive_from(buffer(buff), remote_endpoint,
  158.                               strand.wrap(boost::bind(&AsioConnection::handle_receive, this, _1, _2, &error,
  159.                                                       &bytes_read)));
  160.  
  161.     do
  162.     {
  163.         strand.get_io_service().run_one();
  164.     }
  165.     while (error == boost::asio::error::would_block ||
  166.             error == boost::asio::error::try_again);
  167.  
  168.     // Reset the deadline timer so we can leave this socket open as long
  169.     // as we want.
  170.     reset_deadline();
  171.  
  172.     /*
  173.      * Check for errors after the read.
  174.      */
  175.     if (error)
  176.     {
  177.         if (error.value() == boost::asio::error::operation_aborted
  178.                 || error.value() == boost::asio::error::timed_out)
  179.             throw SocketTimeoutException(error.message());
  180.         else
  181.             throw UdpException(error.message());
  182.     }
  183.     else
  184.         data.insert(data.end(), buff.begin(), buff.begin() + bytes_read);
  185.  
  186.     return bytes_read;
  187. }
  188.  
  189. void UdpConnection::connect(Mode mode)
  190. {
  191.     if (!socket.is_open())
  192.         socket.open(boost::asio::ip::udp::v4());
  193.  
  194.     if (mode == SERVER)
  195.     {
  196.         socket.bind(
  197.             udp::endpoint(udp::v4(),
  198.                           lexical_cast<int>(port)), error);
  199.     }
  200.     else if (mode == CLIENT)
  201.     {
  202.         udp::resolver resolver(io_service);
  203.         udp::resolver::query query(udp::v4(), host, port);
  204.         remote_endpoint = *resolver.resolve(query, error);
  205.     }
  206. }
  207.  
  208. void UdpConnection::check_deadline()
  209. {
  210.     // Check whether the deadline has passed. We compare the deadline against
  211.     // the current time since a new asynchronous operation may have moved the
  212.     // deadline before this actor had a chance to run.
  213.     if (deadline.expires_at() <= deadline_timer::traits_type::now())
  214.     {
  215.         // The deadline has passed. The outstanding asynchronous operation needs
  216.         // to be cancelled so that the blocked receive() function will return.
  217.         //
  218.         // Please note that cancel() has portability issues on some versions of
  219.         // Microsoft Windows, and it may be necessary to use close() instead.
  220.         // Consult the documentation for cancel() for further information.
  221.         socket.cancel();
  222.  
  223.         // There is no longer an active deadline. The expiry is set to positive
  224.         // infinity so that the actor takes no action until a new deadline is set.
  225.         reset_deadline();
  226.     }
  227.  
  228.     // Put the actor back to sleep.
  229.     deadline.async_wait(strand.wrap(boost::bind(&UdpConnection::check_deadline, this)));
  230. }
  231.  
  232. /*
  233.  * This member function is good for diagnostic purposes
  234.  */
  235. const string UdpConnection::str() const
  236. {
  237.     stringstream sstr;
  238.     sstr << "Host: " << host << endl;
  239.     sstr << "Port: " << port << endl;
  240.     sstr << "Read timeout: " << read_timeout_int << endl;
  241.     sstr << "Remote Endpoint Address: " << remote_endpoint.address().to_string()
  242.     << endl;
  243.     sstr << "Remote Endpoint Port: " << remote_endpoint.port() << endl;
  244.  
  245.     try
  246.     {
  247.         sstr << "Socket Remote Endpoint Address: "
  248.         << socket.remote_endpoint().address().to_string() << endl;
  249.         sstr << "Socket Remote Endpoint Port: "
  250.         << socket.remote_endpoint().port() << endl;
  251.     }
  252.     catch (exception& e) { }
  253.  
  254.     try
  255.     {
  256.         sstr << "Socket Local Endpoint Address: "
  257.         << socket.local_endpoint().address().to_string() << endl;
  258.         sstr << "Socket Local Endpoint Port: " << socket.local_endpoint().port()
  259.         << endl;
  260.     }
  261.     catch (exception& e) { }
  262.  
  263.     return sstr.str();
  264. }
  265.  
  266. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement