tcp.cpp
Go to the documentation of this file.
1 //
2 // Tcp.cpp
3 //
4 // TCP-Client.
5 //
6 
7 #include "tcp.hpp"
8 #include "../tools/errorhandler.hpp"
9 #include "../tools/toolbox.hpp"
10 #include <stdio.h> // for sprintf()
11 
12 #include <sys/socket.h> // for socket(), bind(), and connect()
13 #include <arpa/inet.h> // for sockaddr_in and inet_ntoa()
14 #include <string.h> // for memset()
15 #include <netdb.h> // for hostent
16 
17 
19 {
20  m_beVerbose = false;
21  m_connectionSocket = -1;
22 
24 
26  m_disconnectFunction = NULL;
28  m_readFunction = NULL;
29  m_readFunctionObjPtr = NULL;
30 
31 }
32 
33 //
34 // Destruktor.
35 //
36 Tcp::~Tcp(void)
37 {
38  close();
39 }
40 
41 
42 //
43 // Schreibe eine Anzahl Bytes auf die Schnittstelle.
44 //
45 // Dieser Aufruf wartet, bis alle Bytes geschrieben wurden.
46 //
47 bool Tcp::write(UINT8* buffer, UINT32 numberOfBytes)
48 {
49  INT32 bytesSent;
50  bool result;
51  INT32* socketPtr = &m_connectionSocket;
52 
53  // Sende Daten an das Socket
54  bytesSent = ::send(*socketPtr, buffer, numberOfBytes, 0);
55 
56  if (bytesSent != (INT32)numberOfBytes)
57  {
58  printWarning("Tcp::write: Failed to send data to socket.");
59  result = false;
60  }
61  else
62  {
63  // Erfolg
64  printInfoMessage("Tcp::write: Sent " + toString(numberOfBytes) + " bytes to client.", m_beVerbose);
65  result = true;
66  }
67 
68  return result;
69 }
70 
71 
72 //
73 // Setzt die Funktion, die bei einem Disconnect-Ereignis aufgerufen wird.
74 //
76 {
77  m_disconnectFunction = discFunction;
79 }
80 
81 
82 
89 {
90  if (m_connectionSocket >= 0)
91  {
92 // printInfoMessage("Tcp::isOpen: Reporting open connection.", m_beVerbose);
93  return true;
94  }
95 
96 // printInfoMessage("Tcp::isOpen: Reporting no connection.", m_beVerbose);
97  return false;
98 }
99 
100 //
101 // Definiere die Lese-Callback-Funktion.
102 //
103 void Tcp::setReadCallbackFunction(Tcp::ReadFunction readFunction, void* obj)
104 {
105  m_readFunction = readFunction;
106  m_readFunctionObjPtr = obj;
107 }
108 
109 //
110 // Alternative open-Funktion.
111 //
112 bool Tcp::open(UINT32 ipAddress, UINT16 port, bool enableVerboseDebugOutput)
113 {
114  std::string ipAdrStr;
115 
116  ipAdrStr = ipAdrToString(ipAddress);
117 
118  bool result = open(ipAdrStr, port, enableVerboseDebugOutput);
119 
120  return result;
121 }
122 
123 
124 //
125 // Oeffnet die Verbindung.
126 //
127 // -- Wir sind der Client, und wollen uns z.B. mit einem Scanner verbinden --
128 //
129 bool Tcp::open(std::string ipAddress, UINT16 port, bool enableVerboseDebugOutput)
130 {
131  INT32 result;
132  m_beVerbose = enableVerboseDebugOutput;
133 
134 // printInfoMessage("Tcp::open: Setting up input buffer with size=" + convertValueToString(requiredInputBufferSize) + " bytes.", m_beVerbose);
135 // m_inBuffer.init(requiredInputBufferSize, m_beVerbose);
136 
137  printInfoMessage("Tcp::open: Opening connection.", m_beVerbose);
138 
139  // Socket erzeugen
140  m_connectionSocket = -1; // Keine Verbindung
141  {
142  ScopedLock lock(&m_socketMutex); // Mutex setzen
143  m_connectionSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
144  }
145  if (m_connectionSocket < 0)
146  {
147  printError("Tcp::open: socket() failed, aborting.");
148  return false;
149  }
150 
151  // Socket ist da. Nun die Verbindung oeffnen.
152  printInfoMessage("Tcp::open: Connecting. Target address is " + ipAddress + ":" + toString(port) + ".", m_beVerbose);
153 
154  struct sockaddr_in addr;
155  struct hostent *server;
156  server = gethostbyname(ipAddress.c_str());
157  memset(&addr, 0, sizeof(addr)); // Zero out structure
158  addr.sin_family = AF_INET;
159  bcopy((char *)server->h_addr, (char *)&addr.sin_addr.s_addr, server->h_length);
160  addr.sin_port = htons(port); // Host-2-Network byte order
161  result = connect(m_connectionSocket, (sockaddr*)(&addr), sizeof(addr));
162  if (result < 0)
163  {
164  // Verbindungsversuch ist fehlgeschlagen
165  std::string text = "Tcp::open: Failed to open TCP connection to " + ipAddress + ", aborting.";
166  printError(text);
167  return false;
168  }
169 
170  printInfoMessage("Tcp::open: Connection established. Now starting read thread.", m_beVerbose);
171 
172  // Empfangsthread starten
173  m_readThread.run(this);
174 
175  printInfoMessage("Tcp::open: Done, leaving now.", m_beVerbose);
176 
177  return true;
178 }
179 
180 
181 //
182 // Lese-Thread (Hauptfunktion).
183 //
184 void Tcp::readThreadFunction(bool& endThread, UINT16& waitTimeMs)
185 {
186  INT32 result;
187 
188  // Lesen
189  result = readInputData();
190 
191  // Ergebnis?
192  if (result < 0)
193  {
194  // Verbindung wurde abgebrochen
195  if (m_readThread.m_threadShouldRun == true)
196  {
197  // Wir sollten eigentlich noch laufen!
198  printInfoMessage("Tcp::readThreadMain: Connection is lost! Read thread terminates now.", m_beVerbose);
199  }
200  waitTimeMs = 0;
201  }
202  else if (result == 0)
203  {
204  // Wir haben nichts empfangen. Schlafen und dann weiter...
205  waitTimeMs = 1;
206  }
207  else
208  {
209  // Wir haben etwas empfangen, also nicht schlafen
210  waitTimeMs = 0;
211  }
212 }
213 
214 //
215 // Read some data from the TCP connection.
216 //
218 {
219  // Prepare the input buffer
220  const UINT16 max_length = 8192;
221  UINT8 inBuffer[max_length];
222  INT32 recvMsgSize = 0;
223 
224  // Ist die Verbindung offen?
225  if (isOpen() == false)
226  {
227  printError("Tcp::readInputData: Connection is not open, aborting!");
228  return -1;
229  }
230 
231  // Read some data, if any
232  recvMsgSize = recv(m_connectionSocket, inBuffer, max_length, 0);
233  if (recvMsgSize < 0)
234  {
235  // Fehler
236  printError("Tcp::readInputData: Failed to read data from socket, aborting!");
237  }
238  else if (recvMsgSize > 0)
239  {
240  // Erfolg
241  printInfoMessage("Tcp::readInputData: Read " + toString(recvMsgSize) + " bytes from the connection.", m_beVerbose);
242 
243  // Falls eine Callback-Funktion definiert ist, rufe sie auf mit den
244  // empfangenen Daten.
245  if (m_readFunction != NULL)
246  {
247  // Die Daten an die Callback-Funktion uebergeben
248  UINT32 length_uint32 = (UINT32)recvMsgSize;
249  m_readFunction(m_readFunctionObjPtr, inBuffer, length_uint32);
250  }
251  else
252  {
253  // Es ist keine Callback-Funktion definiert, also die Daten im
254  // lokalen Puffer speichern.
255  for (INT32 i = 0; i < recvMsgSize; i++)
256  {
257  m_rxBuffer.push_back(inBuffer[i]);
258  }
259  }
260  }
261  else if (recvMsgSize == 0)
262  {
263  // Verbindungsabbruch
264  printInfoMessage("Tcp::readInputData: Read 0 bytes - connection is lost!", true);
265 
266  // Informieren?
267  if (m_disconnectFunction != NULL)
268  {
270  }
271 
272  // Mutex setzen
273  ScopedLock lock(&m_socketMutex);
274 
275  m_connectionSocket = -1; // Keine Verbindung mehr
276  }
277 
278  return recvMsgSize;
279 }
280 
281 
282 //
283 // Close an open connection, if any.
284 //
286 {
287  printInfoMessage("Tcp::close: Closing Tcp connection.", m_beVerbose);
288 
289  if (isOpen() == true)
290  {
291  // Dem Lese-Thread ein Ende signalisieren
293 
294  // Verbindung schliessen
296 
297  // Auf das Ende des Empfangsthreads warten
298  printInfoMessage("Tcp::close: Waiting for the server thread to terminate...", m_beVerbose);
299 
300  // Thread stoppen
301  stopReadThread();
302  }
303  else
304  {
305  printInfoMessage("Tcp::close: Nothing to do - no open connection? Aborting.", m_beVerbose);
306  }
307 
308  printInfoMessage("Tcp::close: Done - Connection is now closed.", m_beVerbose);
309 }
310 
311 
316 {
317  printInfoMessage("Tcp::stopReadThread: Stopping thread.", m_beVerbose);
318 
319 // m_readThread.m_threadShouldRun = false;
320  m_readThread.join();
321 
322  printInfoMessage("Tcp::stopReadThread: Done - Read thread is now closed.", m_beVerbose);
323 }
324 
325 
326 
333 {
334  return m_rxBuffer.size();
335 }
336 
337 
338 //
339 // Read function.
340 //
341 // 0..bufferLen bytes are returned.
342 // Return value is the number of returned bytes.
343 //
344 // DEPRECATED. Use the callback mechanism instead!
345 //
346 UINT32 Tcp::read(UINT8* buffer, UINT32 bufferLen)
347 {
348  UINT32 bytesRead = 0;
349 
350  // Lesen
351  while ((getNumReadableBytes() > 0) && (bufferLen > bytesRead))
352  {
353  buffer[bytesRead] = m_rxBuffer.front();
354  m_rxBuffer.pop_front();
355  bytesRead += 1; // m_inBuffer.read(buffer, bufferLen);
356  }
357 
358  return bytesRead;
359 }
360 
361 
367 std::string Tcp::readString(UINT8 delimiter)
368 {
369  UINT8 c = delimiter;
370  std::string outString;
371  const UINT16 maxStringLength = 8192;
372 
373  // String fuellen
374  while (m_rxBuffer.size() > 0)
375  {
376  // Es sind noch Daten im Puffer
377  c = m_rxBuffer.front();
378  m_rxBuffer.pop_front();
379  if (c == delimiter)
380  {
381  // Trennzeichen gefunden - wir sind fertig!
382  outString = m_rxString;
383  m_rxString.clear();
384  break;
385  }
386  m_rxString += c;
387  }
388 
389  // Ueberlauf der Ausgabe?
390  if (m_rxString.length() > maxStringLength)
391  {
392  if (m_longStringWarningPrinted == false)
393  {
394  // Die lange Version
395  printWarning("Receive-String has excessive length (" + toString(m_rxString.length()) +" bytes). Clearing string. On serial devices, incorrect bitrate settings may cause this behaviour.");
397  }
398  else
399  {
400  // Die Kurzfassung
401  printWarning("Receive-String has excessive length (" + toString(m_rxString.length()) +" bytes). Clearing string.");
402  }
403  m_rxString.clear();
404  }
405 
406  // Textmeldung
407  if ((m_beVerbose == true) && (outString.length() > 0))
408  {
409  printInfoMessage("Tcp::readString: Returning string: " + outString, true);
410  }
411 
412  return outString;
413 }
414 
415 
UINT32 getNumReadableBytes()
Definition: tcp.cpp:332
void printError(std::string message)
std::string toString(const PositionWGS84::PositionWGS84SourceType &type)
bool m_longStringWarningPrinted
Definition: tcp.hpp:58
uint16_t UINT16
void(* DisconnectFunction)(void *obj)
Definition: tcp.hpp:53
#define printInfoMessage(a, b)
uint32_t UINT32
void * m_disconnectFunctionObjPtr
Definition: tcp.hpp:79
bool write(UINT8 *buffer, UINT32 numberOfBytes)
Definition: tcp.cpp:47
SickThread< Tcp,&Tcp::readThreadFunction > m_readThread
Definition: tcp.hpp:73
bool m_beVerbose
Definition: tcp.hpp:67
std::string m_rxString
Definition: tcp.hpp:59
std::list< unsigned char > m_rxBuffer
Definition: tcp.hpp:61
bool m_threadShouldRun
Definition: SickThread.hpp:106
void run(void *classptr)
Definition: SickThread.hpp:26
void readThreadFunction(bool &endThread, UINT16 &waitTimeMs)
Definition: tcp.cpp:184
bool open(std::string ipAddress, UINT16 port, bool enableVerboseDebugOutput=false)
Definition: tcp.cpp:129
void * m_readFunctionObjPtr
Definition: tcp.hpp:77
ReadFunction m_readFunction
Definition: tcp.hpp:76
std::string ipAdrToString(UINT32 ipAddress)
Definition: toolbox.cpp:424
void(* ReadFunction)(void *obj, UINT8 *inputBuffer, UINT32 &numBytes)
Definition: tcp.hpp:49
INT32 readInputData()
Definition: tcp.cpp:217
DisconnectFunction m_disconnectFunction
Definition: tcp.hpp:78
std::string readString(UINT8 delimiter)
Definition: tcp.cpp:367
int32_t INT32
Mutex m_socketMutex
Definition: tcp.hpp:68
~Tcp()
Definition: tcp.cpp:36
bool isOpen()
Definition: tcp.cpp:88
Tcp()
Definition: tcp.cpp:18
void join()
Definition: SickThread.hpp:99
UINT32 read(UINT8 *buffer, UINT32 bufferLen)
Definition: tcp.cpp:346
void setReadCallbackFunction(ReadFunction readFunction, void *obj)
Definition: tcp.cpp:103
void setDisconnectCallbackFunction(DisconnectFunction discFunction, void *obj)
Definition: tcp.cpp:75
void close()
Definition: tcp.cpp:285
INT32 m_connectionSocket
Definition: tcp.hpp:70
void printWarning(std::string message)
void stopReadThread()
Definition: tcp.cpp:315
uint8_t UINT8


libsick_ldmrs
Author(s): SICK AG , Martin Günther , Jochen Sprickerhof
autogenerated on Sat Jun 8 2019 17:57:33