File: lz4.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 (92 lines) | stat: -rw-r--r-- 3,644 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
//    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
//

#pragma once

#include <cstdint> // for std::uint32_t, uint64_t, etc.

#include <lz4.h>

#include <openvpn/common/clamp_typerange.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/socktypes.hpp> // for ntohl/htonl
#include <openvpn/buffer/buffer.hpp>

using openvpn::numeric_util::clamp_to_typerange;

namespace openvpn::LZ4 {

OPENVPN_EXCEPTION(lz4_error);

inline BufferPtr compress(const ConstBuffer &src,
                          const size_t headroom,
                          const size_t tailroom)
{
    // sanity check
    if (src.size() > LZ4_MAX_INPUT_SIZE)
        OPENVPN_THROW(lz4_error, "compress buffer size=" << src.size() << " exceeds LZ4_MAX_INPUT_SIZE=" << LZ4_MAX_INPUT_SIZE);

    // allocate dest buffer
    auto dest = BufferAllocatedRc::Create(sizeof(std::uint32_t) + headroom + tailroom + LZ4_COMPRESSBOUND(src.size()), 0);
    dest->init_headroom(headroom);

    // as a hint to receiver, write the decompressed size
    {
        const std::uint32_t size = htonl(clamp_to_typerange<uint32_t>(src.size()));
        dest->write(&size, sizeof(size));
    }

    // compress
    const int comp_size = ::LZ4_compress_default((const char *)src.c_data(),
                                                 (char *)dest->data_end(),
                                                 (int)src.size(),
                                                 (int)dest->remaining(tailroom));
    if (comp_size <= 0)
        OPENVPN_THROW(lz4_error, "LZ4_compress_default returned error status=" << comp_size);
    dest->inc_size(comp_size);
    return dest;
}

inline BufferPtr decompress(const ConstBuffer &source,
                            const size_t headroom,
                            const size_t tailroom,
                            size_t max_decompressed_size = LZ4_MAX_INPUT_SIZE)
{
    // get the decompressed size
    ConstBuffer src(source);
    if (src.size() < sizeof(std::uint32_t))
        OPENVPN_THROW(lz4_error, "decompress buffer size=" << src.size() << " is too small");
    std::uint32_t size;
    src.read(&size, sizeof(size));
    size = ntohl(size);
    if (max_decompressed_size > LZ4_MAX_INPUT_SIZE)
        max_decompressed_size = LZ4_MAX_INPUT_SIZE;
    if (max_decompressed_size && size > max_decompressed_size)
        OPENVPN_THROW(lz4_error, "decompress expansion size=" << size << " is too large (must be <= " << max_decompressed_size << ')');

    // allocate dest buffer
    auto dest = BufferAllocatedRc::Create(headroom + tailroom + size, 0);
    dest->init_headroom(headroom);

    // decompress
    const int decomp_size = LZ4_decompress_safe((const char *)src.c_data(),
                                                (char *)dest->data(),
                                                (int)src.size(),
                                                size);
    if (decomp_size <= 0)
        OPENVPN_THROW(lz4_error, "LZ4_decompress_safe returned error status=" << decomp_size);
    if (static_cast<unsigned int>(decomp_size) != size)
        OPENVPN_THROW(lz4_error, "decompress size inconsistency expected_size=" << size << " actual_size=" << decomp_size);
    dest->inc_size(decomp_size);
    return dest;
}

} // namespace openvpn::LZ4