tcp.cpp
Go to the documentation of this file.
1 //
2 // Tcp.cpp
3 //
4 // TCP-Client.
5 //
6 
7 #include "sick_scan/tcp/tcp.hpp"
11 #include <stdio.h> // for sprintf()
12 
13 #ifdef _MSC_VER
14 #include <WinSock2.h>
15 #else
16 #include <sys/socket.h> // for socket(), bind(), and connect()
17 #include <arpa/inet.h> // for sockaddr_in and inet_ntoa()
18 #endif
19 #include <string.h> // for memset()
20 #include <netdb.h> // for hostent
21 #include <iostream> // for cout
22 #ifndef _MSC_VER
23 #include <sys/poll.h>
24 #include <poll.h>
25 #endif
26 
28 {
29  m_beVerbose = false;
30  m_connectionSocket = -1;
31 
32  m_readThread = 0; // m_readThread.m_threadShouldRun = false;
33 
39 
40  m_last_tcp_msg_received_nsec = 0; // no message received
41 }
42 
43 //
44 // Destruktor.
45 //
46 Tcp::~Tcp(void)
47 {
48  close();
49 }
50 
51 
52 //
53 // Schreibe eine Anzahl Bytes auf die Schnittstelle.
54 //
55 // Dieser Aufruf wartet, bis alle Bytes geschrieben wurden.
56 //
57 bool Tcp::write(UINT8* buffer, UINT32 numberOfBytes)
58 {
59  // Ist die Verbindung offen?
60  if (isOpen() == false)
61  {
62  ROS_ERROR("Tcp::write: Connection is not open");
63  return false;
64  }
65  INT32 bytesSent;
66  bool result;
67 #ifdef _MSC_VER
68  SOCKET* socketPtr = &m_connectionSocket;
69  bytesSent = ::send(*socketPtr, (const char*)buffer, numberOfBytes, 0);
70 #else
71  INT32* socketPtr = &m_connectionSocket;
72  bytesSent = ::send(*socketPtr, buffer, numberOfBytes, 0);
73 #endif
74  // Sende Daten an das Socket
75  if (bytesSent != (INT32)numberOfBytes)
76  {
77  printWarning("Tcp::write: Failed to send data to socket.");
78  result = false;
79  }
80  else
81  {
82  // Erfolg
83  printInfoMessage("Tcp::write: Sent " + toString(numberOfBytes) + " bytes to client.", m_beVerbose);
84  result = true;
85  }
86 
87  return result;
88 }
89 
90 
91 //
92 // Setzt die Funktion, die bei einem Disconnect-Ereignis aufgerufen wird.
93 //
94 void Tcp::setDisconnectCallbackFunction(DisconnectFunction discFunction, void* obj)
95 {
96  m_disconnectFunction = discFunction;
98 }
99 
100 
101 
108 {
109  if (m_connectionSocket >= 0)
110  {
111 // printInfoMessage("Tcp::isOpen: Reporting open connection.", m_beVerbose);
112  return true;
113  }
114 
115 // printInfoMessage("Tcp::isOpen: Reporting no connection.", m_beVerbose);
116  return false;
117 }
118 
119 //
120 // Definiere die Lese-Callback-Funktion.
121 //
122 void Tcp::setReadCallbackFunction(Tcp::ReadFunction readFunction, void* obj)
123 {
124  m_readFunction = readFunction;
125  m_readFunctionObjPtr = obj;
126 }
127 
128 //
129 // Alternative open-Funktion.
130 //
131 bool Tcp::open(UINT32 ipAddress, UINT16 port, bool enableVerboseDebugOutput)
132 {
133  std::string ipAdrStr;
134 
135  ipAdrStr = ipAdrToString(ipAddress);
136 
137  bool result = open(ipAdrStr, port, enableVerboseDebugOutput);
138 
139  return result;
140 }
141 
142 
143 //
144 // Oeffnet die Verbindung.
145 //
146 // -- Wir sind der Client, und wollen uns z.B. mit einem Scanner verbinden --
147 //
148 bool Tcp::open(std::string ipAddress, UINT16 port, bool enableVerboseDebugOutput)
149 {
150  INT32 result;
151  m_beVerbose = enableVerboseDebugOutput;
152  m_last_tcp_msg_received_nsec = 0; // no message received
153 // printInfoMessage("Tcp::open: Setting up input buffer with size=" + convertValueToString(requiredInputBufferSize) + " bytes.", m_beVerbose);
154 // m_inBuffer.init(requiredInputBufferSize, m_beVerbose);
155 
156  printInfoMessage("Tcp::open: Opening connection.", m_beVerbose);
157  wsa_init();
158 
159  // Socket erzeugen
160  m_connectionSocket = -1; // Keine Verbindung
161  {
162  ScopedLock lock(&m_socketMutex); // Mutex setzen
163  m_connectionSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
164  }
165  if (m_connectionSocket < 0)
166  {
167  ROS_ERROR("Tcp::open: socket() failed, aborting.");
168  return false;
169  }
170 
171  // Socket ist da. Nun die Verbindung oeffnen.
172  ROS_INFO_STREAM("sick_scan_xd: Tcp::open: connecting to " << ipAddress << ":" << port << " ...");
173  printInfoMessage("Tcp::open: Connecting. Target address is " + ipAddress + ":" + toString(port) + ".", m_beVerbose);
174 
175  struct sockaddr_in addr;
176  struct hostent *server = 0;
177  server = gethostbyname(ipAddress.c_str());
178  memset(&addr, 0, sizeof(addr)); // Zero out structure
179  addr.sin_family = AF_INET;
180  if (server != 0 && server->h_addr != 0)
181  {
182 #ifdef _MSC_VER
183  memcpy((char*)&addr.sin_addr.s_addr, (char*)server->h_addr, server->h_length);
184 #else
185  bcopy((char*)server->h_addr, (char*)&addr.sin_addr.s_addr, server->h_length);
186 #endif
187  }
188  else
189  {
190  addr.sin_addr.s_addr = inet_addr(ipAddress.c_str());
191  }
192  addr.sin_port = htons(port); // Host-2-Network byte order
193 #ifdef _MSC_VER
194  result = connect(m_connectionSocket, (SOCKADDR*)(&addr), sizeof(addr));
195 #else
196  result = connect(m_connectionSocket, (sockaddr*)(&addr), sizeof(addr));
197 #endif
198  if (result < 0)
199  {
200  // Verbindungsversuch ist fehlgeschlagen
201  std::string text = "Tcp::open: Failed to open TCP connection to " + ipAddress + ":" + toString(port) + ", aborting.";
202 #ifdef _MSC_VER
203  char msgbuf[256] = "";
204  int err = WSAGetLastError();
205  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), msgbuf, sizeof(msgbuf), NULL);
206  text = text + " Connect error " + toString(WSAGetLastError()) + std::string(msgbuf);
207 #endif
208  ROS_ERROR_STREAM("" << text);
209  close(); // close socket
210  return false;
211  }
212 
213  printInfoMessage("Tcp::open: Connection established. Now starting read thread.", m_beVerbose);
214 
215  // Empfangsthread starten
217  m_readThread->run(this);
218 
219  ROS_INFO_STREAM("sick_scan_xd Tcp::open: connected to " << ipAddress << ":" << port);
220  printInfoMessage("Tcp::open: Done, leaving now.", m_beVerbose);
221 
222  return true;
223 }
224 
225 
226 //
227 // Lese-Thread (Hauptfunktion).
228 //
229 void Tcp::readThreadFunction(bool& endThread, UINT16& waitTimeMs)
230 {
231  INT32 result;
232 
233  // Lesen
234  result = readInputData();
235 
236  // Ergebnis?
237  if (result < 0)
238  {
239  // Verbindung wurde abgebrochen
241  {
242  // Wir sollten eigentlich noch laufen!
243  printInfoMessage("Tcp::readThreadMain: Connection is lost! Read thread terminates now.", m_beVerbose);
244  endThread = true; // interrupt thread
245  }
246  waitTimeMs = 0;
247  }
248  else if (result == 0)
249  {
250  // Wir haben nichts empfangen. Schlafen und dann weiter...
251  waitTimeMs = 1;
252  }
253  else
254  {
255  // Wir haben etwas empfangen, also nicht schlafen
256  waitTimeMs = 0;
257  }
258 }
259 
260 //
261 // Read some data from the TCP connection.
262 //
264 {
265  // Prepare the input buffer
266  const UINT16 max_length = 8192;
267  UINT8 inBuffer[max_length];
268  INT32 recvMsgSize = 0;
269 
270  // Ist die Verbindung offen?
271  if (isOpen() == false)
272  {
273  if (rosOk())
274  ROS_ERROR("Tcp::readInputData: Connection is not open, aborting!");
275  else
276  ROS_INFO("Tcp::readInputData: Connection is not open, aborting");
277  return -1;
278  }
279 
280  // Read some data, if any
281 #ifdef _MSC_VER
282  recvMsgSize = recv(m_connectionSocket, (char *)inBuffer, max_length, 0);
283 #else
284  {
285  int ret = -1;
286  do {
287  struct pollfd fd;
288 
289  fd.fd = m_connectionSocket; // your socket handler
290  fd.events = POLLIN;
291  ret = poll(&fd, 1, 1000); // 1 second for timeout
292  switch (ret) {
293  case -1:
294  // Error
295  break;
296  case 0:
297  // Timeout
298  break;
299  default:
300  recvMsgSize = recv(m_connectionSocket, inBuffer, max_length, 0);
301  break;
302  }
303  if (!m_readThread || m_readThread->m_threadShouldRun == false)
304  {
305  recvMsgSize = 0;
306  break;
307  }
308  } while (ret == 0);
309  }
310 #endif
311  if (recvMsgSize < 0)
312  {
313  // Fehler
314  if (rosOk())
315  ROS_ERROR("Tcp::readInputData: Failed to read data from socket, aborting!");
316  else
317  ROS_INFO("Tcp::readInputData: Failed to read data from socket, aborting!");
318  ScopedLock lock(&m_socketMutex);
319  closeSocket(); // otherwise the driver can terminate with broken pipe in next call to Tcp::write()
320  }
321  else if (recvMsgSize > 0)
322  {
323  // Erfolg
324  printInfoMessage("Tcp::readInputData: Read " + toString(recvMsgSize) + " bytes from the connection.", m_beVerbose);
325 
326  // Falls eine Callback-Funktion definiert ist, rufe sie auf mit den
327  // empfangenen Daten.
328  if (m_readFunction != NULL)
329  {
330  // Die Daten an die Callback-Funktion uebergeben
331  UINT32 length_uint32 = (UINT32)recvMsgSize;
332  m_readFunction(m_readFunctionObjPtr, inBuffer, length_uint32);
333  }
334  else
335  {
336  // Es ist keine Callback-Funktion definiert, also die Daten im
337  // lokalen Puffer speichern.
338  for (INT32 i = 0; i < recvMsgSize; i++)
339  {
340  m_rxBuffer.push_back(inBuffer[i]);
341  }
342  }
343  m_last_tcp_msg_received_nsec = rosNanosecTimestampNow(); // timestamp in nanoseconds of the last received tcp message (or 0 if no message received)
344 
345  }
346  else if (recvMsgSize == 0)
347  {
348  // Verbindungsabbruch
349  if (rosOk())
350  ROS_ERROR("Tcp::readInputData: Read 0 bytes, connection is lost!");
351  else
352  ROS_INFO("Tcp::readInputData: Read 0 bytes, connection is lost");
353 
354  // Informieren?
355  if (m_disconnectFunction != NULL)
356  {
358  }
359 
360  // Mutex setzen
361  ScopedLock lock(&m_socketMutex);
362  closeSocket(); // otherwise the driver can terminate with broken pipe in next call to Tcp::write()
363  // m_connectionSocket = -1; // Keine Verbindung mehr
364  }
365 
366  return recvMsgSize;
367 }
368 
369 
370 //
371 // Close an open connection, if any, and stops the read thread (if running)
372 //
374 {
375  printInfoMessage("Tcp::close: Closing Tcp connection.", m_beVerbose);
376 
377  // Dem Lese-Thread ein Ende signalisieren
378  if(m_readThread)
380  // Close TCP socket
381  if (isOpen() == true)
382  {
383  closeSocket();
384  }
385  else
386  {
387  printInfoMessage("Tcp::close: Nothing to do - no open connection? Aborting.", m_beVerbose);
388  }
389  // Thread stoppen
390  if(m_readThread)
391  stopReadThread();
392  m_last_tcp_msg_received_nsec = 0; // no message received
393 
394  printInfoMessage("Tcp::close: Done - Connection is now closed.", m_beVerbose);
395 }
396 
401 {
402  // Close TCP socket
403  if (isOpen() == true)
404  {
405  // Verbindung schliessen
406 #ifdef _MSC_VER
408  closesocket(m_connectionSocket); // waere evtl. auch fuer Linux korrekt
409 #else
410  ::shutdown(m_connectionSocket, SHUT_RDWR);
412 #endif
413  m_connectionSocket = -1; // Keine Verbindung mehr
414  }
415 }
416 
421 {
422  if(m_readThread)
423  {
424  printInfoMessage("Tcp::stopReadThread: Stopping thread.", m_beVerbose);
425 
427  m_readThread->join();
428  delete m_readThread;
429  m_readThread = 0;
430  printInfoMessage("Tcp::stopReadThread: Done - Read thread is now closed.", m_beVerbose);
431  }
432 }
433 
434 
435 
442 {
443  return (UINT32)m_rxBuffer.size();
444 }
445 
446 
447 //
448 // Read function.
449 //
450 // 0..bufferLen bytes are returned.
451 // Return value is the number of returned bytes.
452 //
453 // DEPRECATED. Use the callback mechanism instead!
454 //
455 UINT32 Tcp::read(UINT8* buffer, UINT32 bufferLen)
456 {
457  UINT32 bytesRead = 0;
458 
459  // Lesen
460  while ((getNumReadableBytes() > 0) && (bufferLen > bytesRead))
461  {
462  buffer[bytesRead] = m_rxBuffer.front();
463  m_rxBuffer.pop_front();
464  bytesRead += 1; // m_inBuffer.read(buffer, bufferLen);
465  }
466 
467  return bytesRead;
468 }
469 
470 
476 std::string Tcp::readString(UINT8 delimiter)
477 {
478  UINT8 c = delimiter;
479  std::string outString;
480  const UINT16 maxStringLength = 8192;
481 
482  // String fuellen
483  while (m_rxBuffer.size() > 0)
484  {
485  // Es sind noch Daten im Puffer
486  c = m_rxBuffer.front();
487  m_rxBuffer.pop_front();
488  if (c == delimiter)
489  {
490  // Trennzeichen gefunden - wir sind fertig!
491  outString = m_rxString;
492  m_rxString.clear();
493  break;
494  }
495  m_rxString += c;
496  }
497 
498  // Ueberlauf der Ausgabe?
499  if (m_rxString.length() > maxStringLength)
500  {
501  if (m_longStringWarningPrinted == false)
502  {
503  // Die lange Version
504  printWarning("Receive-String has excessive length (" + toString(m_rxString.length()) +" bytes). Clearing string. On serial devices, incorrect bitrate settings may cause this behaviour.");
506  }
507  else
508  {
509  // Die Kurzfassung
510  printWarning("Receive-String has excessive length (" + toString(m_rxString.length()) +" bytes). Clearing string.");
511  }
512  m_rxString.clear();
513  }
514 
515  // Textmeldung
516  if ((m_beVerbose == true) && (outString.length() > 0))
517  {
518  printInfoMessage("Tcp::readString: Returning string: " + outString, true);
519  }
520 
521  return outString;
522 }
523 
524 
UINT16
uint16_t UINT16
Definition: BasicDatatypes.hpp:73
UINT8
uint8_t UINT8
Definition: BasicDatatypes.hpp:75
Tcp::isOpen
bool isOpen()
Definition: tcp.cpp:107
SOCKET
int SOCKET
Definition: udp_sockets.h:81
NULL
#define NULL
Tcp::m_last_tcp_msg_received_nsec
uint64_t m_last_tcp_msg_received_nsec
Definition: tcp.hpp:91
errorhandler.hpp
ScopedLock
Definition: Mutex.hpp:39
SickThread::join
void join()
Definition: SickThread.hpp:112
Tcp::m_rxBuffer
std::list< unsigned char > m_rxBuffer
Definition: tcp.hpp:68
Tcp::getNumReadableBytes
UINT32 getNumReadableBytes()
Definition: tcp.cpp:441
Tcp::m_disconnectFunctionObjPtr
void * m_disconnectFunctionObjPtr
Definition: tcp.hpp:89
roswrap::console::shutdown
ROSCONSOLE_DECL void shutdown()
Definition: rossimu.cpp:269
Tcp::m_rxString
std::string m_rxString
Definition: tcp.hpp:66
Tcp::stopReadThread
void stopReadThread()
Definition: tcp.cpp:420
Tcp::ReadFunction
void(* ReadFunction)(void *obj, UINT8 *inputBuffer, UINT32 &numBytes)
Definition: tcp.hpp:55
Tcp::~Tcp
~Tcp()
Definition: tcp.cpp:46
toString
std::string toString(INT32 value)
Definition: toolbox.cpp:279
INT32
int32_t INT32
Definition: BasicDatatypes.hpp:71
printInfoMessage
#define printInfoMessage(a, b)
Definition: errorhandler.hpp:14
printWarning
void printWarning(std::string message)
Definition: errorhandler.cpp:80
Tcp::write
bool write(UINT8 *buffer, UINT32 numberOfBytes)
Definition: tcp.cpp:57
Tcp::setDisconnectCallbackFunction
void setDisconnectCallbackFunction(DisconnectFunction discFunction, void *obj)
Definition: tcp.cpp:94
SickThread< Tcp, &Tcp::readThreadFunction >
ROS_INFO_STREAM
#define ROS_INFO_STREAM(...)
Definition: sick_scan_ros2_example.cpp:71
Tcp::m_readFunctionObjPtr
void * m_readFunctionObjPtr
Definition: tcp.hpp:87
wsa_init
void wsa_init(void)
Definition: wsa_init.cpp:36
toolbox.hpp
ThreadWrapperBase::run
void run(void *classptr)
Definition: SickThread.hpp:34
Tcp::readString
std::string readString(UINT8 delimiter)
Definition: tcp.cpp:476
Tcp::m_longStringWarningPrinted
bool m_longStringWarningPrinted
Definition: tcp.hpp:65
netdb.h
Tcp::m_beVerbose
bool m_beVerbose
Definition: tcp.hpp:75
Tcp::readInputData
INT32 readInputData()
Definition: tcp.cpp:263
ROS_INFO
#define ROS_INFO(...)
Definition: sick_scan_logging.h:117
Tcp::setReadCallbackFunction
void setReadCallbackFunction(ReadFunction readFunction, void *obj)
Definition: tcp.cpp:122
Tcp::m_readFunction
ReadFunction m_readFunction
Definition: tcp.hpp:86
SD_BOTH
#define SD_BOTH
Definition: server_socket.cpp:66
tcp.hpp
ROS_ERROR
#define ROS_ERROR(...)
Definition: sick_scan_logging.h:127
sick_scan_xd_api_test.c
c
Definition: sick_scan_xd_api_test.py:445
closesocket
#define closesocket
Definition: udp_sockets.h:85
wsa_init.hpp
ipAdrToString
std::string ipAdrToString(UINT32 ipAddress)
Definition: toolbox.cpp:432
Tcp::read
UINT32 read(UINT8 *buffer, UINT32 bufferLen)
Definition: tcp.cpp:455
Tcp::m_connectionSocket
INT32 m_connectionSocket
Definition: tcp.hpp:78
SickThread::m_threadShouldRun
bool m_threadShouldRun
Definition: SickThread.hpp:119
rosNanosecTimestampNow
uint64_t rosNanosecTimestampNow(void)
Definition: sick_ros_wrapper.h:178
ROS_ERROR_STREAM
#define ROS_ERROR_STREAM(...)
Definition: sick_scan_ros2_example.cpp:72
UINT32
uint32_t UINT32
Definition: BasicDatatypes.hpp:72
Tcp::close
void close()
Definition: tcp.cpp:373
Tcp::m_socketMutex
Mutex m_socketMutex
Definition: tcp.hpp:76
Tcp::readThreadFunction
void readThreadFunction(bool &endThread, UINT16 &waitTimeMs)
Definition: tcp.cpp:229
Tcp::m_disconnectFunction
DisconnectFunction m_disconnectFunction
Definition: tcp.hpp:88
rosOk
bool rosOk(void)
Definition: sick_ros_wrapper.h:206
Tcp::Tcp
Tcp()
Definition: tcp.cpp:27
Tcp::closeSocket
void closeSocket()
Definition: tcp.cpp:400
test_server.server
server
Definition: test_server.py:219
SOCKADDR
struct sockaddr SOCKADDR
Definition: udp_sockets.h:82
Tcp::m_readThread
SickThread< Tcp, &Tcp::readThreadFunction > * m_readThread
Definition: tcp.hpp:83
Tcp::open
bool open(std::string ipAddress, UINT16 port, bool enableVerboseDebugOutput=false)
Definition: tcp.cpp:148


sick_scan_xd
Author(s): Michael Lehning , Jochen Sprickerhof , Martin Günther
autogenerated on Fri Oct 25 2024 02:47:12