IBR-DTNSuite  0.10
lowpanstream.cpp
Go to the documentation of this file.
1 /*
2  * lowpanstream.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 
22 #include "ibrcommon/config.h"
24 
25 #include "ibrcommon/Logger.h"
27 
28 #include <signal.h>
29 #include <string.h>
30 #include <math.h>
31 
32 /* Header:
33  * +---------------+
34  * |7 6 5 4 3 2 1 0|
35  * +---------------+
36  * Bit 7-6: 00 to be compatible with 6LoWPAN
37  * Bit 5-4: 00 Middle segment
38  * 01 Last segment
39  * 10 First segment
40  * 11 First and last segment
41  * Bit 3: 0 Extended frame not available
42  * 1 Extended frame available
43  * Bit 2-0: sequence number (0-7)
44  *
45  * Extended header (only if extended frame available)
46  * +---------------+
47  * |7 6 5 4 3 2 1 0|
48  * +---------------+
49  * Bit 7: 0 No discovery frame
50  * 1 Discovery frame
51  * Bit 6-0: Reserved
52  *
53  * Two bytes at the end of the frame are reserved for the short address of the
54  * sender. This is a workaround until recvfrom() gets fixed.
55  */
56 #define SEGMENT_FIRST 0x20
57 #define SEGMENT_LAST 0x10
58 //#define SEGMENT_BOTH 0x30
59 #define SEGMENT_MIDDLE 0x00
60 
61 #define SEQ_NUM_MASK 0x07
62 
63 namespace ibrcommon
64 {
66  std::iostream(this), _address(address), _in_first_segment(true), _out_stat(SEGMENT_FIRST), in_buf_(BUFF_SIZE),
67  in_buf_len(0), in_buf_free(true), out_buf_(BUFF_SIZE+2), out2_buf_(BUFF_SIZE),
68  in_seq_num_(0), out_seq_num_(0), out_seq_num_global(0), _abort(false), callback(callback)
69  {
70  // Initialize get pointer. This should be zero so that underflow is called upon first read.
71  setg(0, 0, 0);
72  setp(&out_buf_[1], &out_buf_[BUFF_SIZE - 1]);
73  }
74 
76  {
77  }
78 
80  {
81  ibrcommon::MutexLock l(in_buf_cond);
82 
83  while (!in_buf_free)
84  {
85  in_buf_cond.wait();
86  }
87 
88  _abort = true;
89  in_buf_cond.signal();
90  }
91 
92  void lowpanstream::queue(char *buf, size_t len)
93  {
94  ibrcommon::MutexLock l(in_buf_cond);
95 
96  IBRCOMMON_LOGGER_DEBUG_TAG("lowpanstream", 75) << "queue" << IBRCOMMON_LOGGER_ENDL;
97 
98  // Retrieve sequence number of frame
99  unsigned int seq_num = buf[0] & SEQ_NUM_MASK;
100 
101  IBRCOMMON_LOGGER_DEBUG_TAG("lowpanstream", 70) << "Received frame sequence number: " << seq_num << IBRCOMMON_LOGGER_ENDL;
102 
103  // Check if the sequence number is what we expect
104  if (in_seq_num_ != seq_num)
105  {
106  IBRCOMMON_LOGGER_TAG("lowpanstream", error) << "Received frame with out of bound sequence number (" << seq_num << " expected " << (int)in_seq_num_ << ")"<< IBRCOMMON_LOGGER_ENDL;
107  _abort = true;
108  in_buf_cond.signal();
109  return;
110  }
111 
112  if (buf[0] & SEGMENT_LAST)
113  {
114  // reset sequence number for first segment
115  in_seq_num_ = 0;
116  } else
117  {
118  // increment the sequence number
119  in_seq_num_ = static_cast<uint8_t>((in_seq_num_ + 1) % 8);
120  }
121 
122  // check if this is the right segment
123  if (_in_first_segment)
124  {
125  if (!(buf[0] & SEGMENT_FIRST)) return;
126  if (!(buf[0] & SEGMENT_LAST)) _in_first_segment = false;
127  }
128 
129  while (!in_buf_free)
130  {
131  in_buf_cond.wait();
132  }
133 
134  memcpy(&in_buf_[0], buf + 1, len - 1);
135  in_buf_len = len - 1;
136  in_buf_free = false;
137  in_buf_cond.signal();
138  }
139 
140  // close woth abort for conditional
141 
143  {
144  // Here we know we get the last segment. Mark it so.
145  _out_stat |= SEGMENT_LAST;
146 
147  int ret = std::char_traits<char>::eq_int_type(this->overflow(
148  std::char_traits<char>::eof()), std::char_traits<char>::eof()) ? -1
149  : 0;
150 
151  IBRCOMMON_LOGGER_DEBUG_TAG("lowpanstream", 80) << "sync" << IBRCOMMON_LOGGER_ENDL;
152 
153  return ret;
154  }
155 
156  std::char_traits<char>::int_type lowpanstream::overflow(std::char_traits<char>::int_type c)
157  {
158  char *ibegin = &out_buf_[0];
159  char *iend = pptr();
160 
161  IBRCOMMON_LOGGER_DEBUG_TAG("lowpanstream", 80) << "overflow" << IBRCOMMON_LOGGER_ENDL;
162 
163  // mark the buffer as free
164  setp(&out_buf_[1], &out_buf_[BUFF_SIZE - 1]);
165 
166  if (!std::char_traits<char>::eq_int_type(c, std::char_traits<char>::eof()))
167  {
168  *iend++ = std::char_traits<char>::to_char_type(c);
169  }
170 
171  // bytes to send
172  size_t bytes = (iend - ibegin);
173 
174  // if there is nothing to send, just return
175  if (bytes == 0)
176  {
177  IBRCOMMON_LOGGER_DEBUG_TAG("lowpanstream", 80) << "overflow() nothing to sent" << IBRCOMMON_LOGGER_ENDL;
178  return std::char_traits<char>::not_eof(c);
179  }
180 
181  //FIXME: Should we write in the segment position here?
182  out_buf_[0] = 0x07 & out_seq_num_;
183  out_buf_[0] |= _out_stat;
184 
185  out_seq_num_global++;
186  out_seq_num_ = static_cast<uint8_t>((out_seq_num_ + 1) % 8);
187 
188  IBRCOMMON_LOGGER_DEBUG_TAG("lowpanstream", 80) << "lowpanstream send segment " << (int)out_seq_num_ << " / " << out_seq_num_global << IBRCOMMON_LOGGER_ENDL;
189 
190  // Send segment to CL, use callback interface
191  callback.send_cb(&out_buf_[0], bytes, _address);
192 
193  if (_out_stat & SEGMENT_LAST)
194  {
195  // reset outgoing status byte and sequence number
196  _out_stat = SEGMENT_FIRST;
197  out_seq_num_ = 0;
198  }
199  else
200  {
201  _out_stat = SEGMENT_MIDDLE;
202  }
203 
204  return std::char_traits<char>::not_eof(c);
205 }
206 
207  std::char_traits<char>::int_type lowpanstream::underflow()
208  {
209  ibrcommon::MutexLock l(in_buf_cond);
210 
211  IBRCOMMON_LOGGER_DEBUG_TAG("lowpanstream", 80) << "underflow"<< IBRCOMMON_LOGGER_ENDL;
212 
213  while (in_buf_free)
214  {
215  if (_abort) throw ibrcommon::Exception("stream aborted");
216  in_buf_cond.wait();
217  }
218  memcpy(&out2_buf_[0] , &in_buf_[0], in_buf_len);
219  in_buf_free = true;
220  IBRCOMMON_LOGGER_DEBUG_TAG("lowpanstream", 80) << "underflow in_buf_free: " << in_buf_free << IBRCOMMON_LOGGER_ENDL;
221  in_buf_cond.signal();
222 
223  // Since the input buffer content is now valid (or is new)
224  // the get pointer should be initialized (or reset).
225  setg(&out2_buf_[0], &out2_buf_[0], &out2_buf_[0] + in_buf_len);
226 
227  return std::char_traits<char>::not_eof(out2_buf_[0]);
228  }
229 }