LTKCPP-- LLRP Toolkit C Plus Plus Library
ltkcpp_connection.cpp
Go to the documentation of this file.
1 
2 /*
3  *****************************************************************************
4  * *
5  * IMPINJ CONFIDENTIAL AND PROPRIETARY *
6  * *
7  * This source code is the sole property of Impinj, Inc. Reproduction or *
8  * utilization of this source code in whole or in part is forbidden without *
9  * the prior written consent of Impinj, Inc. *
10  * *
11  * (c) Copyright Impinj, Inc. 2007,2008. All rights reserved. *
12  * *
13  *****************************************************************************/
14 
31 #include <assert.h>
32 
33 #ifdef _WIN32
34 #include <Ws2tcpip.h>
35 #define LLRPCLOSESOCKET(X) closesocket(X)
36 #else
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netdb.h>
41 #define LLRPCLOSESOCKET(X) close(X)
42 #endif
43 
44 #include <openssl/ssl.h>
45 
46 #include "ltkcpp_platform.h"
47 #include "ltkcpp_base.h"
48 #include "ltkcpp_frame.h"
49 #include "ltkcpp_connection.h"
50 
51 #define LLRP1_TCP_PORT "5084"
52 #define LLRP1_TLS_PORT "5085"
53 
54 // Windows defines INVALID_SOCKET the following way, and we must define it the same
55 // way on Linux:
56 #ifndef INVALID_SOCKET
57 #define INVALID_SOCKET (unsigned long)(~0)
58 #endif // INVALID_SOCKET
59 
60 // Windows defines SOCKET_ERROR the following way, and we must define it the same
61 // way on Linux:
62 #ifndef SOCKET_ERROR
63 #define SOCKET_ERROR (-1)
64 #endif
65 
66 namespace LLRP
67 {
68 
88  const CTypeRegistry * pTypeRegistry,
89  unsigned int nBufferSize)
90 {
91  initializeWinsock();
92  initializeOpenSSL();
93 
94  /*
95  * Apply default buffer size
96  */
97  if(0 == nBufferSize)
98  {
99  nBufferSize = 128u*1024u;
100  }
101 
102  /*
103  * Make sure the buffer size is sane. This is arbitrary.
104  * The smallest message is 10 bytes, but it ain't anything
105  * useful. 1024u covers a surprising number of messages.
106  */
107  if(1024u > nBufferSize || 1u*1024u*1024u < nBufferSize)
108  {
109  throw "Insane buffer size";
110  }
111 
112  /*
113  * Capture variables. A NULL m_pBio indicates there
114  * is no connection yet.
115  */
116  m_pBio = NULL;
117  m_pTypeRegistry = pTypeRegistry;
118  m_nBufferSize = nBufferSize;
119 
120  memset(&m_Recv, 0, sizeof m_Recv);
121  memset(&m_Send, 0, sizeof m_Send);
122 
123  /*
124  * Allocate and check each the recv and send buffers.
125  */
126  m_Recv.pBuffer = new llrp_byte_t[nBufferSize];
127  m_Send.pBuffer = new llrp_byte_t[nBufferSize];
128 
129  /*
130  * Zero-fill buffers just so debugger printing is tidy
131  */
132  memset(m_Recv.pBuffer, 0, nBufferSize);
133  memset(m_Send.pBuffer, 0, nBufferSize);
134 }
135 
136 
145 {
146  /*
147  * Close the connection, if one
148  */
150 
151  /*
152  * Destruct any messages on the input queue
153  */
154  for (
155  std::list<CMessage *>::iterator msg = m_listInputQueue.begin();
156  msg != m_listInputQueue.end();
157  msg++)
158  {
159  delete *msg;
160  }
161 
162  /*
163  * free each the receive and send bufers
164  */
165  delete[] m_Recv.pBuffer;
166  delete[] m_Send.pBuffer;
167 
168  shutdownWinsock();
169 }
170 
171 
183 int CConnection::openConnectionToReader(const char * pReaderHostName)
184 {
185  return openConnectionToReader(pReaderHostName, E_LLRP_CONNECTION_TYPE_UNSECURE);
186 }
187 
199 int CConnection::openSecureConnectionToReader(const char * pReaderHostName)
200 {
201  return openConnectionToReader(pReaderHostName, E_LLRP_CONNECTION_TYPE_SSL);
202 }
203 
216 int CConnection::openConnectionToReader(const char * pReaderHostName, E_LLRP_CONNECTION_TYPE eType)
217 {
218  int rc = -1;
219  unsigned long hSocket = INVALID_SOCKET;
220  BIO* pSocketBio = NULL;
221 
222  /*
223  * Clear the connect error string
224  */
225  m_pConnectErrorStr = NULL;
226 
227  /*
228  * Make sure there isn't already a connection.
229  */
230  if(NULL != m_pBio)
231  {
232  m_pConnectErrorStr = "already connected";
233  return -1;
234  }
235 
236  // Open a raw socket to the reader:
237  switch (eType)
238  {
239  case E_LLRP_CONNECTION_TYPE_SSL:
240  rc = openSocketConnection(pReaderHostName, LLRP1_TLS_PORT, &hSocket);
241  break;
242  case E_LLRP_CONNECTION_TYPE_UNSECURE:
243  rc = openSocketConnection(pReaderHostName, LLRP1_TCP_PORT, &hSocket);
244  break;
245  default:
246  m_pConnectErrorStr = "Unknown connection type.";
247  rc = -1;
248  break;
249  }
250 
251  if (rc != 0)
252  {
253  // log message should already be set to the appropriate error
254  // by openSocketConnection
255  return -1;
256  }
257 
258  // Wrap the socket in an OpenSSL 'BIO'
259  pSocketBio = BIO_new_socket(hSocket, BIO_CLOSE);
260  if (pSocketBio == NULL)
261  {
262  m_pConnectErrorStr = "Failed to register socket with OpenSSL.";
263  LLRPCLOSESOCKET(hSocket);
264 
265  return -1;
266  }
267 
268  // If we're performing a secured connection, we'll need to create an SSL
269  // 'BIO' and push that onto the BIO chain.
270  if (eType == E_LLRP_CONNECTION_TYPE_SSL)
271  {
272  BIO* pSslBio = NULL;
273  int rc = initializeSslBio(&pSslBio);
274  if (rc != 0)
275  {
276  BIO_free_all(pSocketBio);
277  return -1;
278  }
279 
280  BIO_push(pSslBio, pSocketBio);
281 
282  rc = BIO_do_handshake(pSslBio);
283  if (rc == 1)
284  {
285  this->m_pBio = pSslBio;
286  }
287  else
288  {
289  m_pConnectErrorStr = "Failed to perform TLS handshake";
290  BIO_free_all(pSslBio);
291  return -1;
292  }
293  }
294  else
295  {
296  this->m_pBio = pSocketBio;
297  }
298 
299  return 0;
300 }
301 
315 int CConnection::openSocketConnection(const char* pkzReaderHostName, const char* pkzPort, unsigned long* phSocket)
316 {
317  if (phSocket == NULL)
318  {
319  m_pConnectErrorStr = "Internal error.";
320  return -1;
321  }
322 
323  addrinfo* pAddrInfo = NULL;
324  int rc = getaddrinfo(pkzReaderHostName, pkzPort, NULL, &pAddrInfo);
325  if (rc != 0)
326  {
327  m_pConnectErrorStr = "Failed to resolve host.";
328  freeaddrinfo(pAddrInfo);
329  return -1;
330  }
331 
332  unsigned long hSocket = socket(pAddrInfo->ai_family, SOCK_STREAM, IPPROTO_TCP);
333  if (hSocket == INVALID_SOCKET)
334  {
335  m_pConnectErrorStr = "Failed to allocate a socket descriptor.";
336  freeaddrinfo(pAddrInfo);
337  return -1;
338  }
339 
340  rc = connect(hSocket, pAddrInfo->ai_addr, pAddrInfo->ai_addrlen);
341  if (rc == SOCKET_ERROR)
342  {
343  m_pConnectErrorStr = "Failed to connect to host.";
344  LLRPCLOSESOCKET(hSocket);
345  freeaddrinfo(pAddrInfo);
346  return -1;
347  }
348 
349  *phSocket = hSocket;
350  freeaddrinfo(pAddrInfo);
351 
352  return rc;
353 }
354 
366 int CConnection::initializeSslBio(BIO** ppBio)
367 {
368  BIO* pBio = NULL;
369  long sslOptions = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
370 
371  if (ppBio == NULL)
372  {
373  m_pConnectErrorStr = "Internal parameter failure";
374  return -1;
375  }
376 
377  SSL_CTX* pSslCtx = SSL_CTX_new(SSLv23_method());
378  if (pSslCtx == NULL)
379  {
380  m_pConnectErrorStr = "System SSL context failure";
381  return -1;
382  }
383 
384  SSL_CTX_set_verify(pSslCtx, SSL_VERIFY_NONE, NULL);
385  SSL_CTX_set_options(pSslCtx, sslOptions);
386 
387  pBio = BIO_new_ssl(pSslCtx, 1); // If "client" is non-zero, the SSL bio is initialized in client mode.
388  SSL_CTX_free(pSslCtx);
389  if (pBio == NULL)
390  {
391  m_pConnectErrorStr = "System SSL socket allocation failure";
392  return -1;
393  }
394 
395  *ppBio = pBio;
396  return 0;
397 }
398 
409 const char *
411 {
412  return m_pConnectErrorStr;
413 }
414 
415 
426 int
428 {
429  SSL* pSsl = NULL;
430  int rc = -1;
431 
432  if(NULL == m_pBio)
433  {
434  m_pConnectErrorStr = "not connected";
435  return -1;
436  }
437 
438  BIO_get_ssl(m_pBio, pSsl);
439  if (pSsl != NULL)
440  {
441  BIO_ssl_shutdown(m_pBio);
442  }
443 
444  BIO_free_all(m_pBio);
445  m_pBio = NULL;
446 
447  rc = shutdownWinsock();
448  return rc;
449 }
450 
451 
474 CMessage *
476  CMessage * pSendMessage,
477  int nMaxMS)
478 {
479  const CTypeDescriptor * pResponseType;
480  EResultCode lrc;
481  CMessage * pResponseMessage;
482 
483  /*
484  * Determine the response type. The type descriptor
485  * of the outgoing request message points to the
486  * type descriptor of the response. Since we are
487  * totally dependent upon it, fail if there
488  * is no response type pointer value.
489  */
490  pResponseType = pSendMessage->m_pType->m_pResponseType;
491  if(NULL == pResponseType)
492  {
493  CErrorDetails * pError = &m_Send.ErrorDetails;
494 
495  pError->clear();
497  "send message has no response type");
498  return NULL;
499  }
500 
501  /*
502  * Send the request
503  */
504  lrc = sendMessage(pSendMessage);
505  if(RC_OK != lrc)
506  {
507  return NULL;
508  }
509 
510  /*
511  * Receive the response subject to timeout
512  */
513  pResponseMessage = recvResponse(nMaxMS,
514  pResponseType, pSendMessage->getMessageID());
515 
516  /*
517  * Whatever recvResponse() returned is the result.
518  */
519  return pResponseMessage;
520 }
521 
522 
537 const CErrorDetails *
539 {
540  const CErrorDetails * pError;
541 
542  pError = getSendError();
543  if(RC_OK == pError->m_eResultCode)
544  {
545  pError = getRecvError();
546  }
547 
548  return pError;
549 }
550 
551 
569  CMessage * pMessage)
570 {
571  CErrorDetails * pError = &m_Send.ErrorDetails;
572  CFrameEncoder frameEncoder(m_Send.pBuffer, m_nBufferSize);
573 
574  /*
575  * Clear the error details in the send state.
576  */
577  pError->clear();
578 
579  /*
580  * Make sure the socket is open.
581  */
582  if(NULL == m_pBio)
583  {
584  pError->resultCodeAndWhatStr(RC_MiscError, "not connected");
585  return pError->m_eResultCode;
586  }
587 
588  /*
589  * Encode the message, then check the encoder's ErrorDetails for results.
590  */
591  frameEncoder.encodeElement(pMessage);
592 
593  /*
594  * Regardless of what happened capture the error details
595  * and the number of bytes placed in the buffer.
596  */
597  m_Send.ErrorDetails = frameEncoder.m_ErrorDetails;
598  m_Send.nBuffer = frameEncoder.getLength();
599 
600  /*
601  * If the encoding appears complete write the frame
602  * to the connection. NB: this is not ready for
603  * non-blocking I/O (EWOULDBLOCK).
604  */
605  if (RC_OK == pError->m_eResultCode)
606  {
607  int rc = BIO_write(m_pBio, m_Send.pBuffer, (m_Send.nBuffer * sizeof(llrp_byte_t)));
608  if(rc != (int)m_Send.nBuffer)
609  {
610  /* Yikes! */
611  pError->resultCodeAndWhatStr(RC_SendIOError, "send IO error");
612  }
613  }
614 
615  /*
616  * Done.
617  */
618  return pError->m_eResultCode;
619 }
620 
621 
631 const CErrorDetails *
633 {
634  return &m_Send.ErrorDetails;
635 }
636 
637 
658 CMessage *
660  int nMaxMS)
661 {
662  time_t timeLimit = calculateTimeLimit(nMaxMS);
663  EResultCode lrc;
664  CMessage * pMessage;
665 
666  /*
667  * Make sure the socket is open.
668  */
669  if(NULL == m_pBio)
670  {
671  CErrorDetails * pError = &m_Recv.ErrorDetails;
672 
673  pError->resultCodeAndWhatStr(RC_MiscError, "not connected");
674  return NULL;
675  }
676 
677  /*
678  * Loop until victory or some sort of exception happens
679  */
680  for(;;)
681  {
682  /*
683  * Check the input queue to see if there is already
684  * a message pending.
685  */
686  if(!m_listInputQueue.empty())
687  {
688  pMessage = m_listInputQueue.front();
689  m_listInputQueue.pop_front();
690  return pMessage;
691  }
692 
693  /*
694  * No message available. Advance the receiver state
695  * and see if a message is produced.
696  */
697  lrc = recvAdvance(nMaxMS, timeLimit);
698  if(lrc != RC_OK)
699  {
700  return NULL;
701  }
702  }
703 }
704 
705 
716 const CErrorDetails *
718 {
719  return &m_Recv.ErrorDetails;
720 }
721 
722 
769 CMessage *
771  int nMaxMS,
772  const CTypeDescriptor * pResponseType,
773  llrp_u32_t ResponseMessageID)
774 {
775  time_t timeLimit = calculateTimeLimit(nMaxMS);
776  const CTypeDescriptor * pErrorMsgType;
777  EResultCode lrc;
778  CMessage * pMessage;
779 
780  /*
781  * Make sure the socket is open.
782  */
783  if(NULL == m_pBio)
784  {
785  CErrorDetails * pError = &m_Recv.ErrorDetails;
786 
787  pError->resultCodeAndWhatStr(RC_MiscError, "not connected");
788  return NULL;
789  }
790 
791  /*
792  * Look up the ERROR_MESSAGE type descriptor now.
793  */
794  pErrorMsgType = m_pTypeRegistry->lookupMessage(100u);
795 
796  /*
797  * Loop until victory or some sort of exception happens
798  */
799  for(;;)
800  {
801  /*
802  * Check the input queue to see if the sought
803  * message is present.
804  */
805  for (
806  std::list<CMessage *>::iterator msg = m_listInputQueue.begin();
807  msg != m_listInputQueue.end();
808  msg++)
809  {
810  pMessage = *msg;
811 
812  /*
813  * Are we looking for a particular message type?
814  */
815  if(NULL != pResponseType)
816  {
817  /*
818  * See if it is the sought response type or
819  * an ERROR_MESSAGE.
820  */
821  if(pMessage->m_pType != pResponseType &&
822  pMessage->m_pType != pErrorMsgType)
823  {
824  /* Type does not match. Keep looking. */
825  continue;
826  }
827  }
828 
829  /*
830  * Are we looking for a particular message ID?
831  */
832  if(0 != ResponseMessageID)
833  {
834  if(pMessage->getMessageID() != ResponseMessageID)
835  {
836  /* Message ID does not match. Keep looking. */
837  continue;
838  }
839  }
840 
841  /*
842  * Found it. Unlink it from the queue and return it.
843  */
844  m_listInputQueue.remove(pMessage);
845  return pMessage;
846  }
847 
848  /*
849  * Sought message is not in the queue. Advance the
850  * receiver state and see if the message is produced.
851  */
852  lrc = recvAdvance(nMaxMS, timeLimit);
853  if(lrc != RC_OK)
854  {
855  return NULL;
856  }
857 
858  /*
859  * Loop to the top and try again.
860  */
861  }
862 }
863 
864 
900 CConnection::recvAdvance (
901  int nMaxMS,
902  time_t timeLimit)
903 {
904  CErrorDetails * pError = &m_Recv.ErrorDetails;
905 
906  /*
907  * Clear the error details in the receiver state.
908  */
909  pError->clear();
910 
911  /*
912  * Loop until victory or some sort of exception happens
913  */
914  for(;;)
915  {
916  /*
917  * Note that the frame is in progress.
918  * Existing buffer content, if any, is deemed
919  * invalid or incomplete.
920  */
921  m_Recv.bFrameValid = FALSE;
922 
923  /*
924  * Check to see if we have a frame in the buffer.
925  * If not, how many more bytes do we need?
926  *
927  * LLRP_FrameExtract() status
928  *
929  * FRAME_ERROR Impossible situation, like message
930  * length too small or the like.
931  * Recovery in this situation is
932  * unlikely and probably the app
933  * should drop the connection.
934  *
935  * FRAME_READY Frame is complete. Details are
936  * available for pre-decode decisions.
937  *
938  * FRAME_NEED_MORE Need more input bytes to finish the frame.
939  * The m_nBytesNeeded field is how many more.
940  */
941  m_Recv.FrameExtract = CFrameExtract(m_Recv.pBuffer, m_Recv.nBuffer);
942 
943  /*
944  * Framing error?
945  */
946  if(CFrameExtract::FRAME_ERROR == m_Recv.FrameExtract.m_eStatus)
947  {
949  "framing error in message stream");
950  break;
951  }
952 
953  /*
954  * Need more bytes? extractRc>0 means we do and extractRc is the
955  * number of bytes immediately required.
956  */
957  if(CFrameExtract::NEED_MORE == m_Recv.FrameExtract.m_eStatus)
958  {
959  unsigned int nRead = m_Recv.FrameExtract.m_nBytesNeeded;
960  unsigned char * pBufPos = &m_Recv.pBuffer[m_Recv.nBuffer];
961 
962  /*
963  * Before we do anything that might block,
964  * check to see if the time limit is exceeded.
965  */
966  if(0 != timeLimit)
967  {
968  if(time(NULL) > timeLimit)
969  {
970  // Timeout
972  "timeout");
973  break;
974  }
975  }
976 
977  /*
978  * The frame extractor needs more data, make sure the
979  * frame size fits in the receive buffer.
980  */
981  if(m_Recv.nBuffer + nRead > m_nBufferSize)
982  {
984  "buffer overflow");
985  break;
986  }
987 
988  /*
989  * If this is not a block indefinitely request use select()
990  * to see if there is data in time.
991  */
992  if (nMaxMS >= 0)
993  {
994  fd_set readFdSet = {0};
995  timeval timeout = {0};
996  int bioSocket = -1;
997  SSL* pSsl = NULL;
998 
999  // Check for SSL and error out if it's not null
1000  BIO_get_ssl(m_pBio, &pSsl);
1001  if (pSsl != NULL)
1002  {
1003  pError->resultCodeAndWhatStr(RC_RecvIOError, "Non-blocking I/O not supported over secure connections.");
1004  break;
1005  }
1006 
1007  FD_ZERO(&readFdSet);
1008  timeout.tv_sec = nMaxMS / 1000u;
1009  timeout.tv_usec = (nMaxMS % 1000u) * 1000u;
1010 
1011  BIO_get_fd(m_pBio, &bioSocket);
1012  if (bioSocket == -1)
1013  {
1014  pError->resultCodeAndWhatStr(RC_RecvIOError, "failed to retrieve socket's file descriptor");
1015  break;
1016  }
1017 
1018  FD_SET(bioSocket, &readFdSet);
1019 
1020  int rc = select((bioSocket+1), &readFdSet, NULL, NULL, &timeout);
1021  if (0 > rc)
1022  {
1023  /* Error */
1024  pError->resultCodeAndWhatStr(RC_RecvIOError, "poll failed");
1025  break;
1026  }
1027  else if (0 == rc)
1028  {
1029  /* Timeout */
1030  pError->resultCodeAndWhatStr(RC_RecvTimeout, "timeout");
1031  break;
1032  }
1033  }
1034 
1035  /*
1036  * Call BIO_read, and if no data, but should_retry is true, retry within timeout window
1037  */
1038  int rc = BIO_read(m_pBio, pBufPos, nRead);
1039 
1040  // We will retry on the next go around if need be, checking against the timeout, so only break
1041  // if BIO_should_retry returns false.
1042  if ((0 == rc) && (!BIO_should_retry(m_pBio)))
1043  {
1045  "connection closed by remote");
1046  break;
1047  }
1048  else if (0 > rc)
1049  {
1051  "recv IO error");
1052  break;
1053  }
1054  else // We have data!
1055  {
1056  m_Recv.nBuffer += rc;
1057 
1058  // Re-run the loop in order to call CFrameExtract's constructor
1059  // again, which will determine if another network read is
1060  // necessary or if the message is now assembled and ready
1061  // for further consumption.
1062  continue;
1063  }
1064  }
1065 
1066  /*
1067  * Is the frame ready?
1068  * If a valid frame is present, decode and enqueue it.
1069  */
1070  if(CFrameExtract::READY == m_Recv.FrameExtract.m_eStatus)
1071  {
1072  /*
1073  * Frame appears complete. Time to try to decode it.
1074  */
1075  CFrameDecoder decoder(m_pTypeRegistry, m_Recv.pBuffer, m_Recv.nBuffer);
1076  CMessage * pMessage;
1077 
1078  /*
1079  * Now ask the nice, brand new decoder to decode the frame.
1080  * It returns NULL for some kind of error.
1081  */
1082  pMessage = decoder.decodeMessage();
1083 
1084  /*
1085  * Always capture the error details even when it works.
1086  * Whatever happened, we are done with the decoder.
1087  */
1088  m_Recv.ErrorDetails = decoder.m_ErrorDetails;
1089 
1090  /*
1091  * If NULL there was an error. Clean up the
1092  * receive state. Return the error.
1093  */
1094  if(NULL == pMessage)
1095  {
1096  /*
1097  * Make sure the return is not RC_OK
1098  */
1099  if(RC_OK == pError->m_eResultCode)
1100  {
1102  "NULL message but no error");
1103  }
1104 
1105  /*
1106  * All we can do is discard the frame.
1107  */
1108  m_Recv.nBuffer = 0;
1109  m_Recv.bFrameValid = FALSE;
1110 
1111  break;
1112  }
1113 
1114  /*
1115  * Yay! It worked. Enqueue the message.
1116  */
1117  m_listInputQueue.push_back(pMessage);
1118 
1119  /*
1120  * Note that the frame is valid. Consult
1121  * Recv.FrameExtract.m_MessageLength.
1122  * Clear the buffer count to be ready for next time.
1123  */
1124  m_Recv.bFrameValid = TRUE;
1125  m_Recv.nBuffer = 0;
1126 
1127  break;
1128  }
1129 
1130  /*
1131  * If we get here there was an FrameExtract status
1132  * we didn't expect.
1133  */
1134 
1135  /*NOTREACHED*/
1136  assert(0);
1137  }
1138 
1139  return pError->m_eResultCode;
1140 }
1141 
1142 
1165 time_t
1166 CConnection::calculateTimeLimit (
1167  int nMaxMS)
1168 {
1169  if(0 == nMaxMS)
1170  {
1171  /* When just peeking, try for at most one second */
1172  return time(NULL) + 1;
1173  }
1174  else if(0 < nMaxMS)
1175  {
1176  /*
1177  * Try for a at most a certain period of time.
1178  *
1179  * timeLimit = now + ceil(nMaxMS/1000) + 1
1180  *
1181  * The last +1 compensates for not knowing
1182  * when the next time() tick will happen.
1183  *
1184  * For example, if now is SECONDS.999 seconds
1185  * the next tick will happen in 1 millisecond.
1186  * Suppose nMaxMS is 500ms (1/2 second).
1187  * Even rounding 500ms up to 1 second, the
1188  * time limit without the +1 would be
1189  * SECONDS+1 -- 1ms away. That's too soon.
1190  *
1191  * The extra +1 makes the maximum timeout
1192  * longer than required. But the timeLimit
1193  * is a safeguard anyway and usually the
1194  * timeout will occur when the user wants.
1195  */
1196  return time(NULL) + ((nMaxMS + 1999u) / 1000u);
1197  }
1198  else
1199  {
1200  /* Try indefinitely */
1201  return 0;
1202  }
1203 }
1204 
1211 void CConnection::initializeOpenSSL()
1212 {
1213  CRYPTO_malloc_init(); // only needed for windows to safely transfer
1214  // data across the dll boundry as the
1215  // mallocs/heaps are not the same. This is a
1216  // no-op on Linux.
1217 
1218  SSL_library_init(); // SSL_library_init() always returns "1",
1219  // so it is safe to discard the return value.
1220 
1221  SSL_load_error_strings();
1222 }
1223 
1224 
1234 int CConnection::initializeWinsock()
1235 {
1236  int rc = 0;
1237 
1238 #ifdef _WIN32
1239  WSADATA winsockData = { 0 };
1240  rc = WSAStartup(MAKEWORD(2, 2), &winsockData);
1241 #endif
1242 
1243  return rc;
1244 }
1245 
1255 int CConnection::shutdownWinsock()
1256 {
1257  int rc = 0;
1258 
1259 #ifdef _WIN32
1260  rc = WSACleanup();
1261 #endif
1262 
1263  return rc;
1264 }
1265 
1266 }; /* namespace LLRP */
1267 
const CTypeDescriptor * lookupMessage(unsigned int MessageTypeNum) const
Lookup a standard message type descriptor. NULL=>not found.
CMessage * recvResponse(int nMaxMS, const CTypeDescriptor *pResponseType, llrp_u32_t ResponseMessageID)
Receive a specific message from a connection.
const CTypeDescriptor * m_pType
The type descriptor desribing this element.
Definition: ltkcpp_base.h:972
CConnection(const CTypeRegistry *pTypeRegistry, unsigned int nBufferSize)
Construct a new LLRP connection instance.
Class for handling two-way LLRP message traffic.
EResultCode m_eResultCode
Result code from operation.
Definition: ltkcpp_base.h:635
Based type descriptions for the LTKCPP library.
Classes to encode and decod LLRP binary frames.
EResultCode
Error result codes for LTK operations.
Definition: ltkcpp_base.h:583
int closeConnectionToReader(void)
Close connection to reader, allow reuse of instance.
A collection of pointers to CTypeDescriptors.
Definition: ltkcpp_base.h:885
const CErrorDetails * getTransactError(void)
Get the details that explains transact() error.
Based types for the LKTCPP library.
void resultCodeAndWhatStr(EResultCode eResultCode, const char *pWhatStr)
Convenience function used by the toolkit to set CErrorDetails result code and pWhatStr.
CMessage * recvMessage(int nMaxMS)
Receive a message from a connection.
CMessage * transact(CMessage *pSendMessage, int nMaxMS)
Transact a LLRP request and response to a connection.
const CErrorDetails * getRecvError(void)
Get the details that explains recvMessage() or recvResponse() error.
void clear(void)
Clears the contents of a CErrorDetails.
int openConnectionToReader(const char *pReaderHostName)
Open a connection to the reader over an unencrypted socket.
const CTypeDescriptor * m_pResponseType
For messages (bIsMessage==TRUE), this is the type descriptor for the corresponding response...
Definition: ltkcpp_base.h:776
EResultCode sendMessage(CMessage *pMessage)
Send a LLRP message to a connection.
Class to return error details in LTKCPP operations.
Definition: ltkcpp_base.h:631
llrp_u32_t getMessageID(void) const
Gets the current LLRP Message ID for the Message.
Definition: ltkcpp_base.h:1107
Base Class for All LLRP LTK Messages.
Definition: ltkcpp_base.h:1088
const char * getConnectError(void)
Get the string that explains openReaderConnection() error.
~CConnection(void)
Destruct a LLRP connection instance.
int openSecureConnectionToReader(const char *pReaderHostName)
Open a connection to the reader over an encrypted socket.
Describes a message or parameter type.
Definition: ltkcpp_base.h:755
const CErrorDetails * getSendError(void)
Get the details that explains sendMessage() error.