File: snappy.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 (130 lines) | stat: -rw-r--r-- 3,627 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
//    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
//

#ifndef OPENVPN_COMPRESS_SNAPPY_H
#define OPENVPN_COMPRESS_SNAPPY_H

// Implement Snappy compression.
// Should only be included by compress.hpp

#include <snappy.h>

namespace openvpn {

class CompressSnappy : public Compress
{
    // magic number for Snappy compression
    enum
    {
        SNAPPY_COMPRESS = 0x68,
    };

  public:
    CompressSnappy(const Frame::Ptr &frame, const SessionStats::Ptr &stats, const bool asym_arg)
        : Compress(frame, stats),
          asym(asym_arg)
    {
        OVPN_LOG_INFO("SNAPPY init asym=" << asym_arg);
    }

    const char *name() const override
    {
        return "snappy";
    }

    void compress(BufferAllocated &buf, const bool hint) override
    {
        // skip null packets
        if (!buf.size())
            return;

        if (hint && !asym)
        {
            // initialize work buffer
            frame->prepare(Frame::COMPRESS_WORK, work);

            // verify that input data length is not too large
            if (snappy::MaxCompressedLength(buf.size()) > work.max_size())
            {
                error(buf);
                return;
            }

            // do compress
            size_t comp_size;
            snappy::RawCompress((const char *)buf.c_data(), buf.size(), (char *)work.data(), &comp_size);

            // did compression actually reduce data length?
            if (comp_size < buf.size())
            {
                OVPN_LOG_VERBOSE("SNAPPY compress " << buf.size() << " -> " << comp_size);
                work.set_size(comp_size);
                do_swap(work, SNAPPY_COMPRESS);
                buf.swap(work);
                return;
            }
        }

        // indicate that we didn't compress
        do_swap(buf, NO_COMPRESS_SWAP);
    }

    void decompress(BufferAllocated &buf) override
    {
        // skip null packets
        if (!buf.size())
            return;

        const unsigned char c = buf.pop_front();
        switch (c)
        {
        case NO_COMPRESS_SWAP:
            do_unswap(buf);
            break;
        case SNAPPY_COMPRESS:
            {
                do_unswap(buf);

                // initialize work buffer
                const size_t payload_size = frame->prepare(Frame::DECOMPRESS_WORK, work);

                // do uncompress
                size_t decomp_size;
                if (!snappy::GetUncompressedLength((const char *)buf.c_data(), buf.size(), &decomp_size)
                    || decomp_size > payload_size)
                {
                    error(buf);
                    break;
                }
                if (!snappy::RawUncompress((const char *)buf.c_data(), buf.size(), (char *)work.data()))
                {
                    error(buf);
                    break;
                }
                OVPN_LOG_VERBOSE("SNAPPY uncompress " << buf.size() << " -> " << decomp_size);
                work.set_size(decomp_size);
                buf.swap(work);
            }
            break;
        default:
            error(buf); // unknown op
            break;
        }
    }

  private:
    const bool asym;
    BufferAllocated work;
};

} // namespace openvpn

#endif // OPENVPN_COMPRESS_SNAPPY_H