IBR-DTNSuite
0.8
|
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 }