Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

ltkcpp_connection.cpp

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

Generated on Wed Nov 26 12:27:44 2008 for LTKCPP-- LLRP Toolkit C Plus Plus Library by  doxygen 1.3.9.1