svn cleanup
[anytun.git] / openvpn / lzo.c
blobf5afc083edca6e53c31264bddd2314bded820ffb
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #ifdef WIN32
26 #include "config-win32.h"
27 #else
28 #include "config.h"
29 #endif
31 #ifdef USE_LZO
33 #include "syshead.h"
35 #include "lzo.h"
36 #include "error.h"
37 #include "otime.h"
39 #include "memdbg.h"
41 static bool
42 lzo_adaptive_compress_test (struct lzo_adaptive_compress *ac)
44 const bool save = ac->compress_state;
45 const time_t local_now = now;
47 if (!ac->enabled)
48 return true;
50 if (!ac->compress_state)
52 if (local_now >= ac->next)
54 if (ac->n_total > AC_MIN_BYTES
55 && (ac->n_total - ac->n_comp) < (ac->n_total / (100 / AC_SAVE_PCT)))
57 ac->compress_state = true;
58 ac->next = local_now + AC_OFF_SEC;
60 else
62 ac->next = local_now + AC_SAMP_SEC;
64 dmsg (D_COMP, "lzo_adaptive_compress_test: comp=%d total=%d", ac->n_comp, ac->n_total);
65 ac->n_total = ac->n_comp = 0;
68 else
70 if (local_now >= ac->next)
72 ac->next = local_now + AC_SAMP_SEC;
73 ac->n_total = ac->n_comp = 0;
74 ac->compress_state = false;
78 if (ac->compress_state != save)
79 dmsg (D_COMP_LOW, "Adaptive compression state %s", (ac->compress_state ? "OFF" : "ON"));
81 return !ac->compress_state;
84 static inline void
85 lzo_adaptive_compress_data (struct lzo_adaptive_compress *ac, int n_total, int n_comp)
87 if (ac->enabled)
89 ac->n_total += n_total;
90 ac->n_comp += n_comp;
94 void lzo_adjust_frame_parameters (struct frame *frame)
96 /* Leave room for our one-byte compressed/didn't-compress prefix byte. */
97 frame_add_to_extra_frame (frame, LZO_PREFIX_LEN);
99 /* Leave room for compression buffer to expand in worst case scenario
100 where data is totally uncompressible */
101 frame_add_to_extra_buffer (frame, LZO_EXTRA_BUFFER (EXPANDED_SIZE(frame)));
104 void
105 lzo_compress_init (struct lzo_compress_workspace *lzowork, bool adaptive)
107 CLEAR (*lzowork);
109 lzowork->wmem_size = LZO_WORKSPACE;
110 lzowork->ac.enabled = adaptive;
112 if (lzo_init () != LZO_E_OK)
113 msg (M_FATAL, "Cannot initialize LZO compression library");
114 lzowork->wmem = (lzo_voidp) lzo_malloc (lzowork->wmem_size);
115 check_malloc_return (lzowork->wmem);
116 msg (M_INFO, "LZO compression initialized");
119 void
120 lzo_compress_uninit (struct lzo_compress_workspace *lzowork)
122 if (lzowork)
124 lzo_free (lzowork->wmem);
125 lzowork->wmem = NULL;
129 /* Magic numbers to tell our peer if we compressed or not */
130 #define YES_COMPRESS 0x66
131 #define NO_COMPRESS 0xFA
133 void
134 lzo_compress (struct buffer *buf, struct buffer work,
135 struct lzo_compress_workspace *lzowork,
136 const struct frame* frame)
138 lzo_uint zlen = 0;
139 int err;
140 bool compressed = false;
142 if (buf->len <= 0)
143 return;
146 * In order to attempt compression, length must be at least COMPRESS_THRESHOLD,
147 * and our adaptive level must give the OK.
149 if (buf->len >= COMPRESS_THRESHOLD && lzo_adaptive_compress_test (&lzowork->ac))
151 ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
152 ASSERT (buf_safe (&work, LZO_EXTRA_BUFFER (PAYLOAD_SIZE (frame))));
153 ASSERT (buf->len <= PAYLOAD_SIZE (frame));
155 err = LZO_COMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, lzowork->wmem);
156 if (err != LZO_E_OK)
158 dmsg (D_COMP_ERRORS, "LZO compression error: %d", err);
159 buf->len = 0;
160 return;
163 ASSERT (buf_safe (&work, zlen));
164 work.len = zlen;
165 compressed = true;
167 dmsg (D_COMP, "compress %d -> %d", buf->len, work.len);
168 lzowork->pre_compress += buf->len;
169 lzowork->post_compress += work.len;
171 /* tell adaptive level about our success or lack thereof in getting any size reduction */
172 lzo_adaptive_compress_data(&lzowork->ac, buf->len, work.len);
175 /* did compression save us anything ? */
176 if (compressed && work.len < buf->len)
178 uint8_t *header = buf_prepend (&work, 1);
179 *header = YES_COMPRESS;
180 *buf = work;
182 else
184 uint8_t *header = buf_prepend (buf, 1);
185 *header = NO_COMPRESS;
189 void
190 lzo_decompress (struct buffer *buf, struct buffer work,
191 struct lzo_compress_workspace *lzowork,
192 const struct frame* frame)
194 lzo_uint zlen = EXPANDED_SIZE (frame);
195 uint8_t c; /* flag indicating whether or not our peer compressed */
196 int err;
198 if (buf->len <= 0)
199 return;
201 ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
203 c = *BPTR (buf);
204 ASSERT (buf_advance (buf, 1));
206 if (c == YES_COMPRESS) /* packet was compressed */
208 ASSERT (buf_safe (&work, zlen));
209 err = LZO_DECOMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen,
210 lzowork->wmem);
211 if (err != LZO_E_OK)
213 dmsg (D_COMP_ERRORS, "LZO decompression error: %d", err);
214 buf->len = 0;
215 return;
218 ASSERT (buf_safe (&work, zlen));
219 work.len = zlen;
221 dmsg (D_COMP, "decompress %d -> %d", buf->len, work.len);
222 lzowork->pre_decompress += buf->len;
223 lzowork->post_decompress += work.len;
225 *buf = work;
227 else if (c == NO_COMPRESS) /* packet was not compressed */
231 else
233 dmsg (D_COMP_ERRORS, "Bad LZO decompression header byte: %d", c);
234 buf->len = 0;
239 * Print statistics
241 void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct status_output *so)
243 status_printf (so, "pre-compress bytes," counter_format, lzo_compwork->pre_compress);
244 status_printf (so, "post-compress bytes," counter_format, lzo_compwork->post_compress);
245 status_printf (so, "pre-decompress bytes," counter_format, lzo_compwork->pre_decompress);
246 status_printf (so, "post-decompress bytes," counter_format, lzo_compwork->post_decompress);
249 #else
250 static void dummy(void) {}
251 #endif /* USE_LZO */