File: relsend.hpp

package info (click to toggle)
openvpn3-client 25%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 19,276 kB
  • sloc: cpp: 190,085; python: 7,218; ansic: 1,866; sh: 1,361; java: 402; lisp: 81; makefile: 17
file content (159 lines) | stat: -rw-r--r-- 4,042 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//    OpenVPN -- An application to securely tunnel IP networks
//               over a single port, with support for SSL/TLS-based
//               session authentication and key exchange,
//               packet encryption, packet authentication, and
//               packet compression.
//
//    Copyright (C) 2012- OpenVPN Inc.
//
//    SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//

// Sender side of reliability layer

#ifndef OPENVPN_RELIABLE_RELSEND_H
#define OPENVPN_RELIABLE_RELSEND_H

#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/msgwin.hpp>
#include <openvpn/time/time.hpp>
#include <openvpn/reliable/relcommon.hpp>

namespace openvpn {

template <typename PACKET>
class ReliableSendTemplate
{
  public:
    typedef reliable::id_t id_t;

    class Message : public ReliableMessageBase<PACKET>
    {
        friend class ReliableSendTemplate;
        using ReliableMessageBase<PACKET>::defined;

      public:
        bool ready_retransmit(const Time &now) const
        {
            return defined() && now >= retransmit_at_;
        }

        Time::Duration until_retransmit(const Time &now) const
        {
            Time::Duration ret;
            if (now < retransmit_at_)
                ret = retransmit_at_ - now;
            return ret;
        }

        void reset_retransmit(const Time &now, const Time::Duration &tls_timeout)
        {
            retransmit_at_ = now + tls_timeout;
        }

      private:
        Time retransmit_at_;
    };

    ReliableSendTemplate()
        : next(0)
    {
    }
    ReliableSendTemplate(const id_t span, id_t start_at = 0)
    {
        init(span, start_at);
    }

    void init(const id_t span, id_t start_at = 0)
    {
        next = start_at;
        window_.init(next, span);
    }

    // Return the id that the object at the head of the queue
    // would have (even if it isn't defined yet).
    id_t head_id() const
    {
        return window_.head_id();
    }

    // Return the ID of one past the end of the window
    id_t tail_id() const
    {
        return window_.tail_id();
    }

    // Return the window size
    id_t span() const
    {
        return window_.span();
    }

    // Return a reference to M object at id, throw exception
    // if id is not in current window
    Message &ref_by_id(const id_t id)
    {
        return window_.ref_by_id(id);
    }

    // Return the shortest duration for any pending retransmissions
    Time::Duration until_retransmit(const Time &now)
    {
        Time::Duration ret = Time::Duration::infinite();
        for (id_t i = head_id(); i < tail_id(); ++i)
        {
            const Message &msg = ref_by_id(i);
            if (msg.defined())
            {
                Time::Duration ut = msg.until_retransmit(now);
                if (ut < ret)
                    ret = ut;
            }
        }
        return ret;
    }

    // Return number of unacknowleged packets in send queue
    unsigned int n_unacked()
    {
        unsigned int ret = 0;
        for (id_t i = head_id(); i < tail_id(); ++i)
        {
            if (ref_by_id(i).defined())
                ++ret;
        }
        return ret;
    }

    // Return a fresh Message object that can be used to
    // construct the next packet in the sequence.  Don't call
    // unless ready() returns true.
    Message &send(const Time &now, const Time::Duration &tls_timeout)
    {
        Message &msg = window_.ref_by_id(next);
        msg.id_ = next++;
        msg.reset_retransmit(now, tls_timeout);
        return msg;
    }

    // Return true if send queue is ready to receive another packet
    bool ready() const
    {
        return window_.in_window(next);
    }

    // Remove a message from send queue that has been acknowledged
    void ack(const id_t id)
    {
        window_.rm_by_id(id);
    }

  private:
    id_t next;
    MessageWindow<Message, id_t> window_;
};

} // namespace openvpn

#endif // OPENVPN_RELIABLE_RELSEND_H