servlib/conv_layers/SeqpacketConvergenceLayer.h
changeset 0 2b3e5ec03512
equal deleted inserted replaced
-1:000000000000 0:2b3e5ec03512
       
     1 /*
       
     2  *    Copyright 2009-2010 Darren Long, darren.long@mac.com
       
     3  *    Copyright 2006 Intel Corporation
       
     4  * 
       
     5  *    Licensed under the Apache License, Version 2.0 (the "License");
       
     6  *    you may not use this file except in compliance with the License.
       
     7  *    You may obtain a copy of the License at
       
     8  * 
       
     9  *        http://www.apache.org/licenses/LICENSE-2.0
       
    10  * 
       
    11  *    Unless required by applicable law or agreed to in writing, software
       
    12  *    distributed under the License is distributed on an "AS IS" BASIS,
       
    13  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    14  *    See the License for the specific language governing permissions and
       
    15  *    limitations under the License.
       
    16  */
       
    17 
       
    18 #ifndef _SEQPACKET_CONVERGENCE_LAYER_H_
       
    19 #define _SEQPACKET_CONVERGENCE_LAYER_H_
       
    20 
       
    21 #include "ConnectionConvergenceLayer.h"
       
    22 #include "CLConnection.h"
       
    23 
       
    24 namespace dtn {
       
    25 
       
    26 /**
       
    27  * Another shared-implementation convergence layer class for use with
       
    28  * reliable, in-order SEQ_PACKET protocols, i.e. Connected Mode AX.25.
       
    29  * The goal is to share as much functionality as
       
    30  * possible between protocols that have in-order, reliable, delivery
       
    31  * semantics, but require fixed sized payloads rather than conforming to 
       
    32  * stream semantics.
       
    33  *
       
    34  * For the protocol, bundles are broken up into configurable-sized
       
    35  * segments that are sent sequentially. Only a single bundle is
       
    36  * inflight on the wire at one time (i.e. we don't interleave segments
       
    37  * from different bundles). When segment acknowledgements are enabled
       
    38  * (the default behavior), the receiving node sends an acknowledgement
       
    39  * for each segment of the bundle that was received.
       
    40  *
       
    41  * Keepalive messages are sent back and forth to ensure that the
       
    42  * connection remains open. In the case of on demand links, a
       
    43  * configurable idle timer is maintained to close the link when no
       
    44  * bundle traffic has been sent or received. Links that are expected
       
    45  * to be open but have broken due to underlying network conditions
       
    46  * (i.e. always on and on demand links) are reopened by a timer that
       
    47  * is managed by the contact manager.
       
    48  *
       
    49  * Flow control is managed through the poll callbacks given by the
       
    50  * base class CLConnection. In send_pending_data, we check if there
       
    51  * are any acks that need to be sent, then check if there are bundle
       
    52  * segments to be sent (i.e. acks are given priority). The only
       
    53  * exception to this is that the connection might be write blocked in
       
    54  * the middle of sending a data segment. In that case, we must first
       
    55  * finish transmitting the current segment before sending any other
       
    56  * acks (or the shutdown message), otherwise those messages will be
       
    57  * consumed as part of the payload.
       
    58  *
       
    59  * To make sure that we don't deadlock with the other side, we always
       
    60  * drain any data that is ready on the channel. All incoming messages
       
    61  * mark state in the appropriate data structures (i.e. InFlightList
       
    62  * and IncomingList), then rely on send_pending_data to send the
       
    63  * appropriate responses.
       
    64  *
       
    65  * The InflightBundle is used to record state about bundle
       
    66  * transmissions. To record the segments that have been sent, we fill
       
    67  * in the sent_data_ sparse bitmap with the range of bytes as we send
       
    68  * segments out. As acks arrive, we extend the ack_data_ field to
       
    69  * match. Once the whole bundle is acked, the entry is removed from
       
    70  * the InFlightList.
       
    71  *
       
    72  * The IncomingBundle is used to record state about bundle reception.
       
    73  * The rcvd_data_ bitmap is extended contiguously with the amount of
       
    74  * data that has been received, including partially received segments.
       
    75  *
       
    76  * To track segments that we have received but haven't yet acked, we
       
    77  * set a single bit for the offset of the end of the segment in the
       
    78  * ack_data_ bitmap. We also separately record the total range of acks
       
    79  * that have been previously sent in acked_length_. As we send acks
       
    80  * out, we clear away the bits in ack_data_
       
    81  */
       
    82 class SeqpacketConvergenceLayer : public ConnectionConvergenceLayer {
       
    83 public:
       
    84     /**
       
    85      * Constructor
       
    86      */
       
    87     SeqpacketConvergenceLayer(const char* logpath, const char* cl_name,
       
    88                            u_int8_t cl_version);
       
    89 
       
    90 protected:
       
    91     /**
       
    92      * Values for ContactHeader flags.
       
    93      */
       
    94     typedef enum {
       
    95         SEGMENT_ACK_ENABLED   = 1 << 0, ///< segment acks requested
       
    96         REACTIVE_FRAG_ENABLED = 1 << 1, ///< reactive fragmentation enabled
       
    97         NEGATIVE_ACK_ENABLED  = 1 << 2, ///< refuse bundle enabled
       
    98     } contact_header_flags_t;
       
    99 
       
   100     /**
       
   101      * Contact initiation header. Sent at the beginning of a contact. 
       
   102      */
       
   103     struct ContactHeader {
       
   104         u_int32_t magic;        ///< magic word (MAGIC: "dtn!")
       
   105         u_int8_t  version;      ///< cl protocol version
       
   106         u_int8_t  flags;        ///< connection flags (see above)
       
   107         u_int16_t keepalive_interval;   ///< seconds between keepalive packets
       
   108         // SDNV   local_eid_length           local eid length
       
   109         // byte[] local_eid                  local eid data
       
   110     } __attribute__((packed));
       
   111 
       
   112     /**
       
   113      * Valid type codes for the protocol messages, shifted into the
       
   114      * high-order four bits of the byte. The lower four bits are used
       
   115      * for per-message flags, defined below.
       
   116      */
       
   117     typedef enum {
       
   118         DATA_SEGMENT    = 0x1 << 4, ///< a segment of bundle data
       
   119                                     ///< (followed by a SDNV segment length)
       
   120         ACK_SEGMENT     = 0x2 << 4, ///< acknowledgement of a segment
       
   121                                     ///< (followed by a SDNV ack length)
       
   122         REFUSE_BUNDLE   = 0x3 << 4, ///< reject reception of current bundle
       
   123         KEEPALIVE       = 0x4 << 4, ///< keepalive packet
       
   124         SHUTDOWN        = 0x5 << 4, ///< about to shutdown
       
   125     } msg_type_t;
       
   126 
       
   127     /**
       
   128      * Valid flags for the DATA_SEGMENT message.
       
   129      */
       
   130     typedef enum {
       
   131         BUNDLE_START    = 0x1 << 1, ///< First segment of a bundle
       
   132         BUNDLE_END      = 0x1 << 0, ///< Last segment of a bundle
       
   133     } data_segment_flags_t;
       
   134     
       
   135     /**
       
   136      * Valid flags for the SHUTDOWN message.
       
   137      */
       
   138     typedef enum {
       
   139         SHUTDOWN_HAS_REASON = 0x1 << 1, ///< Has reason code
       
   140         SHUTDOWN_HAS_DELAY  = 0x1 << 0, ///< Has reconnect delay
       
   141     } shutdown_flags_t;
       
   142     
       
   143     /**
       
   144      * Values for the SHUTDOWN reason codes
       
   145      */
       
   146     typedef enum {
       
   147         SHUTDOWN_NO_REASON          = 0xff, ///< no reason code (never sent)
       
   148         SHUTDOWN_IDLE_TIMEOUT       = 0x0,  ///< idle connection
       
   149         SHUTDOWN_VERSION_MISMATCH   = 0x1,  ///< version mismatch
       
   150         SHUTDOWN_BUSY               = 0x2,  ///< node is busy
       
   151     } shutdown_reason_t;
       
   152 
       
   153     /**
       
   154      * Convert a reason code to a string.
       
   155      */
       
   156     static const char* shutdown_reason_to_str(shutdown_reason_t reason)
       
   157     {
       
   158         switch (reason) {
       
   159         case SHUTDOWN_NO_REASON:    return "no reason";
       
   160         case SHUTDOWN_IDLE_TIMEOUT:     return "idle connection";
       
   161         case SHUTDOWN_VERSION_MISMATCH: return "version mismatch";
       
   162         case SHUTDOWN_BUSY:         return "node is busy";
       
   163         }
       
   164         NOTREACHED;
       
   165     }
       
   166     
       
   167     /**
       
   168      * Link parameters shared among all Seqpacket based convergence layers.
       
   169      */
       
   170     class SeqpacketLinkParams : public ConnectionConvergenceLayer::LinkParams {
       
   171     public:
       
   172         bool  segment_ack_enabled_; ///< Use per-segment acks
       
   173         bool  negative_ack_enabled_;///< Enable negative acks
       
   174         u_int keepalive_interval_;  ///< Seconds between keepalive packets
       
   175         u_int segment_length_;      ///< Maximum size of transmitted segments
       
   176         u_int ack_window_;          ///< Number of segments before acking
       
   177 
       
   178     protected:
       
   179         // See comment in LinkParams for why this should be protected
       
   180         SeqpacketLinkParams(bool init_defaults);
       
   181     };
       
   182     
       
   183     /**
       
   184      * Version of the actual CL protocol.
       
   185      */
       
   186     u_int8_t cl_version_;
       
   187 
       
   188     /**
       
   189      * Seqpacket connection class.
       
   190      */
       
   191     class Connection : public CLConnection {
       
   192     public:
       
   193         /**
       
   194          * Constructor.
       
   195          */
       
   196         Connection(const char* classname,
       
   197                    const char* logpath,
       
   198                    SeqpacketConvergenceLayer* cl,
       
   199                    SeqpacketLinkParams* params,
       
   200                    bool active_connector);
       
   201 
       
   202         /// @{ virtual from CLConnection
       
   203         bool send_pending_data();
       
   204         void handle_bundles_queued();
       
   205         void handle_cancel_bundle(Bundle* bundle);
       
   206         void handle_poll_timeout();
       
   207         void break_contact(ContactEvent::reason_t reason);
       
   208         /// @}
       
   209 
       
   210     protected:
       
   211         /**
       
   212          * Hook used to tell the derived CL class to drain data out of
       
   213          * the send buffer.
       
   214          */
       
   215         virtual void send_data() = 0;
       
   216 
       
   217         /// @{ utility functions used by derived classes
       
   218         void initiate_contact();
       
   219         void process_data();
       
   220         void check_keepalive();
       
   221         /// @}
       
   222 
       
   223     private:
       
   224         /// @{ utility functions used internally in this class
       
   225         void note_data_rcvd();
       
   226         void note_data_sent();
       
   227         bool send_pending_acks();
       
   228         bool start_next_bundle();
       
   229         bool send_next_segment(InFlightBundle* inflight);
       
   230         bool send_data_todo(InFlightBundle* inflight);
       
   231         bool finish_bundle(InFlightBundle* inflight);
       
   232         void check_completed(InFlightBundle* inflight);
       
   233         void send_keepalive();
       
   234         
       
   235         void handle_contact_initiation();
       
   236         bool handle_data_segment(u_int8_t flags);
       
   237         bool handle_data_todo();
       
   238         bool handle_ack_segment(u_int8_t flags);
       
   239         bool handle_refuse_bundle(u_int8_t flags);
       
   240         bool handle_keepalive(u_int8_t flags);
       
   241         bool handle_shutdown(u_int8_t flags);
       
   242         void check_completed(IncomingBundle* incoming);
       
   243         /// @}
       
   244 
       
   245         /**
       
   246          * Utility function to downcast the params_ pointer that's
       
   247          * stored in the CLConnection parent class.
       
   248          */
       
   249         SeqpacketLinkParams* seqpacket_lparams()
       
   250         {
       
   251             SeqpacketLinkParams* ret = dynamic_cast<SeqpacketLinkParams*>(params_);
       
   252             ASSERT(ret != NULL);
       
   253             return ret;
       
   254         }
       
   255         
       
   256     protected:
       
   257         InFlightBundle* current_inflight_; ///< Current bundle that's in flight 
       
   258         size_t send_segment_todo_;         ///< Bytes left to send of current segment
       
   259         std::queue<u_int> sendbuf_sequence_delimiters_; ///< sendbuf_ may hold many segments 
       
   260         size_t recv_segment_todo_;  ///< Bytes left to recv of current segment
       
   261         struct timeval data_rcvd_;  ///< Timestamp for idle/keepalive timer
       
   262         struct timeval data_sent_;  ///< Timestamp for idle timer
       
   263         struct timeval keepalive_sent_; ///< Timestamp for keepalive timer
       
   264         bool breaking_contact_;     ///< Bit to catch multiple calls to
       
   265                                     ///< break_contact 
       
   266         bool contact_initiated_;    ///< bit to prevent certain actions before
       
   267                                     ///< contact is initiated
       
   268         u_int ack_window_todo_; ///< number of segments left in ack_window
       
   269     };
       
   270 
       
   271     /// For some gcc variants, this typedef seems to be needed
       
   272     typedef ConnectionConvergenceLayer::LinkParams LinkParams;
       
   273 
       
   274     /// @{ Virtual from ConvergenceLayer
       
   275     void dump_link(const LinkRef& link, oasys::StringBuffer* buf);
       
   276     /// @}
       
   277     
       
   278     /// @{ Virtual from ConnectionConvergenceLayer
       
   279     bool parse_link_params(LinkParams* params,
       
   280                            int argc, const char** argv,
       
   281                            const char** invalidp);
       
   282     bool finish_init_link(const LinkRef& link, LinkParams* params);
       
   283     /// @}
       
   284 
       
   285 };
       
   286 
       
   287 } // namespace dtn
       
   288 
       
   289 #endif /* _STREAM_CONVERGENCE_LAYER_H_ */