IBR-DTNSuite  0.8
ibrcommon/ibrcommon/net/lowpanstream.cpp
Go to the documentation of this file.
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 }