Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <sys/socket.h>
00029 #include <netinet/in.h>
00030 #include <sys/types.h>
00031 #include <errno.h>
00032
00033 #include "TcpReporting.hpp"
00034 #include <rtt/Activity.hpp>
00035 #include <rtt/Logger.hpp>
00036 #include <rtt/os/Mutex.hpp>
00037 #include "socket.hpp"
00038 #include "socketmarshaller.hpp"
00039
00040 using RTT::Logger;
00041 using RTT::os::Mutex;
00042
00043 #include "ocl/Component.hpp"
00044 ORO_LIST_COMPONENT_TYPE(OCL::TcpReporting);
00045
00046 namespace OCL
00047 {
00052 class ListenThread
00053 : public RTT::Activity
00054 {
00055 private:
00056 bool inBreak;
00057 static ListenThread* _instance;
00058 RTT::SocketMarshaller* _marshaller;
00059 unsigned short _port;
00060 bool _accepting;
00061 int _sock;
00062
00063 bool listen()
00064 {
00065 _sock = ::socket(PF_INET, SOCK_STREAM, 0);
00066 if( _sock < 0 )
00067 {
00068 Logger::log() << Logger::Error << "Socket creation failed." << Logger::endl;
00069 return false;
00070 }
00071
00072 struct sockaddr_in localsocket;
00073 struct sockaddr remote;
00074 int adrlen = sizeof(remote);
00075
00076 localsocket.sin_family = AF_INET;
00077 localsocket.sin_port = htons(_port);
00078 localsocket.sin_addr.s_addr = INADDR_ANY;
00079 if( ::bind(_sock, (struct sockaddr*)&localsocket, sizeof(localsocket) ) < 0 )
00080 {
00081
00082
00083
00084
00085 #define TRY_OTHER_PORTS
00086
00087 #ifdef TRY_OTHER_PORTS
00088 int i = 1;
00089 int r = -1;
00090 while( errno == EADDRINUSE && i < 5 && r < 0 )
00091 {
00092 localsocket.sin_port = htons(_port + i);
00093 r = ::bind(_sock, (struct sockaddr*)&localsocket, sizeof(localsocket) );
00094 i++;
00095 }
00096 if( r >= 0 )
00097 {
00098 Logger::log() << Logger::Info << "Port occupied, use port " << (_port+i-1) << " instead." << Logger::endl;
00099 } else {
00100 #endif
00101 if( errno == EADDRINUSE )
00102 {
00103 Logger::log() << Logger::Error << "Binding of port failed: address already in use." << Logger::endl;
00104 } else {
00105 Logger::log() << Logger::Error << "Binding of port failed with errno " << errno << Logger::endl;
00106 }
00107 ::close(_sock);
00108 return false;
00109 #ifdef TRY_OTHER_PORTS
00110 }
00111 #endif
00112 }
00113
00114 if( ::listen(_sock, 2) < 0 )
00115 {
00116 Logger::log() << Logger::Info << "Cannot listen on socket" << Logger::endl;
00117 ::close(_sock);
00118 return true;
00119 }
00120 while(_accepting)
00121 {
00122 int socket = ::accept( _sock, &remote,
00123 reinterpret_cast<socklen_t*>(&adrlen) );
00124 if( socket == -1 )
00125 {
00126 return false;
00127 }
00128 if( _accepting )
00129 {
00130 Logger::log() << Logger::Info << "Incoming connection" << Logger::endl;
00131 _marshaller->addConnection( new Orocos::TCP::Socket(socket) );
00132 }
00133 }
00134 return true;
00135 }
00136
00137 ListenThread( RTT::SocketMarshaller* marshaller, unsigned short port )
00138 : Activity(10), _marshaller(marshaller)
00139 {
00140 inBreak = false;
00141 removeInstance();
00142 _accepting = true;
00143 _port = port;
00144 Logger::log() << Logger::Info << "Starting server on port " << port << Logger::endl;
00145 this->Activity::start();
00146 }
00147
00148
00149 void removeInstance()
00150 {
00151 if( _instance )
00152 {
00153 delete _instance;
00154 }
00155 }
00156
00157 public:
00158 ~ListenThread()
00159 {
00160 _accepting = false;
00161 }
00162
00163 virtual void loop()
00164 {
00165 if( !inBreak )
00166 {
00167 if( !listen() )
00168 {
00169 Logger::log() << Logger::Error << "Could not listen on port " << _port << Logger::endl;
00170 } else {
00171 Logger::log() << Logger::Info << "Shutting down server" << Logger::endl;
00172 }
00173 }
00174 }
00175
00176 virtual bool breakLoop()
00177 {
00178 inBreak = true;
00179 _accepting = false;
00180 ::close( _sock );
00181
00182 int sock = ::socket(PF_INET, SOCK_STREAM, 0);
00183 if( sock > 0 )
00184 {
00185 struct sockaddr_in socket;
00186 socket.sin_family = AF_INET;
00187 socket.sin_port = htons(_port);
00188 socket.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00189 ::connect( sock, (struct sockaddr*)&socket, sizeof(socket) );
00190 ::close( sock );
00191 }
00192 return true;
00193 }
00194
00195 static void createInstance( RTT::SocketMarshaller* marshaller, unsigned short port = 3142 )
00196 {
00197
00198
00199
00200 ListenThread::_instance = new ListenThread( marshaller, port );
00201
00202 }
00203
00204 static void destroyInstance()
00205 {
00206 ListenThread::_instance->breakLoop();
00207 }
00208 };
00209 ListenThread* ListenThread::_instance = 0;
00210 }
00211
00212 namespace OCL
00213 {
00214 TcpReporting::TcpReporting(std::string fr_name )
00215 : ReportingComponent( fr_name ),
00216 port_prop("port","port to listen/send to",3142)
00217 {
00218 _finishing = false;
00219 this->properties()->addProperty( port_prop);
00220 }
00221
00222 TcpReporting::~TcpReporting()
00223 {
00224 }
00225
00226 const RTT::PropertyBag* TcpReporting::getReport()
00227 {
00228 makeReport2();
00229 return &report;
00230 }
00231
00232 bool TcpReporting::configureHook(){
00233 port=port_prop.value();
00234 return true;
00235 }
00236
00237 bool TcpReporting::startHook()
00238 {
00239 RTT::Logger::In in("TcpReporting::startup");
00240 fbody = new RTT::SocketMarshaller(this);
00241 this->addMarshaller( 0, fbody );
00242 ListenThread::createInstance( fbody, port );
00243 return ReportingComponent::startHook();
00244 }
00245
00246 void TcpReporting::stopHook()
00247 {
00248 _finishing = true;
00249 ListenThread::destroyInstance();
00250 fbody->shutdown();
00251 ReportingComponent::stopHook();
00252 this->removeMarshallers();
00253 }
00254 }