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 LLRPCLOSESOCKET(hSocket);
345 freeaddrinfo(pAddrInfo);
350 freeaddrinfo(pAddrInfo);
366 int CConnection::initializeSslBio(BIO** ppBio)
369 long sslOptions = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
373 m_pConnectErrorStr =
"Internal parameter failure";
377 SSL_CTX* pSslCtx = SSL_CTX_new(SSLv23_method());
380 m_pConnectErrorStr =
"System SSL context failure";
384 SSL_CTX_set_verify(pSslCtx, SSL_VERIFY_NONE, NULL);
385 SSL_CTX_set_options(pSslCtx, sslOptions);
387 pBio = BIO_new_ssl(pSslCtx, 1);
388 SSL_CTX_free(pSslCtx);
391 m_pConnectErrorStr =
"System SSL socket allocation failure";
412 return m_pConnectErrorStr;
434 m_pConnectErrorStr =
"not connected";
438 BIO_get_ssl(m_pBio, pSsl);
441 BIO_ssl_shutdown(m_pBio);
444 BIO_free_all(m_pBio);
447 rc = shutdownWinsock();
491 if(NULL == pResponseType)
497 "send message has no response type");
519 return pResponseMessage;
572 CFrameEncoder frameEncoder(m_Send.pBuffer, m_nBufferSize);
591 frameEncoder.encodeElement(pMessage);
597 m_Send.ErrorDetails = frameEncoder.m_ErrorDetails;
598 m_Send.nBuffer = frameEncoder.getLength();
607 int rc = BIO_write(m_pBio, m_Send.pBuffer, (m_Send.nBuffer *
sizeof(llrp_byte_t)));
608 if(rc != (
int)m_Send.nBuffer)
634 return &m_Send.ErrorDetails;
662 time_t timeLimit = calculateTimeLimit(nMaxMS);
686 if(!m_listInputQueue.empty())
688 pMessage = m_listInputQueue.front();
689 m_listInputQueue.pop_front();
697 lrc = recvAdvance(nMaxMS, timeLimit);
719 return &m_Recv.ErrorDetails;
773 llrp_u32_t ResponseMessageID)
775 time_t timeLimit = calculateTimeLimit(nMaxMS);
806 std::list<CMessage *>::iterator msg = m_listInputQueue.begin();
807 msg != m_listInputQueue.end();
815 if(NULL != pResponseType)
821 if(pMessage->
m_pType != pResponseType &&
822 pMessage->
m_pType != pErrorMsgType)
832 if(0 != ResponseMessageID)
844 m_listInputQueue.remove(pMessage);
852 lrc = recvAdvance(nMaxMS, timeLimit);
900 CConnection::recvAdvance (
921 m_Recv.bFrameValid = FALSE;
941 m_Recv.FrameExtract = CFrameExtract(m_Recv.pBuffer, m_Recv.nBuffer);
946 if(CFrameExtract::FRAME_ERROR == m_Recv.FrameExtract.m_eStatus)
949 "framing error in message stream");
957 if(CFrameExtract::NEED_MORE == m_Recv.FrameExtract.m_eStatus)
959 unsigned int nRead = m_Recv.FrameExtract.m_nBytesNeeded;
960 unsigned char * pBufPos = &m_Recv.pBuffer[m_Recv.nBuffer];
968 if(time(NULL) > timeLimit)
981 if(m_Recv.nBuffer + nRead > m_nBufferSize)
994 fd_set readFdSet = {0};
995 timeval timeout = {0};
1000 BIO_get_ssl(m_pBio, &pSsl);
1007 FD_ZERO(&readFdSet);
1008 timeout.tv_sec = nMaxMS / 1000u;
1009 timeout.tv_usec = (nMaxMS % 1000u) * 1000u;
1011 BIO_get_fd(m_pBio, &bioSocket);
1012 if (bioSocket == -1)
1018 FD_SET(bioSocket, &readFdSet);
1020 int rc = select((bioSocket+1), &readFdSet, NULL, NULL, &timeout);
1038 int rc = BIO_read(m_pBio, pBufPos, nRead);
1042 if ((0 == rc) && (!BIO_should_retry(m_pBio)))
1045 "connection closed by remote");
1056 m_Recv.nBuffer += rc;
1070 if(CFrameExtract::READY == m_Recv.FrameExtract.m_eStatus)
1075 CFrameDecoder decoder(m_pTypeRegistry, m_Recv.pBuffer, m_Recv.nBuffer);
1076 CMessage * pMessage;
1082 pMessage = decoder.decodeMessage();
1088 m_Recv.ErrorDetails = decoder.m_ErrorDetails;
1094 if(NULL == pMessage)
1102 "NULL message but no error");
1109 m_Recv.bFrameValid = FALSE;
1117 m_listInputQueue.push_back(pMessage);
1124 m_Recv.bFrameValid = TRUE;
1166 CConnection::calculateTimeLimit (
1172 return time(NULL) + 1;
1196 return time(NULL) + ((nMaxMS + 1999u) / 1000u);
1211 void CConnection::initializeOpenSSL()
1213 CRYPTO_malloc_init();
1221 SSL_load_error_strings();
1234 int CConnection::initializeWinsock()
1239 WSADATA winsockData = { 0 };
1240 rc = WSAStartup(MAKEWORD(2, 2), &winsockData);
1255 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.