35 #define LLRPCLOSESOCKET(X) closesocket(X)
38 #include <sys/types.h>
39 #include <sys/socket.h>
41 #define LLRPCLOSESOCKET(X) close(X)
44 #include <openssl/ssl.h>
51 #define LLRP1_TCP_PORT "5084"
52 #define LLRP1_TLS_PORT "5085"
56 #ifndef INVALID_SOCKET
57 #define INVALID_SOCKET (unsigned long)(~0)
58 #endif // INVALID_SOCKET
63 #define SOCKET_ERROR (-1)
89 unsigned int nBufferSize)
99 nBufferSize = 128u*1024u;
107 if(1024u > nBufferSize || 1u*1024u*1024u < nBufferSize)
109 throw "Insane buffer size";
117 m_pTypeRegistry = pTypeRegistry;
118 m_nBufferSize = nBufferSize;
120 memset(&m_Recv, 0,
sizeof m_Recv);
121 memset(&m_Send, 0,
sizeof m_Send);
126 m_Recv.pBuffer =
new llrp_byte_t[nBufferSize];
127 m_Send.pBuffer =
new llrp_byte_t[nBufferSize];
132 memset(m_Recv.pBuffer, 0, nBufferSize);
133 memset(m_Send.pBuffer, 0, nBufferSize);
155 std::list<CMessage *>::iterator msg = m_listInputQueue.begin();
156 msg != m_listInputQueue.end();
165 delete[] m_Recv.pBuffer;
166 delete[] m_Send.pBuffer;
219 unsigned long hSocket = INVALID_SOCKET;
220 BIO* pSocketBio = NULL;
225 m_pConnectErrorStr = NULL;
232 m_pConnectErrorStr =
"already connected";
239 case E_LLRP_CONNECTION_TYPE_SSL:
240 rc = openSocketConnection(pReaderHostName, LLRP1_TLS_PORT, &hSocket);
242 case E_LLRP_CONNECTION_TYPE_UNSECURE:
243 rc = openSocketConnection(pReaderHostName, LLRP1_TCP_PORT, &hSocket);
246 m_pConnectErrorStr =
"Unknown connection type.";
259 pSocketBio = BIO_new_socket(hSocket, BIO_CLOSE);
260 if (pSocketBio == NULL)
262 m_pConnectErrorStr =
"Failed to register socket with OpenSSL.";
263 LLRPCLOSESOCKET(hSocket);
270 if (eType == E_LLRP_CONNECTION_TYPE_SSL)
273 int rc = initializeSslBio(&pSslBio);
276 BIO_free_all(pSocketBio);
280 BIO_push(pSslBio, pSocketBio);
282 rc = BIO_do_handshake(pSslBio);
285 this->m_pBio = pSslBio;
289 m_pConnectErrorStr =
"Failed to perform TLS handshake";
290 BIO_free_all(pSslBio);
296 this->m_pBio = pSocketBio;
315 int CConnection::openSocketConnection(
const char* pkzReaderHostName,
const char* pkzPort,
unsigned long* phSocket)
317 if (phSocket == NULL)
319 m_pConnectErrorStr =
"Internal error.";
323 addrinfo* pAddrInfo = NULL;
324 int rc = getaddrinfo(pkzReaderHostName, pkzPort, NULL, &pAddrInfo);
327 m_pConnectErrorStr =
"Failed to resolve host.";
328 freeaddrinfo(pAddrInfo);
332 unsigned long hSocket = socket(pAddrInfo->ai_family, SOCK_STREAM, IPPROTO_TCP);
333 if (hSocket == INVALID_SOCKET)
335 m_pConnectErrorStr =
"Failed to allocate a socket descriptor.";
336 freeaddrinfo(pAddrInfo);
340 rc = connect(hSocket, pAddrInfo->ai_addr, pAddrInfo->ai_addrlen);
341 if (rc == SOCKET_ERROR)
343 m_pConnectErrorStr =
"Failed to connect to host.";
344 freeaddrinfo(pAddrInfo);
349 freeaddrinfo(pAddrInfo);
365 int CConnection::initializeSslBio(BIO** ppBio)
368 long sslOptions = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
372 m_pConnectErrorStr =
"Internal parameter failure";
376 SSL_CTX* pSslCtx = SSL_CTX_new(SSLv23_method());
379 m_pConnectErrorStr =
"System SSL context failure";
383 SSL_CTX_set_verify(pSslCtx, SSL_VERIFY_NONE, NULL);
384 SSL_CTX_set_options(pSslCtx, sslOptions);
386 pBio = BIO_new_ssl(pSslCtx, 1);
387 SSL_CTX_free(pSslCtx);
390 m_pConnectErrorStr =
"System SSL socket allocation failure";
411 return m_pConnectErrorStr;
433 m_pConnectErrorStr =
"not connected";
437 BIO_get_ssl(m_pBio, pSsl);
440 BIO_ssl_shutdown(m_pBio);
443 BIO_free_all(m_pBio);
446 rc = shutdownWinsock();
490 if(NULL == pResponseType)
496 "send message has no response type");
518 return pResponseMessage;
571 CFrameEncoder frameEncoder(m_Send.pBuffer, m_nBufferSize);
590 frameEncoder.encodeElement(pMessage);
596 m_Send.ErrorDetails = frameEncoder.m_ErrorDetails;
597 m_Send.nBuffer = frameEncoder.getLength();
606 int rc = BIO_write(m_pBio, m_Send.pBuffer, (m_Send.nBuffer *
sizeof(llrp_byte_t)));
607 if(rc != (
int)m_Send.nBuffer)
633 return &m_Send.ErrorDetails;
661 time_t timeLimit = calculateTimeLimit(nMaxMS);
685 if(!m_listInputQueue.empty())
687 pMessage = m_listInputQueue.front();
688 m_listInputQueue.pop_front();
696 lrc = recvAdvance(nMaxMS, timeLimit);
718 return &m_Recv.ErrorDetails;
772 llrp_u32_t ResponseMessageID)
774 time_t timeLimit = calculateTimeLimit(nMaxMS);
805 std::list<CMessage *>::iterator msg = m_listInputQueue.begin();
806 msg != m_listInputQueue.end();
814 if(NULL != pResponseType)
820 if(pMessage->
m_pType != pResponseType &&
821 pMessage->
m_pType != pErrorMsgType)
831 if(0 != ResponseMessageID)
843 m_listInputQueue.remove(pMessage);
851 lrc = recvAdvance(nMaxMS, timeLimit);
899 CConnection::recvAdvance (
920 m_Recv.bFrameValid = FALSE;
940 m_Recv.FrameExtract = CFrameExtract(m_Recv.pBuffer, m_Recv.nBuffer);
945 if(CFrameExtract::FRAME_ERROR == m_Recv.FrameExtract.m_eStatus)
948 "framing error in message stream");
956 if(CFrameExtract::NEED_MORE == m_Recv.FrameExtract.m_eStatus)
958 unsigned int nRead = m_Recv.FrameExtract.m_nBytesNeeded;
959 unsigned char * pBufPos = &m_Recv.pBuffer[m_Recv.nBuffer];
967 if(time(NULL) > timeLimit)
980 if(m_Recv.nBuffer + nRead > m_nBufferSize)
993 fd_set readFdSet = {0};
994 timeval timeout = {0};
999 BIO_get_ssl(m_pBio, &pSsl);
1006 FD_ZERO(&readFdSet);
1007 timeout.tv_sec = nMaxMS / 1000u;
1008 timeout.tv_usec = (nMaxMS % 1000u) * 1000u;
1010 BIO_get_fd(m_pBio, &bioSocket);
1011 if (bioSocket == -1)
1017 FD_SET(bioSocket, &readFdSet);
1019 int rc = select((bioSocket+1), &readFdSet, NULL, NULL, &timeout);
1037 int rc = BIO_read(m_pBio, pBufPos, nRead);
1041 if ((0 == rc) && (!BIO_should_retry(m_pBio)))
1044 "connection closed by remote");
1055 m_Recv.nBuffer += rc;
1069 if(CFrameExtract::READY == m_Recv.FrameExtract.m_eStatus)
1074 CFrameDecoder decoder(m_pTypeRegistry, m_Recv.pBuffer, m_Recv.nBuffer);
1075 CMessage * pMessage;
1081 pMessage = decoder.decodeMessage();
1087 m_Recv.ErrorDetails = decoder.m_ErrorDetails;
1093 if(NULL == pMessage)
1101 "NULL message but no error");
1108 m_Recv.bFrameValid = FALSE;
1116 m_listInputQueue.push_back(pMessage);
1123 m_Recv.bFrameValid = TRUE;
1165 CConnection::calculateTimeLimit (
1171 return time(NULL) + 1;
1195 return time(NULL) + ((nMaxMS + 1999u) / 1000u);
1210 void CConnection::initializeOpenSSL()
1212 CRYPTO_malloc_init();
1220 SSL_load_error_strings();
1233 int CConnection::initializeWinsock()
1238 WSADATA winsockData = { 0 };
1239 rc = WSAStartup(MAKEWORD(2, 2), &winsockData);
1254 int CConnection::shutdownWinsock()
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.
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.
Based type descriptions for the LTKCPP library.
Classes to encode and decod LLRP binary frames.
EResultCode
Error result codes for LTK operations.
int closeConnectionToReader(void)
Close connection to reader, allow reuse of instance.
A collection of pointers to CTypeDescriptors.
const CErrorDetails * getTransactError(void)
Get the details that explains transact() error.
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...
EResultCode sendMessage(CMessage *pMessage)
Send a LLRP message to a connection.
Class to return error details in LTKCPP operations.
llrp_u32_t getMessageID(void) const
Gets the current LLRP Message ID for the Message.
Base Class for All LLRP LTK Messages.
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.
const CErrorDetails * getSendError(void)
Get the details that explains sendMessage() error.