IBR-DTNSuite  0.10
stopandwait.cpp
Go to the documentation of this file.
1 /*
2  * stopandwait.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
24 #include <stdio.h>
25 #include <string.h>
26 #include <vector>
27 
28 namespace ibrcommon
29 {
30  stopandwait::stopandwait(const size_t timeout, const size_t maxretry)
31  : _maxretry(maxretry), _out_seqno(1), _in_seqno(0), _ack_seqno(0), _count(0), _timeout(timeout)
32  {
33  }
34 
36  {
37  }
38 
39  void stopandwait::setTimeout(size_t timeout)
40  {
41  _timeout = timeout;
42  }
43 
44  int stopandwait::__send(const char *buffer, const size_t length)
45  {
46  std::vector<char> sendbuf(length + 2);
47 
48  // set message type
49  sendbuf[0] = 1; // 1 = DATA
50 
51  // add sequence number
52  sendbuf[1] = _out_seqno; _out_seqno++;
53 
54  // copy the buffer
55  char *sendptr = ((char*)&sendbuf[0]) + 2;
56  ::memcpy(sendptr, buffer, length);
57 
58  // send the buffer
59  if (__send_impl((char*)&sendbuf[0], length + 2) != 0)
60  {
61  // ERROR!
62  return -1;
63  }
64 
65  // wait for ACK
66  ibrcommon::MutexLock l(_ack_cond);
67  while (_ack_seqno != _out_seqno)
68  {
69  try {
70  _ack_cond.wait(_timeout);
73  {
74  // retransmission
75  _count++;
76 
77  // abort if the number of retries exceeds the maximum number
78  if ((_maxretry > 0) && (_count > _maxretry))
79  {
80  return -1;
81  }
82 
83  // resend the message
84  if (__send_impl((char*)&sendbuf[0], length + 2) != 0)
85  {
86  // ERROR!
87  return -1;
88  }
89  }
90  else
91  {
92  // ERROR or ABORT
93  return -1;
94  }
95  }
96  }
97 
98  return 0;
99  }
100 
101  int stopandwait::__recv(char *buffer, size_t &length)
102  {
103  char *bufferptr = buffer;
104 
105  while (true)
106  {
107  int ret = __recv_impl(bufferptr, length);
108  if (ret != 0) return ret;
109 
110  // message type
111  char msgtype = *bufferptr; bufferptr++;
112 
113  // read seqnr
114  uint8_t seqno = *bufferptr; bufferptr++;
115 
116  // check for double received messages
117  if (seqno > _in_seqno)
118  {
119  _in_seqno = seqno;
120 
121  switch (msgtype)
122  {
123  case 1: // DATA
124  {
125  ::memcpy(buffer, bufferptr, length - 2);
126  length -= 2;
127  return ret;
128  }
129 
130  case 2: // ACK
131  {
132  ibrcommon::MutexLock l(_ack_cond);
133  _ack_seqno = seqno;
134  _ack_cond.signal(true);
135  break;
136  }
137  }
138  }
139  }
140 
141  return -1;
142  }
143 }