mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-04-24 00:00:05 +08:00
Merge commit '86cc97e55fe346502462284d2e636a2b3708163e' as 'Sources/OpenVPN3'
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
// 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-2017 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef OPENVPN_BUFFER_ZLIB_H
|
||||
#define OPENVPN_BUFFER_ZLIB_H
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
|
||||
#include <cstring> // for std::memset
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/buffer/buffer.hpp>
|
||||
#include <openvpn/buffer/buflist.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace ZLib {
|
||||
OPENVPN_EXCEPTION(zlib_error);
|
||||
|
||||
class ZStreamBase // used internally by compress_gzip/decompress_gzip
|
||||
{
|
||||
public:
|
||||
z_stream s;
|
||||
protected:
|
||||
ZStreamBase() { std::memset(&s, 0, sizeof(s)); }
|
||||
private:
|
||||
ZStreamBase(const ZStreamBase&) = delete;
|
||||
ZStreamBase& operator=(const ZStreamBase&) = delete;
|
||||
};
|
||||
|
||||
inline BufferPtr compress_gzip(BufferPtr src,
|
||||
const size_t headroom,
|
||||
const size_t tailroom,
|
||||
const int level,
|
||||
const int window_bits=15,
|
||||
const int mem_level=8)
|
||||
{
|
||||
constexpr int GZIP_ENCODING = 16;
|
||||
|
||||
struct ZStream : public ZStreamBase {
|
||||
~ZStream() { ::deflateEnd(&s); }
|
||||
};
|
||||
|
||||
if (src)
|
||||
{
|
||||
int status;
|
||||
ZStream zs;
|
||||
zs.s.next_in = src->data();
|
||||
zs.s.avail_in = src->size();
|
||||
status = ::deflateInit2(&zs.s,
|
||||
level,
|
||||
Z_DEFLATED,
|
||||
GZIP_ENCODING + window_bits,
|
||||
mem_level,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
if (status != Z_OK)
|
||||
OPENVPN_THROW(zlib_error, "zlib deflateinit2 failed, error=" << status);
|
||||
const uLong outcap = ::deflateBound(&zs.s, src->size());
|
||||
BufferPtr b = new BufferAllocated(outcap + headroom + tailroom, 0);
|
||||
b->init_headroom(headroom);
|
||||
zs.s.next_out = b->data();
|
||||
zs.s.avail_out = outcap;
|
||||
status = ::deflate(&zs.s, Z_FINISH);
|
||||
if (status != Z_STREAM_END)
|
||||
OPENVPN_THROW(zlib_error, "zlib deflate failed, error=" << status);
|
||||
b->set_size(zs.s.total_out);
|
||||
return b;
|
||||
}
|
||||
else
|
||||
return BufferPtr();
|
||||
}
|
||||
|
||||
inline BufferPtr decompress_gzip(BufferPtr src,
|
||||
const size_t headroom,
|
||||
const size_t tailroom,
|
||||
const size_t max_size,
|
||||
const size_t block_size=4096,
|
||||
const int window_bits=15)
|
||||
{
|
||||
constexpr int GZIP_ENCODING = 16;
|
||||
|
||||
struct ZStream : public ZStreamBase {
|
||||
~ZStream() { ::inflateEnd(&s); }
|
||||
};
|
||||
|
||||
if (src)
|
||||
{
|
||||
int status;
|
||||
ZStream zs;
|
||||
zs.s.next_in = src->data();
|
||||
zs.s.avail_in = src->size();
|
||||
status = ::inflateInit2(&zs.s, GZIP_ENCODING + window_bits);
|
||||
if (status != Z_OK)
|
||||
OPENVPN_THROW(zlib_error, "zlib inflateinit2 failed, error=" << status);
|
||||
|
||||
BufferList blist;
|
||||
size_t hr = headroom;
|
||||
size_t tr = tailroom;
|
||||
do {
|
||||
// use headroom/tailroom on first block to take advantage
|
||||
// of BufferList::join() optimization for one-block lists
|
||||
BufferPtr b = new BufferAllocated(block_size + hr + tr, 0);
|
||||
b->init_headroom(hr);
|
||||
const size_t avail = b->remaining(tr);
|
||||
zs.s.next_out = b->data();
|
||||
zs.s.avail_out = avail;
|
||||
status = ::inflate(&zs.s, Z_SYNC_FLUSH);
|
||||
if (status != Z_OK && status != Z_STREAM_END)
|
||||
OPENVPN_THROW(zlib_error, "zlib inflate failed, error=" << status);
|
||||
b->set_size(avail - zs.s.avail_out);
|
||||
blist.push_back(std::move(b));
|
||||
if (max_size && zs.s.total_out > max_size)
|
||||
OPENVPN_THROW(zlib_error, "zlib inflate max_size " << max_size << " exceeded");
|
||||
hr = tr = 0;
|
||||
} while (status == Z_OK);
|
||||
return blist.join(headroom, tailroom, true);
|
||||
}
|
||||
else
|
||||
return BufferPtr();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
Reference in New Issue
Block a user