Go to the documentation of this file.00001
00002
00003
00004
00005
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
00034 sendbuf[0] = 1;
00035
00036
00037 sendbuf[1] = _out_seqno; _out_seqno++;
00038
00039
00040 char *sendptr = ((char*)&sendbuf) + 2;
00041 ::memcpy(sendptr, buffer, length);
00042
00043
00044 if (__send_impl((char*)&sendbuf, length + 2) != 0)
00045 {
00046
00047 return -1;
00048 }
00049
00050
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
00060 _count++;
00061
00062
00063 if ((_maxretry > 0) && (_count > _maxretry))
00064 {
00065 return -1;
00066 }
00067
00068
00069 if (__send_impl((char*)&sendbuf, length + 2) != 0)
00070 {
00071
00072 return -1;
00073 }
00074 }
00075 else
00076 {
00077
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
00094 char msgtype = *bufferptr; bufferptr++;
00095
00096
00097 u_int8_t seqno = *bufferptr; bufferptr++;
00098
00099
00100 if (seqno > _in_seqno)
00101 {
00102 _in_seqno = seqno;
00103
00104 switch (msgtype)
00105 {
00106 case 1:
00107 {
00108 ::memcpy(buffer, bufferptr, length - 2);
00109 length -= 2;
00110 return ret;
00111 }
00112
00113 case 2:
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 }