TcpReporting.cpp
Go to the documentation of this file.
1 /***************************************************************************
2 
3  TcpReporting.cpp - TCP reporter
4  -------------------
5  begin : Fri Aug 4 2006
6  copyright : (C) 2006 Bas Kemper
7  2007-2008 Ruben Smits
8  email : kst@ <my name> .be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU Lesser General Public *
13  * License as published by the Free Software Foundation; either *
14  * version 2.1 of the License, or (at your option) any later version. *
15  * *
16  * This library is distributed in the hope that it will be useful, *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
19  * Lesser General Public License for more details. *
20  * *
21  * You should have received a copy of the GNU Lesser General Public *
22  * License along with this library; if not, write to the Free Software *
23  * Foundation, Inc., 59 Temple Place, *
24  * Suite 330, Boston, MA 02111-1307 USA *
25  * *
26  ***************************************************************************/
27 
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <sys/types.h>
31 #include <errno.h>
32 
33 #include "TcpReporting.hpp"
34 #include <rtt/Activity.hpp>
35 #include <rtt/Logger.hpp>
36 #include <rtt/os/Mutex.hpp>
37 #include "socket.hpp"
38 #include "socketmarshaller.hpp"
39 
40 using RTT::Logger;
41 using RTT::os::Mutex;
42 
43 #include "ocl/Component.hpp"
45 
46 namespace OCL
47 {
53  : public RTT::Activity
54  {
55  private:
56  bool inBreak;
59  unsigned short _port;
60  bool _accepting;
61  int _sock;
62 
63  bool listen()
64  {
65  _sock = ::socket(PF_INET, SOCK_STREAM, 0);
66  if( _sock < 0 )
67  {
68  Logger::log() << Logger::Error << "Socket creation failed." << Logger::endl;
69  return false;
70  }
71 
72  struct sockaddr_in localsocket;
73  struct sockaddr remote;
74  int adrlen = sizeof(remote);
75 
76  localsocket.sin_family = AF_INET;
77  localsocket.sin_port = htons(_port);
78  localsocket.sin_addr.s_addr = INADDR_ANY;
79  if( ::bind(_sock, (struct sockaddr*)&localsocket, sizeof(localsocket) ) < 0 )
80  {
81  /* bind can fail when there is a legitimate server when a
82  previous run of orocos has crashed and the kernel does
83  not have freed the port yet. TRY_OTHER_PORTS can
84  select another port if the bind fails. */
85  #define TRY_OTHER_PORTS
86  // TODO: remove #define
87  #ifdef TRY_OTHER_PORTS
88  int i = 1;
89  int r = -1;
90  while( errno == EADDRINUSE && i < 5 && r < 0 )
91  {
92  localsocket.sin_port = htons(_port + i);
93  r = ::bind(_sock, (struct sockaddr*)&localsocket, sizeof(localsocket) );
94  i++;
95  }
96  if( r >= 0 )
97  {
98  Logger::log() << Logger::Info << "Port occupied, use port " << (_port+i-1) << " instead." << Logger::endl;
99  } else {
100  #endif
101  if( errno == EADDRINUSE )
102  {
103  Logger::log() << Logger::Error << "Binding of port failed: address already in use." << Logger::endl;
104  } else {
105  Logger::log() << Logger::Error << "Binding of port failed with errno " << errno << Logger::endl;
106  }
107  ::close(_sock);
108  return false;
109  #ifdef TRY_OTHER_PORTS
110  }
111  #endif
112  }
113 
114  if( ::listen(_sock, 2) < 0 )
115  {
116  Logger::log() << Logger::Info << "Cannot listen on socket" << Logger::endl;
117  ::close(_sock);
118  return true;
119  }
120  while(_accepting)
121  {
122  int socket = ::accept( _sock, &remote,
123  reinterpret_cast<socklen_t*>(&adrlen) );
124  if( socket == -1 )
125  {
126  return false;
127  }
128  if( _accepting )
129  {
130  Logger::log() << Logger::Info << "Incoming connection" << Logger::endl;
131  _marshaller->addConnection( new Orocos::TCP::Socket(socket) );
132  }
133  }
134  return true;
135  }
136 
137  ListenThread( RTT::SocketMarshaller* marshaller, unsigned short port )
138  : Activity(10), _marshaller(marshaller)
139  {
140  inBreak = false;
141  removeInstance();
142  _accepting = true;
143  _port = port;
144  Logger::log() << Logger::Info << "Starting server on port " << port << Logger::endl;
145  this->Activity::start();
146  }
147 
148  // This method should only be called when theadCreationLock is locked.
150  {
151  if( _instance )
152  {
153  delete _instance;
154  }
155  }
156 
157  public:
159  {
160  _accepting = false;
161  }
162 
163  virtual void loop()
164  {
165  if( !inBreak )
166  {
167  if( !listen() )
168  {
169  Logger::log() << Logger::Error << "Could not listen on port " << _port << Logger::endl;
170  } else {
171  Logger::log() << Logger::Info << "Shutting down server" << Logger::endl;
172  }
173  }
174  }
175 
176  virtual bool breakLoop()
177  {
178  inBreak = true;
179  _accepting = false;
180  ::close( _sock );
181  // accept still hangs until a new connection has been established
182  int sock = ::socket(PF_INET, SOCK_STREAM, 0);
183  if( sock > 0 )
184  {
185  struct sockaddr_in socket;
186  socket.sin_family = AF_INET;
187  socket.sin_port = htons(_port);
188  socket.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
189  ::connect( sock, (struct sockaddr*)&socket, sizeof(socket) );
190  ::close( sock );
191  }
192  return true;
193  }
194 
195  static void createInstance( RTT::SocketMarshaller* marshaller, unsigned short port = 3142 )
196  {
197  // The lock is needed to avoid problems when createInstance is called by two
198  // different threads (which in reality should not occur very often).
199  //ListenThread* _oinst = ListenThread::_instance;
200  ListenThread::_instance = new ListenThread( marshaller, port );
201  //delete _oinst;
202  }
203 
204  static void destroyInstance()
205  {
206  ListenThread::_instance->breakLoop();
207  }
208  };
209  ListenThread* ListenThread::_instance = 0;
210 }
211 
212 namespace OCL
213 {
214  TcpReporting::TcpReporting(std::string fr_name /*= "Reporting"*/)
215  : ReportingComponent( fr_name ),
216  port_prop("port","port to listen/send to",3142)
217  {
218  _finishing = false;
219  this->properties()->addProperty( port_prop);
220  }
221 
223  {
224  }
225 
227  {
228  makeReport2();
229  return &report;
230  }
231 
233  port=port_prop.value();
234  return true;
235  }
236 
238  {
239  RTT::Logger::In in("TcpReporting::startup");
240  fbody = new RTT::SocketMarshaller(this);
241  this->addMarshaller( 0, fbody );
244  }
245 
247  {
248  _finishing = true;
250  fbody->shutdown();
252  this->removeMarshallers();
253  }
254 }
bool addMarshaller(RTT::marsh::MarshallInterface *headerM, RTT::marsh::MarshallInterface *bodyM)
A component which writes data reports to a tcp/ip socket. It can serve different clients. It uses a ASCI-based protocol.
static void destroyInstance()
virtual void loop()
ListenThread(RTT::SocketMarshaller *marshaller, unsigned short port)
unsigned int port
reference_t value()
const RTT::PropertyBag * getReport()
RTT::SocketMarshaller * _marshaller
static ListenThread * _instance
Property< T > & addProperty(const std::string &name, T &attr)
virtual bool breakLoop()
A Component for periodically reporting Component Port contents to a human readable text format...
PropertyBag * properties()
ORO_LIST_COMPONENT_TYPE(OCL::logging::GenerationalFileAppender)
RTT::Property< unsigned int > port_prop
static void createInstance(RTT::SocketMarshaller *marshaller, unsigned short port=3142)
unsigned short _port
void addConnection(OCL::TCP::Socket *os)
RTT::SocketMarshaller * fbody


ocl
Author(s): OCL Development Team
autogenerated on Mon Mar 23 2020 04:47:19