OpenVPN 3 Core Library
Loading...
Searching...
No Matches
zlib.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#ifndef OPENVPN_BUFFER_ZLIB_H
13#define OPENVPN_BUFFER_ZLIB_H
14
15#ifdef HAVE_ZLIB
16
17#include <cstring> // for std::memset
18
19#include <zlib.h>
20
26
27
28namespace openvpn {
29
30using namespace numeric_util;
31
32namespace ZLib {
33OPENVPN_EXCEPTION(zlib_error);
34
35class ZStreamBase // used internally by compress_gzip/decompress_gzip
36{
37 public:
38 z_stream s;
39
40 protected:
41 ZStreamBase()
42 {
43 std::memset(&s, 0, sizeof(s));
44 }
45
46 private:
47 ZStreamBase(const ZStreamBase &) = delete;
48 ZStreamBase &operator=(const ZStreamBase &) = delete;
49};
50
51inline BufferPtr compress_gzip(BufferPtr src,
52 const size_t headroom,
53 const size_t tailroom,
54 const int level,
55 const int window_bits = 15,
56 const int mem_level = 8)
57{
58 constexpr int GZIP_ENCODING = 16;
59
60 struct ZStream : public ZStreamBase
61 {
62 ~ZStream()
63 {
64 ::deflateEnd(&s);
65 }
66 };
67
68 if (src)
69 {
70 int status;
71 ZStream zs;
72 zs.s.next_in = src->data();
73 zs.s.avail_in = numeric_cast<decltype(zs.s.avail_in)>(src->size());
74 status = ::deflateInit2(&zs.s,
75 level,
76 Z_DEFLATED,
77 GZIP_ENCODING + window_bits,
78 mem_level,
79 Z_DEFAULT_STRATEGY);
80 if (status != Z_OK)
81 OPENVPN_THROW(zlib_error, "zlib deflateinit2 failed, error=" << status);
82 const uLong outcap = ::deflateBound(&zs.s, src->size());
83 auto b = BufferAllocatedRc::Create(outcap + headroom + tailroom, 0);
84 b->init_headroom(headroom);
85 zs.s.next_out = b->data();
86 zs.s.avail_out = numeric_cast<decltype(zs.s.avail_out)>(outcap);
87 status = ::deflate(&zs.s, Z_FINISH);
88 if (status != Z_STREAM_END)
89 OPENVPN_THROW(zlib_error, "zlib deflate failed, error=" << status);
90 b->set_size(zs.s.total_out);
91 return b;
92 }
93 else
94 return BufferPtr();
95}
96
97inline BufferPtr decompress_gzip(BufferPtr src,
98 const size_t headroom,
99 const size_t tailroom,
100 const size_t max_size,
101 const size_t block_size = 4096,
102 const int window_bits = 15)
103{
104 constexpr int GZIP_ENCODING = 16;
105
106 struct ZStream : public ZStreamBase
107 {
108 ~ZStream()
109 {
110 ::inflateEnd(&s);
111 }
112 };
113
114 if (src)
115 {
116 int status;
117 ZStream zs;
118 zs.s.next_in = src->data();
119 zs.s.avail_in = numeric_cast<decltype(zs.s.avail_in)>(src->size());
120 status = ::inflateInit2(&zs.s, GZIP_ENCODING + window_bits);
121 if (status != Z_OK)
122 OPENVPN_THROW(zlib_error, "zlib inflateinit2 failed, error=" << status);
123
124 BufferList blist;
125 size_t hr = headroom;
126 size_t tr = tailroom;
127 do
128 {
129 // use headroom/tailroom on first block to take advantage
130 // of BufferList::join() optimization for one-block lists
131 auto b = BufferAllocatedRc::Create(block_size + hr + tr, 0);
132 b->init_headroom(hr);
133 const size_t avail = b->remaining(tr);
134 zs.s.next_out = b->data();
135 zs.s.avail_out = clamp_to_typerange<decltype(zs.s.avail_out)>(avail);
136 status = ::inflate(&zs.s, Z_SYNC_FLUSH);
137 if (status != Z_OK && status != Z_STREAM_END)
138 OPENVPN_THROW(zlib_error, "zlib inflate failed, error=" << status);
139 b->set_size(avail - zs.s.avail_out);
140 blist.push_back(std::move(b));
141 if (max_size && zs.s.total_out > max_size)
142 OPENVPN_THROW(zlib_error, "zlib inflate max_size " << max_size << " exceeded");
143 hr = tr = 0;
144 } while (status == Z_OK);
145 return blist.join(headroom, tailroom, true);
146 }
147 else
148 return BufferPtr();
149}
150
151} // namespace ZLib
152} // namespace openvpn
153
154#endif
155#endif
#define OPENVPN_EXCEPTION(C)
#define OPENVPN_THROW(exc, stuff)
OutT numeric_cast(InT inVal)
Tests attempted casts to ensure the input value does not exceed the capacity of the output type.
OutT clamp_to_typerange(InT inVal)
Clamps the input value to the legal range for the output type.
Support deferred server-side state creation when client connects.
Definition ovpncli.cpp:95
BufferCollection< std::list > BufferList
Definition buflist.hpp:108
RCPtr< BufferAllocatedRc > BufferPtr
Definition buffer.hpp:1859