ltkcpp_connection.cpp

Go to the documentation of this file.
00001 
00002 /*
00003  *****************************************************************************
00004  *                                                                           *
00005  *                 IMPINJ CONFIDENTIAL AND PROPRIETARY                       *
00006  *                                                                           *
00007  * This source code is the sole property of Impinj, Inc.  Reproduction or    *
00008  * utilization of this source code in whole or in part is forbidden without  *
00009  * the prior written consent of Impinj, Inc.                                 *
00010  *                                                                           *
00011  * (c) Copyright Impinj, Inc. 2007,2008. All rights reserved.                *
00012  *                                                                           *
00013  *****************************************************************************/
00014 
00033 #include <assert.h>
00034 
00035 
00036 #ifdef linux
00037 #include <poll.h>
00038 #include <unistd.h>
00039 #include <errno.h>
00040 #include <sys/types.h>
00041 #include <sys/socket.h>
00042 #include <netinet/in.h>
00043 #include <netinet/tcp.h>
00044 #include <arpa/inet.h>
00045 #include <unistd.h>
00046 #include <netdb.h>
00047 #include <fcntl.h>
00048 #include <time.h>
00049 #endif
00050 #ifdef WIN32
00051 #define WIN32_LEAN_AND_MEAN
00052 #include <windows.h>
00053 #include <winsock2.h>
00054 #include <ws2tcpip.h>
00055 #include <time.h>
00056 #endif
00057 
00058 #include "ltkcpp_platform.h"
00059 #include "ltkcpp_base.h"
00060 #include "ltkcpp_frame.h"
00061 #include "ltkcpp_connection.h"
00062 
00063 
00064 #define LLRP1_TCP_PORT   (5084u)
00065 
00066 
00067 namespace LLRP
00068 {
00069 
00070 /*
00071  * On Linux a socket is a simple type (int). On Windows it
00072  * is a pointer to a specific type defined in a WinSock
00073  * header (.h) file. Rather than make that header file a
00074  * prerequisite to every source file that includes this header
00075  * file (ltkcpp_connection.h), the following CPlatformSocket
00076  * class opaquely wraps the platform-specific socket.
00077  *
00078  * The CConnection class references it by pointer only.
00079  * The content of the CPlatformSocket is only known
00080  * within the implementation of CConnection.
00081  */
00082 #ifdef linux
00083 class CPlatformSocket
00084 {
00085   public:
00086     int                         m_sock;
00087 
00088     CPlatformSocket(int sock);
00089 };
00090 
00091 CPlatformSocket::CPlatformSocket (int sock)
00092 {
00093     m_sock = sock;
00094 }
00095 
00096 #endif
00097 #ifdef WIN32
00098 class CPlatformSocket
00099 {
00100   public:
00101     SOCKET                      m_sock;
00102 
00103     CPlatformSocket(SOCKET sock);
00104 };
00105 
00106 CPlatformSocket::CPlatformSocket (SOCKET sock)
00107 {
00108     m_sock = sock;
00109 }
00110 
00111 #endif
00112 
00113 
00132 CConnection::CConnection (
00133   const CTypeRegistry *         pTypeRegistry,
00134   unsigned int                  nBufferSize)
00135 {
00136     /*
00137      * Apply default buffer size
00138      */
00139     if(0 == nBufferSize)
00140     {
00141         nBufferSize = 128u*1024u;
00142     }
00143 
00144     /*
00145      * Make sure the buffer size is sane. This is arbitrary.
00146      * The smallest message is 10 bytes, but it ain't anything
00147      * useful. 1024u covers a surprising number of messages.
00148      */
00149     if(1024u > nBufferSize || 1u*1024u*1024u < nBufferSize)
00150     {
00151         throw "Insane buffer size";
00152     }
00153 
00154     /*
00155      * Capture variables. m_pPlatformSocket=NULL indicates there
00156      * is no connection yet.
00157      */
00158     m_pPlatformSocket = NULL;
00159     m_pTypeRegistry = pTypeRegistry;
00160     m_nBufferSize = nBufferSize;
00161 
00162     memset(&m_Recv, 0, sizeof m_Recv);
00163     memset(&m_Send, 0, sizeof m_Send);
00164 
00165     /*
00166      * Allocate and check each the recv and send buffers.
00167      */
00168     m_Recv.pBuffer = new llrp_byte_t[nBufferSize];
00169     m_Send.pBuffer = new llrp_byte_t[nBufferSize];
00170 
00171     /*
00172      * Zero-fill buffers just so debugger printing is tidy
00173      */
00174     memset(m_Recv.pBuffer, 0, nBufferSize);
00175     memset(m_Send.pBuffer, 0, nBufferSize);
00176 
00177 #ifdef WIN32
00178     /*
00179      * On Windows have to enable the WinSock library
00180      */
00181     {
00182         WSADATA SocketLibraryInitData;
00183         WSAStartup(0xFFFF, &SocketLibraryInitData);
00184     }
00185 #endif
00186 
00187     /*
00188      * Victory
00189      */
00190 }
00191 
00192 
00200 CConnection::~CConnection (void)
00201 {
00202     /*
00203      * Close the connection, if one
00204      */
00205     closeConnectionToReader();
00206 
00207     /*
00208      * Destruct any messages on the input queue
00209      */
00210     for (
00211         std::list<CMessage *>::iterator msg = m_listInputQueue.begin();
00212         msg != m_listInputQueue.end();
00213         msg++)
00214     {
00215         delete *msg;
00216     }
00217 
00218     /*
00219      * free each the receive and send bufers
00220      */
00221     delete[] m_Recv.pBuffer;
00222     delete[] m_Send.pBuffer;
00223 
00224 #ifdef WIN32
00225     /*
00226      * On Windows have to disable (dereference) the WinSock library
00227      */
00228     {
00229         WSACleanup();
00230     }
00231 #endif
00232 
00233 }
00234 
00235 
00254 int
00255 CConnection::openConnectionToReader (
00256   const char *                  pReaderHostName)
00257 {
00258 #ifdef linux
00259     int                         Sock;
00260 #endif
00261 #ifdef WIN32
00262     SOCKET                      Sock;
00263 #endif
00264     struct addrinfo             aiHints;
00265     struct addrinfo *           aiList;
00266     int                         Flag;
00267     struct sockaddr_in          Sin;
00268     int                         rc;
00269 
00270     /*
00271      * Clear the connect error string
00272      */
00273     m_pConnectErrorStr = NULL;
00274 
00275     /*
00276      * Make sure there isn't already a connection.
00277      */
00278     if(NULL != m_pPlatformSocket)
00279     {
00280         m_pConnectErrorStr = "already connected";
00281         return -1;
00282     }
00283 
00284     /*
00285      * Look up host using getaddrinfo().
00286      * This could be configured a lot of different ways.
00287      * There is /etc/hosts, DNS, NIS, etc, etc.
00288      * Suffice to say it is big, bulky, and susceptible to stall.
00289      */
00290     memset(&aiHints, 0, sizeof(aiHints));
00291     aiHints.ai_family = AF_INET;
00292     aiList = NULL;
00293 
00294     rc = getaddrinfo(pReaderHostName, NULL, &aiHints, &aiList);
00295     if(0 != rc)
00296     {
00297         m_pConnectErrorStr = "host lookup failed";
00298         return -1;
00299     }
00300 
00301     /*
00302      * Convert the address to sockaddr_in format
00303      */
00304     memset(&Sin, 0, sizeof Sin);
00305     Sin.sin_family = AF_INET;
00306     Sin.sin_addr = ((struct sockaddr_in *)(aiList->ai_addr))->sin_addr;
00307     Sin.sin_port = htons(LLRP1_TCP_PORT);
00308 
00309     /*
00310      * Done withe the host addrinfo
00311      */
00312     freeaddrinfo(aiList);
00313 
00314     /*
00315      * Create the socket.
00316      */
00317     Sock = socket(AF_INET, SOCK_STREAM, 0);
00318 #ifdef linux
00319     if(0 > Sock)
00320 #endif /* linux */
00321 #ifdef WIN32
00322     if(NULL == Sock)
00323 #endif /* WIN32 */
00324     {
00325         m_pConnectErrorStr = "socket() failed";
00326         return -3;
00327     }
00328 
00329     /*
00330      * Connect the socket to reader. This can stall.
00331      */
00332     rc = connect(Sock, (struct sockaddr *)&Sin, sizeof Sin);
00333     if(0 > rc)
00334     {
00335         /* Connect failed */
00336         m_pConnectErrorStr = "connection failed";
00337 #ifdef linux
00338         close(Sock);
00339 #endif
00340 #ifdef WIN32
00341         closesocket(Sock);
00342 #endif
00343         return -4;
00344     }
00345 
00346     /*
00347      * Best effort to set no delay. If this doesn't work
00348      * (no reason it shouldn't) we do not declare defeat.
00349      */
00350     Flag = 1;
00351 
00352 #ifdef linux
00353     setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, (void*)&Flag, sizeof Flag);
00354 #endif
00355 #ifdef WIN32
00356     setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, (char*)&Flag, sizeof Flag);
00357 #endif
00358 
00359     /*
00360      * Wrap the platform-specific socket in the platform-specific class.
00361      */
00362     m_pPlatformSocket = new CPlatformSocket(Sock);
00363 
00364     /*
00365      * Victory
00366      */
00367     return 0;
00368 }
00369 
00370 
00381 const char *
00382 CConnection::getConnectError (void)
00383 {
00384     return m_pConnectErrorStr;
00385 }
00386 
00387 
00398 int
00399 CConnection::closeConnectionToReader (void)
00400 {
00401     if(NULL == m_pPlatformSocket)
00402     {
00403         m_pConnectErrorStr = "not connected";
00404         return -1;
00405     }
00406 
00407 #ifdef linux
00408     shutdown(m_pPlatformSocket->m_sock, SHUT_RDWR);
00409     close(m_pPlatformSocket->m_sock);
00410     m_pPlatformSocket->m_sock = -1;
00411 #endif
00412 #ifdef WIN32
00413     closesocket(m_pPlatformSocket->m_sock);
00414     m_pPlatformSocket->m_sock = NULL;
00415 #endif
00416 
00417     delete m_pPlatformSocket;
00418     m_pPlatformSocket = NULL;
00419     return 0;
00420 }
00421 
00422 
00445 CMessage *
00446 CConnection::transact (
00447   CMessage *                    pSendMessage,
00448   int                           nMaxMS)
00449 {
00450     const CTypeDescriptor *     pResponseType;
00451     EResultCode                 lrc;
00452     CMessage *                  pResponseMessage;
00453 
00454     /*
00455      * Determine the response type. The type descriptor
00456      * of the outgoing request message points to the
00457      * type descriptor of the response. Since we are
00458      * totally dependent upon it, fail if there
00459      * is no response type pointer value.
00460      */
00461     pResponseType = pSendMessage->m_pType->m_pResponseType;
00462     if(NULL == pResponseType)
00463     {
00464         CErrorDetails *         pError = &m_Send.ErrorDetails;
00465 
00466         pError->clear();
00467         pError->resultCodeAndWhatStr(RC_MissingResponseType,
00468             "send message has no response type");
00469         return NULL;
00470     }
00471 
00472     /*
00473      * Send the request
00474      */
00475     lrc = sendMessage(pSendMessage);
00476     if(RC_OK != lrc)
00477     {
00478         return NULL;
00479     }
00480 
00481     /*
00482      * Receive the response subject to timeout
00483      */
00484     pResponseMessage = recvResponse(nMaxMS,
00485                             pResponseType, pSendMessage->getMessageID());
00486 
00487     /*
00488      * Whatever recvResponse() returned is the result.
00489      */
00490     return pResponseMessage;
00491 }
00492 
00493 
00508 const CErrorDetails *
00509 CConnection::getTransactError (void)
00510 {
00511     const CErrorDetails *       pError;
00512 
00513     pError = getSendError();
00514     if(RC_OK == pError->m_eResultCode)
00515     {
00516         pError = getRecvError();
00517     }
00518 
00519     return pError;
00520 }
00521 
00522 
00538 EResultCode
00539 CConnection::sendMessage (
00540   CMessage *                    pMessage)
00541 {
00542     CErrorDetails *             pError = &m_Send.ErrorDetails;
00543     CFrameEncoder *             pEncoder;
00544 
00545     /*
00546      * Clear the error details in the send state.
00547      */
00548     pError->clear();
00549 
00550     /*
00551      * Make sure the socket is open.
00552      */
00553     if(NULL == m_pPlatformSocket)
00554     {
00555         pError->resultCodeAndWhatStr(RC_MiscError, "not connected");
00556         return pError->m_eResultCode;
00557     }
00558 
00559     /*
00560      * Construct a frame encoder. It needs to know the buffer
00561      * base and maximum size.
00562      */
00563     pEncoder = new CFrameEncoder(m_Send.pBuffer, m_nBufferSize);
00564 
00565     /*
00566      * Check that the encoder actually got created.
00567      */
00568     if(NULL == pEncoder)
00569     {
00570         pError->resultCodeAndWhatStr(RC_MiscError,
00571                 "encoder constructor failed");
00572         return pError->m_eResultCode;
00573     }
00574 
00575     /*
00576      * Encode the message. Return value is ignored.
00577      * We check the encoder's ErrorDetails for results.
00578      */
00579     pEncoder->encodeElement(pMessage);
00580 
00581     /*
00582      * Regardless of what happened capture the error details
00583      * and the number of bytes placed in the buffer.
00584      */
00585     m_Send.ErrorDetails = pEncoder->m_ErrorDetails;
00586     m_Send.nBuffer = pEncoder->getLength();
00587 
00588     /*
00589      * Bye bye li'l encoder.
00590      */
00591     delete pEncoder;
00592 
00593     /*
00594      * If the encoding appears complete write the frame
00595      * to the connection. NB: this is not ready for
00596      * non-blocking I/O (EWOULDBLOCK).
00597      */
00598     if(RC_OK == pError->m_eResultCode)
00599     {
00600         int             rc;
00601 
00602         rc = send(m_pPlatformSocket->m_sock, (char*)m_Send.pBuffer,
00603             m_Send.nBuffer, 0);
00604         if(rc != (int)m_Send.nBuffer)
00605         {
00606             /* Yikes! */
00607             pError->resultCodeAndWhatStr(RC_SendIOError, "send IO error");
00608         }
00609     }
00610 
00611     /*
00612      * Done.
00613      */
00614     return pError->m_eResultCode;
00615 }
00616 
00617 
00627 const CErrorDetails *
00628 CConnection::getSendError (void)
00629 {
00630     return &m_Send.ErrorDetails;
00631 }
00632 
00633 
00654 CMessage *
00655 CConnection::recvMessage (
00656   int                           nMaxMS)
00657 {
00658     time_t                      timeLimit = calculateTimeLimit(nMaxMS);
00659     EResultCode                 lrc;
00660     CMessage *                  pMessage;
00661 
00662     /*
00663      * Make sure the socket is open.
00664      */
00665     if(NULL == m_pPlatformSocket)
00666     {
00667         CErrorDetails *         pError = &m_Recv.ErrorDetails;
00668 
00669         pError->resultCodeAndWhatStr(RC_MiscError, "not connected");
00670         return NULL;
00671     }
00672 
00673     /*
00674      * Loop until victory or some sort of exception happens
00675      */
00676     for(;;)
00677     {
00678         /*
00679          * Check the input queue to see if there is already
00680          * a message pending.
00681          */
00682         if(!m_listInputQueue.empty())
00683         {
00684             pMessage = m_listInputQueue.front();
00685             m_listInputQueue.pop_front();
00686             return pMessage;
00687         }
00688 
00689         /*
00690          * No message available. Advance the receiver state
00691          * and see if a message is produced.
00692          */
00693         lrc = recvAdvance(nMaxMS, timeLimit);
00694         if(lrc != RC_OK)
00695         {
00696             return NULL;
00697         }
00698     }
00699 }
00700 
00701 
00712 const CErrorDetails *
00713 CConnection::getRecvError (void)
00714 {
00715     return &m_Recv.ErrorDetails;
00716 }
00717 
00718 
00765 CMessage *
00766 CConnection::recvResponse (
00767   int                           nMaxMS,
00768   const CTypeDescriptor *       pResponseType,
00769   llrp_u32_t                    ResponseMessageID)
00770 {
00771     time_t                      timeLimit = calculateTimeLimit(nMaxMS);
00772     const CTypeDescriptor *     pErrorMsgType;
00773     EResultCode                 lrc;
00774     CMessage *                  pMessage;
00775 
00776     /*
00777      * Make sure the socket is open.
00778      */
00779     if(NULL == m_pPlatformSocket)
00780     {
00781         CErrorDetails *         pError = &m_Recv.ErrorDetails;
00782 
00783         pError->resultCodeAndWhatStr(RC_MiscError, "not connected");
00784         return NULL;
00785     }
00786 
00787     /*
00788      * Look up the ERROR_MESSAGE type descriptor now.
00789      */
00790     pErrorMsgType = m_pTypeRegistry->lookupMessage(100u);
00791 
00792     /*
00793      * Loop until victory or some sort of exception happens
00794      */
00795     for(;;)
00796     {
00797         /*
00798          * Check the input queue to see if the sought
00799          * message is present.
00800          */
00801         for (
00802             std::list<CMessage *>::iterator msg = m_listInputQueue.begin();
00803             msg != m_listInputQueue.end();
00804             msg++)
00805         {
00806             pMessage = *msg;
00807 
00808             /*
00809              * Are we looking for a particular message type?
00810              */
00811             if(NULL != pResponseType)
00812             {
00813                 /*
00814                  * See if it is the sought response type or
00815                  * an ERROR_MESSAGE.
00816                  */
00817                 if(pMessage->m_pType != pResponseType &&
00818                    pMessage->m_pType != pErrorMsgType)
00819                 {
00820                     /* Type does not match. Keep looking. */
00821                     continue;
00822                 }
00823             }
00824 
00825             /*
00826              * Are we looking for a particular message ID?
00827              */
00828             if(0 != ResponseMessageID)
00829             {
00830                 if(pMessage->getMessageID() != ResponseMessageID)
00831                 {
00832                     /* Message ID does not match. Keep looking. */
00833                     continue;
00834                 }
00835             }
00836 
00837             /*
00838              * Found it. Unlink it from the queue and return it.
00839              */
00840             m_listInputQueue.remove(pMessage);
00841             return pMessage;
00842         }
00843 
00844         /*
00845          * Sought message is not in the queue. Advance the
00846          * receiver state and see if the message is produced.
00847          */
00848         lrc = recvAdvance(nMaxMS, timeLimit);
00849         if(lrc != RC_OK)
00850         {
00851             return NULL;
00852         }
00853 
00854         /*
00855          * Loop to the top and try again.
00856          */
00857     }
00858 }
00859 
00860 
00895 EResultCode
00896 CConnection::recvAdvance (
00897   int                           nMaxMS,
00898   time_t                        timeLimit)
00899 {
00900     CErrorDetails *             pError = &m_Recv.ErrorDetails;
00901 
00902     /*
00903      * Clear the error details in the receiver state.
00904      */
00905     pError->clear();
00906 
00907     /*
00908      * Loop until victory or some sort of exception happens
00909      */
00910     for(;;)
00911     {
00912         int                     rc;
00913 
00914         /*
00915          * Note that the frame is in progress.
00916          * Existing buffer content, if any, is deemed
00917          * invalid or incomplete.
00918          */
00919         m_Recv.bFrameValid = FALSE;
00920 
00921         /*
00922          * Check to see if we have a frame in the buffer.
00923          * If not, how many more bytes do we need?
00924          *
00925          * LLRP_FrameExtract() status
00926          *
00927          * FRAME_ERROR          Impossible situation, like message
00928          *                      length too small or the like.
00929          *                      Recovery in this situation is
00930          *                      unlikely and probably the app
00931          *                      should drop the connection.
00932          *
00933          * FRAME_READY          Frame is complete. Details are
00934          *                      available for pre-decode decisions.
00935          *
00936          * FRAME_NEED_MORE      Need more input bytes to finish the frame.
00937          *                      The m_nBytesNeeded field is how many more.
00938          */
00939         m_Recv.FrameExtract = CFrameExtract(m_Recv.pBuffer, m_Recv.nBuffer);
00940 
00941         /*
00942          * Framing error?
00943          */
00944         if(CFrameExtract::FRAME_ERROR == m_Recv.FrameExtract.m_eStatus)
00945         {
00946             pError->resultCodeAndWhatStr(RC_RecvFramingError,
00947                     "framing error in message stream");
00948             break;
00949         }
00950 
00951         /*
00952          * Need more bytes? extractRc>0 means we do and extractRc is the
00953          * number of bytes immediately required.
00954          */
00955         if(CFrameExtract::NEED_MORE == m_Recv.FrameExtract.m_eStatus)
00956         {
00957             unsigned int        nRead = m_Recv.FrameExtract.m_nBytesNeeded;
00958             unsigned char *     pBufPos = &m_Recv.pBuffer[m_Recv.nBuffer];
00959 
00960             /*
00961              * Before we do anything that might block,
00962              * check to see if the time limit is exceeded.
00963              */
00964             if(0 != timeLimit)
00965             {
00966                 if(time(NULL) > timeLimit)
00967                 {
00968                     /* Timeout */
00969                     pError->resultCodeAndWhatStr(RC_RecvTimeout,
00970                             "timeout");
00971                     break;
00972                 }
00973             }
00974 
00975             /*
00976              * The frame extractor needs more data, make sure the
00977              * frame size fits in the receive buffer.
00978              */
00979             if(m_Recv.nBuffer + nRead > m_nBufferSize)
00980             {
00981                 pError->resultCodeAndWhatStr(RC_RecvBufferOverflow,
00982                         "buffer overflow");
00983                 break;
00984             }
00985 
00986             /*
00987              * If this is not a block indefinitely request use poll()
00988              * to see if there is data in time.
00989              */
00990             if(nMaxMS >= 0)
00991             {
00992 #ifdef linux
00993                 struct pollfd   pfd;
00994 
00995                 pfd.fd = m_pPlatformSocket->m_sock;
00996                 pfd.events = POLLIN;
00997                 pfd.revents = 0;
00998 
00999                 rc = poll(&pfd, 1, nMaxMS);
01000 #endif /* linux */
01001 #ifdef WIN32
01002                 fd_set          readfds;
01003                 struct timeval  timeout;
01004 
01005                 timeout.tv_sec = nMaxMS / 1000u;
01006                 timeout.tv_usec = (nMaxMS % 1000u) * 1000u;
01007 
01008                 FD_ZERO(&readfds);
01009                 FD_SET(m_pPlatformSocket->m_sock, &readfds);
01010                 rc = select(-1, &readfds, NULL, NULL, &timeout);
01011 
01012 #endif /* WIN32 */
01013                 if(0 > rc)
01014                 {
01015                     /* Error */
01016                     pError->resultCodeAndWhatStr(RC_RecvIOError,
01017                             "poll failed");
01018                     break;
01019                 }
01020                 if(0 == rc)
01021                 {
01022                     /* Timeout */
01023                     pError->resultCodeAndWhatStr(RC_RecvTimeout,
01024                             "timeout");
01025                     break;
01026                 }
01027             }
01028 
01029             /*
01030              * Read (recv) some number of bytes from the socket.
01031              */
01032             rc = recv(m_pPlatformSocket->m_sock, (char*)pBufPos, nRead, 0);
01033             if(0 > rc)
01034             {
01035                 /*
01036                  * Error. Note this could be EWOULDBLOCK if the
01037                  * file descriptor is using non-blocking I/O.
01038                  * So we return the error but do not tear-up
01039                  * the receiver state.
01040                  */
01041                 pError->resultCodeAndWhatStr(RC_RecvIOError,
01042                         "recv IO error");
01043                 break;
01044             }
01045 
01046             if(0 == rc)
01047             {
01048                 /* EOF */
01049                 pError->resultCodeAndWhatStr(RC_RecvEOF,
01050                         "recv end-of-file");
01051                 break;
01052             }
01053 
01054             /*
01055              * When we get here, rc>0 meaning some bytes were read.
01056              * Update the number of bytes present.
01057              * Then loop to the top and retry the FrameExtract().
01058              */
01059             m_Recv.nBuffer += rc;
01060 
01061             continue;
01062         }
01063 
01064         /*
01065          * Is the frame ready?
01066          * If a valid frame is present, decode and enqueue it.
01067          */
01068         if(CFrameExtract::READY == m_Recv.FrameExtract.m_eStatus)
01069         {
01070             /*
01071              * Frame appears complete. Time to try to decode it.
01072              */
01073             CFrameDecoder *     pDecoder;
01074             CMessage *          pMessage;
01075 
01076             /*
01077              * Construct a new frame decoder. It needs the registry
01078              * to facilitate decoding.
01079              */
01080             pDecoder = new CFrameDecoder(m_pTypeRegistry,
01081                     m_Recv.pBuffer, m_Recv.nBuffer);
01082 
01083             /*
01084              * Make sure we really got one. If not, weird problem.
01085              */
01086             if(pDecoder == NULL)
01087             {
01088                 /* All we can do is discard the frame. */
01089                 m_Recv.nBuffer = 0;
01090                 m_Recv.bFrameValid = FALSE;
01091                 pError->resultCodeAndWhatStr(RC_MiscError,
01092                         "decoder constructor failed");
01093                 break;
01094             }
01095 
01096             /*
01097              * Now ask the nice, brand new decoder to decode the frame.
01098              * It returns NULL for some kind of error.
01099              */
01100             pMessage = pDecoder->decodeMessage();
01101 
01102             /*
01103              * Always capture the error details even when it works.
01104              * Whatever happened, we are done with the decoder.
01105              */
01106             m_Recv.ErrorDetails = pDecoder->m_ErrorDetails;
01107 
01108             /*
01109              * Bye bye and thank you li'l decoder.
01110              */
01111             delete pDecoder;
01112 
01113             /*
01114              * If NULL there was an error. Clean up the
01115              * receive state. Return the error.
01116              */
01117             if(NULL == pMessage)
01118             {
01119                 /*
01120                  * Make sure the return is not RC_OK
01121                  */
01122                 if(RC_OK == pError->m_eResultCode)
01123                 {
01124                     pError->resultCodeAndWhatStr(RC_MiscError,
01125                             "NULL message but no error");
01126                 }
01127 
01128                 /*
01129                  * All we can do is discard the frame.
01130                  */
01131                 m_Recv.nBuffer = 0;
01132                 m_Recv.bFrameValid = FALSE;
01133 
01134                 break;
01135             }
01136 
01137             /*
01138              * Yay! It worked. Enqueue the message.
01139              */
01140             m_listInputQueue.push_back(pMessage);
01141 
01142             /*
01143              * Note that the frame is valid. Consult
01144              * Recv.FrameExtract.m_MessageLength.
01145              * Clear the buffer count to be ready for next time.
01146              */
01147             m_Recv.bFrameValid = TRUE;
01148             m_Recv.nBuffer = 0;
01149 
01150             break;
01151         }
01152 
01153         /*
01154          * If we get here there was an FrameExtract status
01155          * we didn't expect.
01156          */
01157 
01158         /*NOTREACHED*/
01159         assert(0);
01160     }
01161 
01162     return pError->m_eResultCode;
01163 }
01164 
01165 
01188 time_t
01189 CConnection::calculateTimeLimit (
01190   int                           nMaxMS)
01191 {
01192     if(0 == nMaxMS)
01193     {
01194         /* When just peeking, try for at most one second */
01195         return time(NULL) + 1;
01196     }
01197     else if(0 < nMaxMS)
01198     {
01199         /*
01200          * Try for a at most a certain period of time.
01201          *
01202          * timeLimit = now + ceil(nMaxMS/1000) + 1
01203          *
01204          * The last +1 compensates for not knowing
01205          * when the next time() tick will happen.
01206          *
01207          * For example, if now is SECONDS.999 seconds
01208          * the next tick will happen in 1 millisecond.
01209          * Suppose nMaxMS is 500ms (1/2 second).
01210          * Even rounding 500ms up to 1 second, the
01211          * time limit without the +1 would be
01212          * SECONDS+1 -- 1ms away. That's too soon.
01213          *
01214          * The extra +1 makes the maximum timeout
01215          * longer than required. But the timeLimit
01216          * is a safeguard anyway and usually the
01217          * timeout will occur when the user wants.
01218          */
01219         return time(NULL) + ((nMaxMS + 1999u) / 1000u);
01220     }
01221     else
01222     {
01223         /* Try indefinitely */
01224         return 0;
01225     }
01226 }
01227 
01228 }; /* namespace LLRP */
01229 

Generated on Wed Jun 6 11:55:49 2012 for LTKCPP-- LLRP Toolkit C Plus Plus Library by  doxygen 1.5.9