IBR-DTNSuite  0.8
ibrcommon/ibrcommon/net/stopandwait.cpp
Go to the documentation of this file.
00001 /*
00002  * stopandwait.cpp
00003  *
00004  *  Created on: 08.11.2010
00005  *      Author: morgenro
00006  */
00007 
00008 #include "ibrcommon/net/stopandwait.h"
00009 #include <ibrcommon/thread/MutexLock.h>
00010 #include <stdio.h>
00011 #include <string.h>
00012 
00013 namespace ibrcommon
00014 {
00015         stopandwait::stopandwait(const size_t timeout, const size_t maxretry)
00016          : _maxretry(maxretry), _out_seqno(1), _in_seqno(0), _ack_seqno(0), _count(0), _timeout(timeout)
00017         {
00018         }
00019 
00020         stopandwait::~stopandwait()
00021         {
00022         }
00023 
00024         void stopandwait::setTimeout(size_t timeout)
00025         {
00026                 _timeout = timeout;
00027         }
00028 
00029         int stopandwait::__send(const char *buffer, const size_t length)
00030         {
00031                 char sendbuf[length + 2];
00032 
00033                 // set message type
00034                 sendbuf[0] = 1;         // 1 = DATA
00035 
00036                 // add sequence number
00037                 sendbuf[1] = _out_seqno; _out_seqno++;
00038 
00039                 // copy the buffer
00040                 char *sendptr = ((char*)&sendbuf) + 2;
00041                 ::memcpy(sendptr, buffer, length);
00042 
00043                 // send the buffer
00044                 if (__send_impl((char*)&sendbuf, length + 2) != 0)
00045                 {
00046                         // ERROR!
00047                         return -1;
00048                 }
00049 
00050                 // wait for ACK
00051                 ibrcommon::MutexLock l(_ack_cond);
00052                 while (_ack_seqno != _out_seqno)
00053                 {
00054                         try {
00055                                 _ack_cond.wait(_timeout);
00056                         } catch (const ibrcommon::Conditional::ConditionalAbortException &ex) {
00057                                 if (ex.reason == ibrcommon::Conditional::ConditionalAbortException::COND_TIMEOUT)
00058                                 {
00059                                         // retransmission
00060                                         _count++;
00061 
00062                                         // abort if the number of retries exceeds the maximum number
00063                                         if ((_maxretry > 0) && (_count > _maxretry))
00064                                         {
00065                                                 return -1;
00066                                         }
00067 
00068                                         // resend the message
00069                                         if (__send_impl((char*)&sendbuf, length + 2) != 0)
00070                                         {
00071                                                 // ERROR!
00072                                                 return -1;
00073                                         }
00074                                 }
00075                                 else
00076                                 {
00077                                         // ERROR or ABORT
00078                                         return -1;
00079                                 }
00080                         }
00081                 }
00082         }
00083 
00084         int stopandwait::__recv(char *buffer, size_t &length)
00085         {
00086                 char *bufferptr = buffer;
00087 
00088                 while (true)
00089                 {
00090                         int ret = __recv_impl(bufferptr, length);
00091                         if (ret != 0) return ret;
00092 
00093                         // message type
00094                         char msgtype = *bufferptr; bufferptr++;
00095 
00096                         // read seqnr
00097                         u_int8_t seqno = *bufferptr; bufferptr++;
00098 
00099                         // check for double received messages
00100                         if (seqno > _in_seqno)
00101                         {
00102                                 _in_seqno = seqno;
00103 
00104                                 switch (msgtype)
00105                                 {
00106                                         case 1:         // DATA
00107                                         {
00108                                                 ::memcpy(buffer, bufferptr, length - 2);
00109                                                 length -= 2;
00110                                                 return ret;
00111                                         }
00112 
00113                                         case 2:         // ACK
00114                                         {
00115                                                 ibrcommon::MutexLock l(_ack_cond);
00116                                                 _ack_seqno = seqno;
00117                                                 _ack_cond.signal(true);
00118                                                 break;
00119                                         }
00120                                 }
00121                         }
00122                 }
00123 
00124                 return -1;
00125         }
00126 }