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 #include <openssl/ssl.h>
33 
34 #include "ltkcpp_platform.h"
35 #include "ltkcpp_base.h"
36 #include "ltkcpp_frame.h"
37 #include "ltkcpp_connection.h"
38 
39 #define LLRP1_TCP_PORT (5084u)
40 #define LLRP1_TLS_PORT (5085u)
41 
42 namespace LLRP
43 {
44 
64  const CTypeRegistry * pTypeRegistry,
65  unsigned int nBufferSize)
66 {
67  initializeOpenSSL();
68 
69  /*
70  * Apply default buffer size
71  */
72  if(0 == nBufferSize)
73  {
74  nBufferSize = 128u*1024u;
75  }
76 
77  /*
78  * Make sure the buffer size is sane. This is arbitrary.
79  * The smallest message is 10 bytes, but it ain't anything
80  * useful. 1024u covers a surprising number of messages.
81  */
82  if(1024u > nBufferSize || 1u*1024u*1024u < nBufferSize)
83  {
84  throw "Insane buffer size";
85  }
86 
87  /*
88  * Capture variables. A NULL m_pBio indicates there
89  * is no connection yet.
90  */
91  m_pBio = NULL;
92  m_pTypeRegistry = pTypeRegistry;
93  m_nBufferSize = nBufferSize;
94 
95  memset(&m_Recv, 0, sizeof m_Recv);
96  memset(&m_Send, 0, sizeof m_Send);
97 
98  /*
99  * Allocate and check each the recv and send buffers.
100  */
101  m_Recv.pBuffer = new llrp_byte_t[nBufferSize];
102  m_Send.pBuffer = new llrp_byte_t[nBufferSize];
103 
104  /*
105  * Zero-fill buffers just so debugger printing is tidy
106  */
107  memset(m_Recv.pBuffer, 0, nBufferSize);
108  memset(m_Send.pBuffer, 0, nBufferSize);
109 }
110 
111 
120 {
121  /*
122  * Close the connection, if one
123  */
125 
126  /*
127  * Destruct any messages on the input queue
128  */
129  for (
130  std::list<CMessage *>::iterator msg = m_listInputQueue.begin();
131  msg != m_listInputQueue.end();
132  msg++)
133  {
134  delete *msg;
135  }
136 
137  /*
138  * free each the receive and send bufers
139  */
140  delete[] m_Recv.pBuffer;
141  delete[] m_Send.pBuffer;
142 
143 }
144 
145 
157 int CConnection::openConnectionToReader(const char * pReaderHostName)
158 {
159  return openConnectionToReader(pReaderHostName, E_LLRP_CONNECTION_TYPE_UNSECURE);
160 }
161 
173 int CConnection::openSecureConnectionToReader(const char * pReaderHostName)
174 {
175  return openConnectionToReader(pReaderHostName, E_LLRP_CONNECTION_TYPE_SSL);
176 }
177 
190 int CConnection::openConnectionToReader(const char * pReaderHostName, E_LLRP_CONNECTION_TYPE eType)
191 {
192  int rc = -1;
193  BIO* pBio = NULL;
194  int port = 0;
195 
196  /*
197  * Clear the connect error string
198  */
199  m_pConnectErrorStr = NULL;
200 
201  /*
202  * Make sure there isn't already a connection.
203  */
204  if(NULL != m_pBio)
205  {
206  m_pConnectErrorStr = "already connected";
207  return -1;
208  }
209 
210  switch (eType)
211  {
212  case E_LLRP_CONNECTION_TYPE_SSL:
213  rc = initializeSslBio(&pBio);
214  port = LLRP1_TLS_PORT;
215  break;
216  case E_LLRP_CONNECTION_TYPE_UNSECURE:
217  default:
218  rc = initializeSocketBio(&pBio);
219  port = LLRP1_TCP_PORT;
220  break;
221  }
222  if (rc != 0)
223  {
224  // log message should already be set to the appropriate error
225  // by either initializeSslBio or initializeSocketBio
226  return -1;
227  }
228 
229  rc = BIO_set_conn_hostname(pBio, pReaderHostName);
230  if (rc != 1)
231  {
232  m_pConnectErrorStr = "Unable to assign hostname to socket";
233  return -1;
234  }
235 
236  rc = BIO_set_conn_int_port(pBio, &port); // This always returns 1 according to the documentation
237  if (rc != 1)
238  {
239  m_pConnectErrorStr = "Unable to assign port to socket";
240  return -1;
241  }
242 
243  rc = BIO_do_connect(pBio);
244  if (rc != 1)
245  {
246  m_pConnectErrorStr = "Failed to connect to the host";
247  return -1;
248  }
249 
250  if (eType == E_LLRP_CONNECTION_TYPE_SSL)
251  {
252  rc = BIO_do_handshake(pBio);
253  if (rc != 1)
254  {
255  m_pConnectErrorStr = "Failed to perform TLS handshake";
256  return -1;
257  }
258  }
259 
260  // Our connection is established, assign it to our object
261  // for further use:
262  this->m_pBio = pBio;
263 
264  return 0;
265 }
266 
278 int CConnection::initializeSslBio(BIO** ppBio)
279 {
280  BIO* pBio = NULL;
281  long sslOptions = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
282 
283  if (ppBio == NULL)
284  {
285  m_pConnectErrorStr = "Internal parameter failure";
286  return -1;
287  }
288 
289  const SSL_METHOD* sslMethod = SSLv23_method();
290  if (sslMethod == NULL)
291  {
292  m_pConnectErrorStr = "System SSL socket method failure";
293  return -1;
294  }
295 
296  SSL_CTX* pSslCtx = SSL_CTX_new(sslMethod);
297  if (pSslCtx == NULL)
298  {
299  m_pConnectErrorStr = "System SSL socket context failure";
300  return -1;
301  }
302 
303  SSL_CTX_set_verify(pSslCtx, SSL_VERIFY_NONE, NULL);
304  SSL_CTX_set_options(pSslCtx, sslOptions);
305 
306  pBio = BIO_new_ssl_connect(pSslCtx);
307  SSL_CTX_free(pSslCtx);
308  if (pBio == NULL)
309  {
310  m_pConnectErrorStr = "System SSL socket allocation failure";
311  return -1;
312  }
313 
314  *ppBio = pBio;
315  return 0;
316 }
317 
329 int CConnection::initializeSocketBio(bio_st** ppBio)
330 {
331  BIO* pBio = NULL;
332  BIO_METHOD* pBioMethod = NULL;
333 
334  if (ppBio == NULL)
335  {
336  m_pConnectErrorStr = "Internal parameter failure";
337  return -1;
338  }
339 
340  pBioMethod = BIO_s_connect();
341  if (pBioMethod == NULL)
342  {
343  m_pConnectErrorStr = "System socket method failure";
344  return -1;
345  }
346 
347  pBio = BIO_new(pBioMethod);
348  if (pBio == NULL)
349  {
350  m_pConnectErrorStr = "System socket allocation failure";
351  return -1;
352  }
353 
354  *ppBio = pBio;
355  return 0;
356 }
357 
368 const char *
370 {
371  return m_pConnectErrorStr;
372 }
373 
374 
385 int
387 {
388  if(NULL == m_pBio)
389  {
390  m_pConnectErrorStr = "not connected";
391  return -1;
392  }
393 
394  BIO_free_all(m_pBio);
395  m_pBio = NULL;
396 
397  return 0;
398 }
399 
400 
423 CMessage *
425  CMessage * pSendMessage,
426  int nMaxMS)
427 {
428  const CTypeDescriptor * pResponseType;
429  EResultCode lrc;
430  CMessage * pResponseMessage;
431 
432  /*
433  * Determine the response type. The type descriptor
434  * of the outgoing request message points to the
435  * type descriptor of the response. Since we are
436  * totally dependent upon it, fail if there
437  * is no response type pointer value.
438  */
439  pResponseType = pSendMessage->m_pType->m_pResponseType;
440  if(NULL == pResponseType)
441  {
442  CErrorDetails * pError = &m_Send.ErrorDetails;
443 
444  pError->clear();
446  "send message has no response type");
447  return NULL;
448  }
449 
450  /*
451  * Send the request
452  */
453  lrc = sendMessage(pSendMessage);
454  if(RC_OK != lrc)
455  {
456  return NULL;
457  }
458 
459  /*
460  * Receive the response subject to timeout
461  */
462  pResponseMessage = recvResponse(nMaxMS,
463  pResponseType, pSendMessage->getMessageID());
464 
465  /*
466  * Whatever recvResponse() returned is the result.
467  */
468  return pResponseMessage;
469 }
470 
471 
486 const CErrorDetails *
488 {
489  const CErrorDetails * pError;
490 
491  pError = getSendError();
492  if(RC_OK == pError->m_eResultCode)
493  {
494  pError = getRecvError();
495  }
496 
497  return pError;
498 }
499 
500 
518  CMessage * pMessage)
519 {
520  CErrorDetails * pError = &m_Send.ErrorDetails;
521  CFrameEncoder frameEncoder(m_Send.pBuffer, m_nBufferSize);
522 
523  /*
524  * Clear the error details in the send state.
525  */
526  pError->clear();
527 
528  /*
529  * Make sure the socket is open.
530  */
531  if(NULL == m_pBio)
532  {
533  pError->resultCodeAndWhatStr(RC_MiscError, "not connected");
534  return pError->m_eResultCode;
535  }
536 
537  /*
538  * Encode the message, then check the encoder's ErrorDetails for results.
539  */
540  frameEncoder.encodeElement(pMessage);
541 
542  /*
543  * Regardless of what happened capture the error details
544  * and the number of bytes placed in the buffer.
545  */
546  m_Send.ErrorDetails = frameEncoder.m_ErrorDetails;
547  m_Send.nBuffer = frameEncoder.getLength();
548 
549  /*
550  * If the encoding appears complete write the frame
551  * to the connection. NB: this is not ready for
552  * non-blocking I/O (EWOULDBLOCK).
553  */
554  if (RC_OK == pError->m_eResultCode)
555  {
556  int rc = BIO_write(m_pBio, m_Send.pBuffer, (m_Send.nBuffer * sizeof(llrp_byte_t)));
557  if(rc != (int)m_Send.nBuffer)
558  {
559  /* Yikes! */
560  pError->resultCodeAndWhatStr(RC_SendIOError, "send IO error");
561  }
562  }
563 
564  /*
565  * Done.
566  */
567  return pError->m_eResultCode;
568 }
569 
570 
580 const CErrorDetails *
582 {
583  return &m_Send.ErrorDetails;
584 }
585 
586 
607 CMessage *
609  int nMaxMS)
610 {
611  time_t timeLimit = calculateTimeLimit(nMaxMS);
612  EResultCode lrc;
613  CMessage * pMessage;
614 
615  /*
616  * Make sure the socket is open.
617  */
618  if(NULL == m_pBio)
619  {
620  CErrorDetails * pError = &m_Recv.ErrorDetails;
621 
622  pError->resultCodeAndWhatStr(RC_MiscError, "not connected");
623  return NULL;
624  }
625 
626  /*
627  * Loop until victory or some sort of exception happens
628  */
629  for(;;)
630  {
631  /*
632  * Check the input queue to see if there is already
633  * a message pending.
634  */
635  if(!m_listInputQueue.empty())
636  {
637  pMessage = m_listInputQueue.front();
638  m_listInputQueue.pop_front();
639  return pMessage;
640  }
641 
642  /*
643  * No message available. Advance the receiver state
644  * and see if a message is produced.
645  */
646  lrc = recvAdvance(nMaxMS, timeLimit);
647  if(lrc != RC_OK)
648  {
649  return NULL;
650  }
651  }
652 }
653 
654 
665 const CErrorDetails *
667 {
668  return &m_Recv.ErrorDetails;
669 }
670 
671 
718 CMessage *
720  int nMaxMS,
721  const CTypeDescriptor * pResponseType,
722  llrp_u32_t ResponseMessageID)
723 {
724  time_t timeLimit = calculateTimeLimit(nMaxMS);
725  const CTypeDescriptor * pErrorMsgType;
726  EResultCode lrc;
727  CMessage * pMessage;
728 
729  /*
730  * Make sure the socket is open.
731  */
732  if(NULL == m_pBio)
733  {
734  CErrorDetails * pError = &m_Recv.ErrorDetails;
735 
736  pError->resultCodeAndWhatStr(RC_MiscError, "not connected");
737  return NULL;
738  }
739 
740  /*
741  * Look up the ERROR_MESSAGE type descriptor now.
742  */
743  pErrorMsgType = m_pTypeRegistry->lookupMessage(100u);
744 
745  /*
746  * Loop until victory or some sort of exception happens
747  */
748  for(;;)
749  {
750  /*
751  * Check the input queue to see if the sought
752  * message is present.
753  */
754  for (
755  std::list<CMessage *>::iterator msg = m_listInputQueue.begin();
756  msg != m_listInputQueue.end();
757  msg++)
758  {
759  pMessage = *msg;
760 
761  /*
762  * Are we looking for a particular message type?
763  */
764  if(NULL != pResponseType)
765  {
766  /*
767  * See if it is the sought response type or
768  * an ERROR_MESSAGE.
769  */
770  if(pMessage->m_pType != pResponseType &&
771  pMessage->m_pType != pErrorMsgType)
772  {
773  /* Type does not match. Keep looking. */
774  continue;
775  }
776  }
777 
778  /*
779  * Are we looking for a particular message ID?
780  */
781  if(0 != ResponseMessageID)
782  {
783  if(pMessage->getMessageID() != ResponseMessageID)
784  {
785  /* Message ID does not match. Keep looking. */
786  continue;
787  }
788  }
789 
790  /*
791  * Found it. Unlink it from the queue and return it.
792  */
793  m_listInputQueue.remove(pMessage);
794  return pMessage;
795  }
796 
797  /*
798  * Sought message is not in the queue. Advance the
799  * receiver state and see if the message is produced.
800  */
801  lrc = recvAdvance(nMaxMS, timeLimit);
802  if(lrc != RC_OK)
803  {
804  return NULL;
805  }
806 
807  /*
808  * Loop to the top and try again.
809  */
810  }
811 }
812 
813 
849 CConnection::recvAdvance (
850  int nMaxMS,
851  time_t timeLimit)
852 {
853  CErrorDetails * pError = &m_Recv.ErrorDetails;
854 
855  /*
856  * Clear the error details in the receiver state.
857  */
858  pError->clear();
859 
860  /*
861  * Loop until victory or some sort of exception happens
862  */
863  for(;;)
864  {
865  /*
866  * Note that the frame is in progress.
867  * Existing buffer content, if any, is deemed
868  * invalid or incomplete.
869  */
870  m_Recv.bFrameValid = FALSE;
871 
872  /*
873  * Check to see if we have a frame in the buffer.
874  * If not, how many more bytes do we need?
875  *
876  * LLRP_FrameExtract() status
877  *
878  * FRAME_ERROR Impossible situation, like message
879  * length too small or the like.
880  * Recovery in this situation is
881  * unlikely and probably the app
882  * should drop the connection.
883  *
884  * FRAME_READY Frame is complete. Details are
885  * available for pre-decode decisions.
886  *
887  * FRAME_NEED_MORE Need more input bytes to finish the frame.
888  * The m_nBytesNeeded field is how many more.
889  */
890  m_Recv.FrameExtract = CFrameExtract(m_Recv.pBuffer, m_Recv.nBuffer);
891 
892  /*
893  * Framing error?
894  */
895  if(CFrameExtract::FRAME_ERROR == m_Recv.FrameExtract.m_eStatus)
896  {
898  "framing error in message stream");
899  break;
900  }
901 
902  /*
903  * Need more bytes? extractRc>0 means we do and extractRc is the
904  * number of bytes immediately required.
905  */
906  if(CFrameExtract::NEED_MORE == m_Recv.FrameExtract.m_eStatus)
907  {
908  unsigned int nRead = m_Recv.FrameExtract.m_nBytesNeeded;
909  unsigned char * pBufPos = &m_Recv.pBuffer[m_Recv.nBuffer];
910 
911  /*
912  * Before we do anything that might block,
913  * check to see if the time limit is exceeded.
914  */
915  if(0 != timeLimit)
916  {
917  if(time(NULL) > timeLimit)
918  {
919  // Timeout
921  "timeout");
922  break;
923  }
924  }
925 
926  /*
927  * The frame extractor needs more data, make sure the
928  * frame size fits in the receive buffer.
929  */
930  if(m_Recv.nBuffer + nRead > m_nBufferSize)
931  {
933  "buffer overflow");
934  break;
935  }
936 
937  /*
938  * If this is not a block indefinitely request use select()
939  * to see if there is data in time.
940  */
941  if (nMaxMS >= 0)
942  {
943  fd_set readFdSet = {0};
944  timeval timeout = {0};
945  int bioSocket = -1;
946  SSL* pSsl = NULL;
947 
948  // Check for SSL and error out if it's not null
949  BIO_get_ssl(m_pBio, &pSsl);
950  if (pSsl != NULL)
951  {
952  pError->resultCodeAndWhatStr(RC_RecvIOError, "Non-blocking I/O not supported over secure connections.");
953  break;
954  }
955 
956  FD_ZERO(&readFdSet);
957  timeout.tv_sec = nMaxMS / 1000u;
958  timeout.tv_usec = (nMaxMS % 1000u) * 1000u;
959 
960  BIO_get_fd(m_pBio, &bioSocket);
961  if (bioSocket == -1)
962  {
963  pError->resultCodeAndWhatStr(RC_RecvIOError, "failed to retrieve socket's file descriptor");
964  break;
965  }
966 
967  FD_SET(bioSocket, &readFdSet);
968 
969  int rc = select((bioSocket+1), &readFdSet, NULL, NULL, &timeout);
970  if (0 > rc)
971  {
972  /* Error */
973  pError->resultCodeAndWhatStr(RC_RecvIOError, "poll failed");
974  break;
975  }
976  else if (0 == rc)
977  {
978  /* Timeout */
979  pError->resultCodeAndWhatStr(RC_RecvTimeout, "timeout");
980  break;
981  }
982  }
983 
984  /*
985  * Call BIO_read, and if no data, but should_retry is true, retry within timeout window
986  */
987  int rc = BIO_read(m_pBio, pBufPos, nRead);
988 
989  // We will retry on the next go around if need be, checking against the timeout, so only break
990  // if BIO_should_retry returns false.
991  if ((0 == rc) && (!BIO_should_retry(m_pBio)))
992  {
994  "connection closed by remote");
995  break;
996  }
997  else if (0 > rc)
998  {
1000  "recv IO error");
1001  break;
1002  }
1003  else // We have data!
1004  {
1005  m_Recv.nBuffer += rc;
1006 
1007  // Re-run the loop in order to call CFrameExtract's constructor
1008  // again, which will determine if another network read is
1009  // necessary or if the message is now assembled and ready
1010  // for further consumption.
1011  continue;
1012  }
1013  }
1014 
1015  /*
1016  * Is the frame ready?
1017  * If a valid frame is present, decode and enqueue it.
1018  */
1019  if(CFrameExtract::READY == m_Recv.FrameExtract.m_eStatus)
1020  {
1021  /*
1022  * Frame appears complete. Time to try to decode it.
1023  */
1024  CFrameDecoder * pDecoder;
1025  CMessage * pMessage;
1026 
1027  /*
1028  * Construct a new frame decoder. It needs the registry
1029  * to facilitate decoding.
1030  */
1031  pDecoder = new CFrameDecoder(m_pTypeRegistry,
1032  m_Recv.pBuffer, m_Recv.nBuffer);
1033 
1034  /*
1035  * Make sure we really got one. If not, weird problem.
1036  */
1037  if(pDecoder == NULL)
1038  {
1039  /* All we can do is discard the frame. */
1040  m_Recv.nBuffer = 0;
1041  m_Recv.bFrameValid = FALSE;
1043  "decoder constructor failed");
1044  break;
1045  }
1046 
1047  /*
1048  * Now ask the nice, brand new decoder to decode the frame.
1049  * It returns NULL for some kind of error.
1050  */
1051  pMessage = pDecoder->decodeMessage();
1052 
1053  /*
1054  * Always capture the error details even when it works.
1055  * Whatever happened, we are done with the decoder.
1056  */
1057  m_Recv.ErrorDetails = pDecoder->m_ErrorDetails;
1058 
1059  /*
1060  * Bye bye and thank you li'l decoder.
1061  */
1062  delete pDecoder;
1063 
1064  /*
1065  * If NULL there was an error. Clean up the
1066  * receive state. Return the error.
1067  */
1068  if(NULL == pMessage)
1069  {
1070  /*
1071  * Make sure the return is not RC_OK
1072  */
1073  if(RC_OK == pError->m_eResultCode)
1074  {
1076  "NULL message but no error");
1077  }
1078 
1079  /*
1080  * All we can do is discard the frame.
1081  */
1082  m_Recv.nBuffer = 0;
1083  m_Recv.bFrameValid = FALSE;
1084 
1085  break;
1086  }
1087 
1088  /*
1089  * Yay! It worked. Enqueue the message.
1090  */
1091  m_listInputQueue.push_back(pMessage);
1092 
1093  /*
1094  * Note that the frame is valid. Consult
1095  * Recv.FrameExtract.m_MessageLength.
1096  * Clear the buffer count to be ready for next time.
1097  */
1098  m_Recv.bFrameValid = TRUE;
1099  m_Recv.nBuffer = 0;
1100 
1101  break;
1102  }
1103 
1104  /*
1105  * If we get here there was an FrameExtract status
1106  * we didn't expect.
1107  */
1108 
1109  /*NOTREACHED*/
1110  assert(0);
1111  }
1112 
1113  return pError->m_eResultCode;
1114 }
1115 
1116 
1139 time_t
1140 CConnection::calculateTimeLimit (
1141  int nMaxMS)
1142 {
1143  if(0 == nMaxMS)
1144  {
1145  /* When just peeking, try for at most one second */
1146  return time(NULL) + 1;
1147  }
1148  else if(0 < nMaxMS)
1149  {
1150  /*
1151  * Try for a at most a certain period of time.
1152  *
1153  * timeLimit = now + ceil(nMaxMS/1000) + 1
1154  *
1155  * The last +1 compensates for not knowing
1156  * when the next time() tick will happen.
1157  *
1158  * For example, if now is SECONDS.999 seconds
1159  * the next tick will happen in 1 millisecond.
1160  * Suppose nMaxMS is 500ms (1/2 second).
1161  * Even rounding 500ms up to 1 second, the
1162  * time limit without the +1 would be
1163  * SECONDS+1 -- 1ms away. That's too soon.
1164  *
1165  * The extra +1 makes the maximum timeout
1166  * longer than required. But the timeLimit
1167  * is a safeguard anyway and usually the
1168  * timeout will occur when the user wants.
1169  */
1170  return time(NULL) + ((nMaxMS + 1999u) / 1000u);
1171  }
1172  else
1173  {
1174  /* Try indefinitely */
1175  return 0;
1176  }
1177 }
1178 
1179 void CConnection::initializeOpenSSL()
1180 {
1181  CRYPTO_malloc_init(); // only needed for windows to safely transfer
1182  // data across the dll boundry as the
1183  // mallocs/heaps are not the same. This is a
1184  // no-op on Linux.
1185 
1186  SSL_library_init(); // SSL_library_init() always returns "1",
1187  // so it is safe to discard the return value.
1188 
1189  SSL_load_error_strings();
1190 }
1191 
1192 }; /* namespace LLRP */
1193 
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.