Goby v2
tcp_server.cpp
1 // Copyright 2009-2018 Toby Schneider (http://gobysoft.org/index.wt/people/toby)
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 //
6 //
7 // This file is part of the Goby Underwater Autonomy Project Libraries
8 // ("The Goby Libraries").
9 //
10 // The Goby Libraries are free software: you can redistribute them and/or modify
11 // them under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 2.1 of the License, or
13 // (at your option) any later version.
14 //
15 // The Goby Libraries are distributed in the hope that they will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
22 
23 #include "tcp_server.h"
24 
25 boost::shared_ptr<goby::util::TCPConnection>
26 goby::util::TCPConnection::create(LineBasedInterface* interface)
27 {
28  return boost::shared_ptr<TCPConnection>(new TCPConnection(interface));
29 }
30 
31 void goby::util::TCPConnection::socket_write(const protobuf::Datagram& line) // give it a string
32 {
33  bool write_in_progress = !out().empty(); // is there anything currently being written?
34  out().push_back(line); // store in write buffer
35  if (!write_in_progress) // if nothing is currently being written, then start
36  write_start();
37 }
38 
39 void goby::util::TCPConnection::socket_close(const boost::system::error_code& error)
40 { // something has gone wrong, so close the socket & make this object inactive
41  if (error ==
42  boost::asio::error::operation_aborted) // if this call is thex result of a timer cancel()
43  return; // ignore it because the connection cancelled the timer
44 
45  if (error)
46  socket_.close();
47 }
48 
49 void goby::util::TCPServer::do_write(const protobuf::Datagram& line)
50 {
51  if (line.has_dest())
52  {
53  std::map<Endpoint, boost::shared_ptr<TCPConnection> >::iterator it =
54  connections_.find(line.dest());
55  if (it != connections_.end())
56  (it->second)->write(line);
57  }
58  else
59  {
60  for (std::map<Endpoint, boost::shared_ptr<TCPConnection> >::iterator
61  it = connections_.begin(),
62  end = connections_.end();
63  it != end; ++it)
64  (it->second)->write(line);
65  }
66 }
67 
68 // close all the connections, it's up to the clients to try to reconnect
69 void goby::util::TCPServer::do_close(const boost::system::error_code& error,
70  goby::util::TCPServer::Endpoint endpt /* = ""*/)
71 {
72  if (!endpt.empty())
73  {
74  std::map<Endpoint, boost::shared_ptr<TCPConnection> >::iterator it =
75  connections_.find(endpt);
76  if (it != connections_.end())
77  (it->second)->close(error);
78  }
79  else
80  {
81  for (std::map<Endpoint, boost::shared_ptr<TCPConnection> >::iterator
82  it = connections_.begin(),
83  end = connections_.end();
84  it != end; ++it)
85  (it->second)->close(error);
86  }
87 }
88 
89 const std::map<goby::util::TCPServer::Endpoint, boost::shared_ptr<goby::util::TCPConnection> >&
90 goby::util::TCPServer::connections()
91 {
92  typedef std::map<Endpoint, boost::shared_ptr<TCPConnection> >::iterator It;
93  It it = connections_.begin(), it_end = connections_.end();
94  while (it != it_end)
95  {
96  if (!(it->second)->socket().is_open())
97  {
98  It to_delete = it;
99  ++it; // increment before erasing!
100  connections_.erase(to_delete);
101  }
102  else
103  {
104  ++it;
105  }
106  }
107  return connections_;
108 }
109 
110 void goby::util::TCPServer::start_accept()
111 {
112  new_connection_ = TCPConnection::create(this);
113  acceptor_.async_accept(new_connection_->socket(),
114  boost::bind(&TCPServer::handle_accept, this, new_connection_,
115  boost::asio::placeholders::error));
116 }
117 
118 void goby::util::TCPServer::handle_accept(boost::shared_ptr<TCPConnection> new_connection,
119  const boost::system::error_code& error)
120 {
121  if (!error)
122  {
123  new_connection_->start();
124  connections_.insert(std::make_pair(new_connection_->remote_endpoint(), new_connection_));
125  start_accept();
126  }
127 }