IBR-DTNSuite
0.8
|
00001 #include "ibrcommon/config.h" 00002 #include "ibrcommon/net/lowpanstream.h" 00003 00004 #include "ibrcommon/Logger.h" 00005 #include "ibrcommon/thread/MutexLock.h" 00006 00007 #include <signal.h> 00008 #include <string.h> 00009 #include <math.h> 00010 00011 /* Header: 00012 * +---------------+ 00013 * |7 6 5 4 3 2 1 0| 00014 * +---------------+ 00015 * Bit 7-6: 00 to be compatible with 6LoWPAN 00016 * Bit 5-4: 00 Middle segment 00017 * 01 Last segment 00018 * 10 First segment 00019 * 11 First and last segment 00020 * Bit 3: 0 Extended frame not available 00021 * 1 Extended frame available 00022 * Bit 2-0: sequence number (0-7) 00023 * 00024 * Extended header (only if extended frame available) 00025 * +---------------+ 00026 * |7 6 5 4 3 2 1 0| 00027 * +---------------+ 00028 * Bit 7: 0 No discovery frame 00029 * 1 Discovery frame 00030 * Bit 6-0: Reserved 00031 * 00032 * Two bytes at the end of the frame are reserved for the short address of the 00033 * sender. This is a workaround until recvfrom() gets fixed. 00034 */ 00035 #define SEGMENT_FIRST 0x20 00036 #define SEGMENT_LAST 0x10 00037 //#define SEGMENT_BOTH 0x30 00038 #define SEGMENT_MIDDLE 0x00 00039 00040 #define SEQ_NUM_MASK 0x07 00041 00042 namespace ibrcommon 00043 { 00044 lowpanstream::lowpanstream(lowpanstream_callback &callback, unsigned int address) : 00045 std::iostream(this), _address(address), _in_first_segment(true), _out_stat(SEGMENT_FIRST), in_buf_(new char[BUFF_SIZE]), 00046 in_buf_len(0), in_buf_free(true), out_buf_(new char[BUFF_SIZE+2]), out2_buf_(new char[BUFF_SIZE]), 00047 in_seq_num_(0), out_seq_num_(0), out_seq_num_global(0), _abort(false), callback(callback) 00048 { 00049 // Initialize get pointer. This should be zero so that underflow is called upon first read. 00050 setg(0, 0, 0); 00051 setp(out_buf_ + 1, out_buf_ + BUFF_SIZE -1); 00052 } 00053 00054 lowpanstream::~lowpanstream() 00055 { 00056 delete[] in_buf_; 00057 delete[] out_buf_; 00058 delete[] out2_buf_; 00059 } 00060 00061 void lowpanstream::abort() 00062 { 00063 ibrcommon::MutexLock l(in_buf_cond); 00064 00065 while (!in_buf_free) 00066 { 00067 in_buf_cond.wait(); 00068 } 00069 00070 _abort = true; 00071 in_buf_cond.signal(); 00072 } 00073 00074 void lowpanstream::queue(char *buf, int len) 00075 { 00076 ibrcommon::MutexLock l(in_buf_cond); 00077 00078 IBRCOMMON_LOGGER_DEBUG(10) << "lowpanstream::queue"<< IBRCOMMON_LOGGER_ENDL; 00079 00080 // Retrieve sequence number of frame 00081 unsigned int seq_num = buf[0] & SEQ_NUM_MASK; 00082 00083 IBRCOMMON_LOGGER_DEBUG(45) << "Received frame sequence number: " << seq_num << IBRCOMMON_LOGGER_ENDL; 00084 00085 // Check if the sequence number is what we expect 00086 if (in_seq_num_ != seq_num) 00087 { 00088 IBRCOMMON_LOGGER(error) << "Received frame with out of bound sequence number (" << seq_num << " expected " << (int)in_seq_num_ << ")"<< IBRCOMMON_LOGGER_ENDL; 00089 _abort = true; 00090 in_buf_cond.signal(); 00091 return; 00092 } 00093 00094 if (buf[0] & SEGMENT_LAST) 00095 { 00096 // reset sequence number for first segment 00097 in_seq_num_ = 0; 00098 } else 00099 { 00100 // increment the sequence number 00101 in_seq_num_ = (in_seq_num_ + 1) % 8; 00102 } 00103 00104 // check if this is the right segment 00105 if (_in_first_segment) 00106 { 00107 if (!(buf[0] & SEGMENT_FIRST)) return; 00108 if (!(buf[0] & SEGMENT_LAST)) _in_first_segment = false; 00109 } 00110 00111 while (!in_buf_free) 00112 { 00113 in_buf_cond.wait(); 00114 } 00115 00116 memcpy(in_buf_, buf + 1, len - 1); 00117 in_buf_len = len - 1; 00118 in_buf_free = false; 00119 in_buf_cond.signal(); 00120 } 00121 00122 // close woth abort for conditional 00123 00124 int lowpanstream::sync() 00125 { 00126 // Here we know we get the last segment. Mark it so. 00127 _out_stat |= SEGMENT_LAST; 00128 00129 int ret = std::char_traits<char>::eq_int_type(this->overflow( 00130 std::char_traits<char>::eof()), std::char_traits<char>::eof()) ? -1 00131 : 0; 00132 00133 IBRCOMMON_LOGGER_DEBUG(10) << "lowpanstream::sync"<< IBRCOMMON_LOGGER_ENDL; 00134 00135 return ret; 00136 } 00137 00138 std::char_traits<char>::int_type lowpanstream::overflow(std::char_traits<char>::int_type c) 00139 { 00140 char *ibegin = out_buf_; 00141 char *iend = pptr(); 00142 00143 IBRCOMMON_LOGGER_DEBUG(10) << "lowpanstream::overflow"<< IBRCOMMON_LOGGER_ENDL; 00144 00145 // mark the buffer as free 00146 setp(out_buf_ + 1, out_buf_ + BUFF_SIZE - 1); 00147 00148 if (!std::char_traits<char>::eq_int_type(c, std::char_traits<char>::eof())) 00149 { 00150 *iend++ = std::char_traits<char>::to_char_type(c); 00151 } 00152 00153 // bytes to send 00154 size_t bytes = (iend - ibegin); 00155 00156 // if there is nothing to send, just return 00157 if (bytes == 0) 00158 { 00159 IBRCOMMON_LOGGER_DEBUG(10) << "lowpanstream::overflow() nothing to sent" << IBRCOMMON_LOGGER_ENDL; 00160 return std::char_traits<char>::not_eof(c); 00161 } 00162 00163 //FIXME: Should we write in the segment position here? 00164 out_buf_[0] = 0x07 & out_seq_num_; 00165 out_buf_[0] |= _out_stat; 00166 00167 out_seq_num_global++; 00168 out_seq_num_ = (out_seq_num_ + 1) % 8; 00169 00170 IBRCOMMON_LOGGER_DEBUG(10) << "lowpanstream send segment " << (int)out_seq_num_ << " / " << out_seq_num_global << IBRCOMMON_LOGGER_ENDL; 00171 00172 // Send segment to CL, use callback interface 00173 callback.send_cb(out_buf_, bytes, _address); 00174 00175 if (_out_stat & SEGMENT_LAST) 00176 { 00177 // reset outgoing status byte and sequence number 00178 _out_stat = SEGMENT_FIRST; 00179 out_seq_num_ = 0; 00180 } 00181 else 00182 { 00183 _out_stat = SEGMENT_MIDDLE; 00184 } 00185 00186 return std::char_traits<char>::not_eof(c); 00187 } 00188 00189 std::char_traits<char>::int_type lowpanstream::underflow() 00190 { 00191 ibrcommon::MutexLock l(in_buf_cond); 00192 00193 IBRCOMMON_LOGGER_DEBUG(10) << "lowpanstream::underflow"<< IBRCOMMON_LOGGER_ENDL; 00194 00195 while (in_buf_free) 00196 { 00197 if (_abort) throw ibrcommon::Exception("stream aborted"); 00198 in_buf_cond.wait(); 00199 } 00200 memcpy(out2_buf_ ,in_buf_, in_buf_len); 00201 in_buf_free = true; 00202 IBRCOMMON_LOGGER_DEBUG(10) << "lowpanstream::underflow in_buf_free: " << in_buf_free << IBRCOMMON_LOGGER_ENDL; 00203 in_buf_cond.signal(); 00204 00205 // Since the input buffer content is now valid (or is new) 00206 // the get pointer should be initialized (or reset). 00207 setg(out2_buf_, out2_buf_, out2_buf_ + in_buf_len); 00208 00209 return std::char_traits<char>::not_eof((unsigned char) out2_buf_[0]); 00210 } 00211 }