Browse code

Added support for the Snappy compression algorithm

Added support for the Snappy compression algorithm which has shown to
have considerably better compression speed than LZO at a comparable
compression ratio.

To enable Snappy add:

compress snappy

to both client and server config files.

Alternatively, enable compression framing on the client:

compress

and have the server selectively push "compress snappy" to the client.

This change also extends the client capability handshake to include
IV_SNAPPY so the server can be aware that a connecting client supports
Snappy.

Note that the Snappy implementation also includes an improved framing
approach where the first byte of the compressed payload is replaced by
the compression control byte (the first payload byte is moved to the end
of the packet). This solves off-by-one alignment issues, which improves
performance on ARM.

By default, the configure script will try to build with Snappy support.
To disable, use the --disable-snappy option.

The --enable-lzo-stub configure directive is now --enable-comp-stub
(because it's not actually "lzo" but "compression-enabled packet framing")

Add compression overhead to extra buffer unconditionally, as long
as USE_COMP is defined.

OpenVPN SVN r8206 (2.1.21a) and r8212 (2.1.21b)

Signed-off-by: Gert Doering <gert@greenie.muc.de>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <1366393268-27392-3-git-send-email-gert@greenie.muc.de>
URL: http://article.gmane.org/gmane.network.openvpn.devel/7531
Signed-off-by: Gert Doering <gert@greenie.muc.de>

James Yonan authored on 2012/09/18 15:33:34
Showing 19 changed files
... ...
@@ -46,11 +46,16 @@ AC_ARG_ENABLE(
46 46
 	[enable_lzo="yes"]
47 47
 )
48 48
 
49
-AC_ARG_ENABLE(
50
-	[lzo-stub],
51
-	[AS_HELP_STRING([--enable-lzo-stub], [don't compile LZO compression support but still allow limited interoperability with LZO-enabled peers @<:@default=no@:>@])],
52
-	,
53
-	[enable_lzo_stub="no"]
49
+AC_ARG_ENABLE(snappy,
50
+	[  --disable-snappy        Disable Snappy compression support],
51
+	[enable_snappy="$enableval"],
52
+	[enable_snappy="yes"]
53
+)
54
+
55
+AC_ARG_ENABLE(comp-stub,
56
+	[  --enable-comp-stub      Don't compile compression support but still allow limited interoperability with compression-enabled peers],
57
+	[enable_comp_stub="$enableval"],
58
+	[enable_comp_stub="no"]
54 59
 )
55 60
 
56 61
 AC_ARG_ENABLE(
... ...
@@ -895,6 +900,46 @@ if test "${have_lzo}" = "yes"; then
895 895
 	CFLAGS="${saved_CFLAGS}"
896 896
 fi
897 897
 
898
+dnl
899
+dnl check for Snappy library
900
+dnl
901
+
902
+AC_ARG_VAR([SNAPPY_CFLAGS], [C compiler flags for snappy])
903
+AC_ARG_VAR([SNAPPY_LIBS], [linker flags for snappy])
904
+if test "$enable_snappy" = "yes" && test "$enable_comp_stub" = "no"; then
905
+    AC_CHECKING([for Snappy Library and Header files])
906
+    havesnappylib=1
907
+
908
+    # if SNAPPY_LIBS is set, we assume it will work, otherwise test
909
+    if test -z "${SNAPPY_LIBS}"; then
910
+	AC_CHECK_LIB(snappy, snappy_compress,
911
+	    [ SNAPPY_LIBS="-lsnappy" ],
912
+	    [
913
+	        AC_MSG_RESULT([Snappy library not found.])
914
+	        havesnappylib=0
915
+	    ])
916
+    fi
917
+
918
+    saved_CFLAGS="${CFLAGS}"
919
+    CFLAGS="${CFLAGS} ${SNAPPY_CFLAGS}"
920
+    AC_CHECK_HEADER(snappy-c.h,
921
+       ,
922
+       [
923
+	   AC_MSG_RESULT([Snappy headers not found.])
924
+	   havesnappylib=0
925
+       ])
926
+
927
+    if test $havesnappylib = 0 ; then
928
+	AC_MSG_RESULT([Snappy library available from http://code.google.com/p/snappy/])
929
+        AC_MSG_ERROR([Or try ./configure --disable-snappy OR ./configure --enable-comp-stub])
930
+    fi
931
+    OPTIONAL_SNAPPY_CFLAGS="${SNAPPY_CFLAGS}"
932
+    OPTIONAL_SNAPPY_LIBS="${SNAPPY_LIBS}"
933
+    AC_DEFINE(ENABLE_SNAPPY, 1, [Enable Snappy compression library])
934
+    CFLAGS="${saved_CFLAGS}"
935
+fi
936
+
937
+
898 938
 AC_MSG_CHECKING([git checkout])
899 939
 GIT_CHECKOUT="no"
900 940
 if test -n "${GIT}" -a -d "${srcdir}/.git"; then
... ...
@@ -1003,10 +1048,10 @@ if test "${enable_lzo}" = "yes"; then
1003 1003
 	OPTIONAL_LZO_LIBS="${LZO_LIBS}"
1004 1004
 	AC_DEFINE([ENABLE_LZO], [1], [Enable LZO compression library])
1005 1005
 fi
1006
-if test "${enable_lzo_stub}" = "yes"; then
1007
-	test "${enable_lzo}" = "yes" && AC_MSG_ERROR([Cannot have both lzo stub and lzo enabled])
1008
-	AC_DEFINE([ENABLE_LZO_STUB], [1], [Enable LZO stub capability])
1009
-	AC_DEFINE([ENABLE_LZO], [1], [Enable LZO compression library])
1006
+if test "${enable_comp_stub}" = "yes"; then
1007
+	test "${enable_lzo}" = "yes" && AC_MSG_ERROR([Cannot have both comp stub and lzo enabled (use --disable-lzo)])
1008
+	test "${enable_snappy}" = "yes" && AC_MSG_ERROR([Cannot have both comp stub and snappy enabled (use --disable-snappy)])
1009
+	AC_DEFINE([ENABLE_COMP_STUB], [1], [Enable compression stub capability])
1010 1010
 fi
1011 1011
 
1012 1012
 if test "${enable_pkcs11}" = "yes"; then
... ...
@@ -1060,6 +1105,8 @@ AC_SUBST([OPTIONAL_CRYPTO_CFLAGS])
1060 1060
 AC_SUBST([OPTIONAL_CRYPTO_LIBS])
1061 1061
 AC_SUBST([OPTIONAL_LZO_CFLAGS])
1062 1062
 AC_SUBST([OPTIONAL_LZO_LIBS])
1063
+AC_SUBST([OPTIONAL_SNAPPY_CFLAGS])
1064
+AC_SUBST([OPTIONAL_SNAPPY_LIBS])
1063 1065
 AC_SUBST([OPTIONAL_PKCS11_HELPER_CFLAGS])
1064 1066
 AC_SUBST([OPTIONAL_PKCS11_HELPER_LIBS])
1065 1067
 
... ...
@@ -2352,12 +2352,32 @@ consecutive messages in the same category.  This is useful to
2352 2352
 limit repetitive logging of similar message types.
2353 2353
 .\"*********************************************************
2354 2354
 .TP
2355
+.B \-\-compress [algorithm]
2356
+Enable a compression algorithm.
2357
+
2358
+The
2359
+.B algorithm
2360
+parameter may be "snappy", "lzo", or empty.  Snappy and LZO
2361
+are different compression algorithms, with Snappy generally
2362
+offering the best performance.
2363
+
2364
+If the
2365
+.B algorithm
2366
+parameter is empty, compression will be turned off, but the packet
2367
+framing for compression will still be enabled, allowing a different
2368
+setting to be pushed later.
2369
+.\"*********************************************************
2370
+.TP
2355 2371
 .B \-\-comp-lzo [mode]
2356
-Use fast LZO compression \-\- may add up to 1 byte per
2372
+Use LZO compression \-\- may add up to 1 byte per
2357 2373
 packet for incompressible data.
2358 2374
 .B mode
2359 2375
 may be "yes", "no", or "adaptive" (default).
2360 2376
 
2377
+This option is deprecated in favor of the newer
2378
+.B --compress
2379
+option.
2380
+
2361 2381
 In a server mode setup, it is possible to selectively turn
2362 2382
 compression on or off for individual clients.
2363 2383
 
... ...
@@ -26,6 +26,7 @@ AM_CFLAGS = \
26 26
 	$(TAP_CFLAGS) \
27 27
 	$(OPTIONAL_CRYPTO_CFLAGS) \
28 28
 	$(OPTIONAL_LZO_CFLAGS) \
29
+	$(OPTIONAL_SNAPPY_CFLAGS) \
29 30
 	$(OPTIONAL_PKCS11_HELPER_CFLAGS)
30 31
 if WIN32
31 32
 # we want unicode entry point but not the macro
... ...
@@ -41,6 +42,7 @@ openvpn_SOURCES = \
41 41
 	circ_list.h \
42 42
 	clinat.c clinat.h \
43 43
 	common.h \
44
+	comp.c comp.h compstub.c \
44 45
 	crypto.c crypto.h crypto_backend.h \
45 46
 	crypto_openssl.c crypto_openssl.h \
46 47
 	crypto_polarssl.c crypto_polarssl.h \
... ...
@@ -98,6 +100,7 @@ openvpn_SOURCES = \
98 98
 	session_id.c session_id.h \
99 99
 	shaper.c shaper.h \
100 100
 	sig.c sig.h \
101
+	snappy.c snappy.h \
101 102
 	socket.c socket.h \
102 103
 	socks.c socks.h \
103 104
 	ssl.c ssl.h  ssl_backend.h \
... ...
@@ -116,6 +119,7 @@ openvpn_LDADD = \
116 116
 	$(top_builddir)/src/compat/libcompat.la \
117 117
 	$(SOCKETS_LIBS) \
118 118
 	$(OPTIONAL_LZO_LIBS) \
119
+	$(OPTIONAL_SNAPPY_LIBS) \
119 120
 	$(OPTIONAL_PKCS11_HELPER_LIBS) \
120 121
 	$(OPTIONAL_CRYPTO_LIBS) \
121 122
 	$(OPTIONAL_SELINUX_LIBS) \
122 123
new file mode 100644
... ...
@@ -0,0 +1,135 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single UDP 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) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
8
+ *
9
+ *  This program is free software; you can redistribute it and/or modify
10
+ *  it under the terms of the GNU General Public License version 2
11
+ *  as published by the Free Software Foundation.
12
+ *
13
+ *  This program is distributed in the hope that it will be useful,
14
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ *  GNU General Public License for more details.
17
+ *
18
+ *  You should have received a copy of the GNU General Public License
19
+ *  along with this program (see the file COPYING included with this
20
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
21
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+#ifdef HAVE_CONFIG_H
25
+#include "config.h"
26
+#elif defined(_MSC_VER)
27
+#include "config-msvc.h"
28
+#endif
29
+
30
+#include "syshead.h"
31
+
32
+#ifdef USE_COMP
33
+
34
+#include "comp.h"
35
+#include "error.h"
36
+#include "otime.h"
37
+
38
+#include "memdbg.h"
39
+
40
+struct compress_context *
41
+comp_init(const struct compress_options *opt)
42
+{
43
+  struct compress_context *compctx = NULL;
44
+  switch (opt->alg)
45
+    {
46
+    case COMP_ALG_STUB:
47
+      ALLOC_OBJ_CLEAR (compctx, struct compress_context);
48
+      compctx->flags = opt->flags;
49
+      compctx->alg = comp_stub_alg;
50
+      (*compctx->alg.compress_init)(compctx);
51
+      break;
52
+#ifdef ENABLE_LZO
53
+    case COMP_ALG_LZO:
54
+      ALLOC_OBJ_CLEAR (compctx, struct compress_context);
55
+      compctx->flags = opt->flags;
56
+      compctx->alg = lzo_alg;
57
+      (*compctx->alg.compress_init)(compctx);
58
+      break;
59
+#endif
60
+#ifdef ENABLE_SNAPPY
61
+    case COMP_ALG_SNAPPY:
62
+      ALLOC_OBJ_CLEAR (compctx, struct compress_context);
63
+      compctx->flags = opt->flags;
64
+      compctx->alg = snappy_alg;
65
+      (*compctx->alg.compress_init)(compctx);
66
+      break;
67
+#endif
68
+    }
69
+  return compctx;
70
+}
71
+
72
+void
73
+comp_uninit(struct compress_context *compctx)
74
+{
75
+  if (compctx)
76
+    {
77
+      (*compctx->alg.compress_uninit)(compctx);
78
+      free(compctx);
79
+    }
80
+}
81
+
82
+void
83
+comp_add_to_extra_frame(struct frame *frame)
84
+{
85
+  /* Leave room for our one-byte compressed/didn't-compress prefix byte. */
86
+  frame_add_to_extra_frame (frame, COMP_PREFIX_LEN);
87
+}
88
+
89
+void
90
+comp_add_to_extra_buffer(struct frame *frame)
91
+{
92
+  /* Leave room for compression buffer to expand in worst case scenario
93
+     where data is totally uncompressible */
94
+  frame_add_to_extra_buffer (frame, COMP_EXTRA_BUFFER (EXPANDED_SIZE(frame)));
95
+}
96
+
97
+void
98
+comp_print_stats (const struct compress_context *compctx, struct status_output *so)
99
+{
100
+  if (compctx)
101
+    {
102
+      status_printf (so, "pre-compress bytes," counter_format, compctx->pre_compress);
103
+      status_printf (so, "post-compress bytes," counter_format, compctx->post_compress);
104
+      status_printf (so, "pre-decompress bytes," counter_format, compctx->pre_decompress);
105
+      status_printf (so, "post-decompress bytes," counter_format, compctx->post_decompress);
106
+    }
107
+}
108
+
109
+/*
110
+ * Tell our peer which compression algorithms we support.
111
+ */
112
+void
113
+comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out)
114
+{
115
+  if (opt)
116
+    {
117
+      bool lzo_avail = false;
118
+      if (!(opt->flags & COMP_F_ADVERTISE_STUBS_ONLY))
119
+	{
120
+#if defined(ENABLE_SNAPPY)
121
+	  buf_printf (out, "IV_SNAPPY=1\n");
122
+#endif
123
+#if defined(ENABLE_LZO)
124
+	  buf_printf (out, "IV_LZO=1\n");
125
+	  lzo_avail = true;
126
+#endif
127
+	}
128
+      if (!lzo_avail)
129
+	buf_printf (out, "IV_LZO_STUB=1\n");
130
+      buf_printf (out, "IV_COMP_STUB=1\n");
131
+    }
132
+}
133
+
134
+#endif /* USE_COMP */
0 135
new file mode 100644
... ...
@@ -0,0 +1,171 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single UDP 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) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
8
+ *
9
+ *  This program is free software; you can redistribute it and/or modify
10
+ *  it under the terms of the GNU General Public License version 2
11
+ *  as published by the Free Software Foundation.
12
+ *
13
+ *  This program is distributed in the hope that it will be useful,
14
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ *  GNU General Public License for more details.
17
+ *
18
+ *  You should have received a copy of the GNU General Public License
19
+ *  along with this program (see the file COPYING included with this
20
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
21
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+/*
25
+ * Generic compression support.  Currently we support
26
+ * Snappy and LZO 2.
27
+ */
28
+#ifndef OPENVPN_COMP_H
29
+#define OPENVPN_COMP_H
30
+
31
+#ifdef USE_COMP
32
+
33
+#include "buffer.h"
34
+#include "mtu.h"
35
+#include "common.h"
36
+#include "status.h"
37
+
38
+/* algorithms */
39
+#define COMP_ALG_UNDEF  0
40
+#define COMP_ALG_STUB   1 /* support compression command byte and framing without actual compression */
41
+#define COMP_ALG_LZO    2 /* LZO algorithm */
42
+#define COMP_ALG_SNAPPY 3 /* Snappy algorithm */
43
+
44
+/* Compression flags */
45
+#define COMP_F_ADAPTIVE   (1<<0) /* COMP_ALG_LZO only */
46
+#define COMP_F_ASYM       (1<<1) /* only downlink is compressed, not uplink */
47
+#define COMP_F_SWAP       (1<<2) /* initial command byte is swapped with last byte in buffer to preserve payload alignment */
48
+#define COMP_F_ADVERTISE_STUBS_ONLY (1<<3) /* tell server that we only support compression stubs */
49
+
50
+/*
51
+ * Length of prepended prefix on compressed packets
52
+ */
53
+#define COMP_PREFIX_LEN 1
54
+
55
+/*
56
+ * Prefix bytes
57
+ */
58
+#define NO_COMPRESS_BYTE      0xFA
59
+#define NO_COMPRESS_BYTE_SWAP 0xFB /* to maintain payload alignment, replace this byte with last byte of packet */
60
+
61
+/*
62
+ * Compress worst case size expansion (for any algorithm)
63
+ *
64
+ * LZO:    len + len/8 + 128 + 3
65
+ * Snappy: len + len/6 + 32
66
+ */
67
+#define COMP_EXTRA_BUFFER(len) ((len)/6 + 128 + 3 + COMP_PREFIX_LEN)
68
+
69
+/*
70
+ * Don't try to compress any packet smaller than this.
71
+ */
72
+#define COMPRESS_THRESHOLD 100
73
+
74
+/* Forward declaration of compression context */
75
+struct compress_context;
76
+
77
+/*
78
+ * Virtual methods and other static info for each compression algorithm
79
+ */
80
+struct compress_alg
81
+{
82
+  const char *name;
83
+  void (*compress_init)(struct compress_context *compctx);
84
+  void (*compress_uninit)(struct compress_context *compctx);
85
+  void (*compress)(struct buffer *buf, struct buffer work,
86
+		   struct compress_context *compctx,
87
+		   const struct frame* frame);
88
+
89
+  void (*decompress)(struct buffer *buf, struct buffer work,
90
+		     struct compress_context *compctx,
91
+		     const struct frame* frame);
92
+};
93
+
94
+/*
95
+ * Headers for each compression implementation
96
+ */
97
+#ifdef ENABLE_LZO
98
+#include "lzo.h"
99
+#endif
100
+
101
+#ifdef ENABLE_SNAPPY
102
+#include "snappy.h"
103
+#endif
104
+
105
+/*
106
+ * Information that basically identifies a compression
107
+ * algorithm and related flags.
108
+ */
109
+struct compress_options
110
+{
111
+  int alg;
112
+  unsigned int flags;
113
+};
114
+
115
+/*
116
+ * Workspace union of all supported compression algorithms
117
+ */
118
+union compress_workspace_union
119
+{
120
+#ifdef ENABLE_LZO
121
+  struct lzo_compress_workspace lzo;
122
+#endif
123
+#ifdef ENABLE_SNAPPY
124
+  struct snappy_workspace snappy;
125
+#endif
126
+};
127
+
128
+/*
129
+ * Context for active compression session
130
+ */
131
+struct compress_context
132
+{
133
+  unsigned int flags;
134
+  struct compress_alg alg;
135
+  union compress_workspace_union wu;
136
+
137
+  /* statistics */
138
+  counter_type pre_decompress;
139
+  counter_type post_decompress;
140
+  counter_type pre_compress;
141
+  counter_type post_compress;
142
+};
143
+
144
+extern const struct compress_alg comp_stub_alg;
145
+
146
+struct compress_context *comp_init(const struct compress_options *opt);
147
+
148
+void comp_uninit(struct compress_context *compctx);
149
+
150
+void comp_add_to_extra_frame(struct frame *frame);
151
+void comp_add_to_extra_buffer(struct frame *frame);
152
+
153
+void comp_print_stats (const struct compress_context *compctx, struct status_output *so);
154
+
155
+void comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out);
156
+
157
+static inline bool
158
+comp_enabled(const struct compress_options *info)
159
+{
160
+  return info->alg != COMP_ALG_UNDEF;
161
+}
162
+
163
+static inline bool
164
+comp_unswapped_prefix(const struct compress_options *info)
165
+{
166
+  return !(info->flags & COMP_F_SWAP);
167
+}
168
+
169
+#endif /* USE_COMP */
170
+#endif
0 171
new file mode 100644
... ...
@@ -0,0 +1,118 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single UDP 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) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
8
+ *
9
+ *  This program is free software; you can redistribute it and/or modify
10
+ *  it under the terms of the GNU General Public License version 2
11
+ *  as published by the Free Software Foundation.
12
+ *
13
+ *  This program is distributed in the hope that it will be useful,
14
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ *  GNU General Public License for more details.
17
+ *
18
+ *  You should have received a copy of the GNU General Public License
19
+ *  along with this program (see the file COPYING included with this
20
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
21
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+#ifdef HAVE_CONFIG_H
25
+#include "config.h"
26
+#elif defined(_MSC_VER)
27
+#include "config-msvc.h"
28
+#endif
29
+
30
+#include "syshead.h"
31
+
32
+#if defined(USE_COMP)
33
+
34
+#include "comp.h"
35
+#include "error.h"
36
+#include "otime.h"
37
+
38
+#include "memdbg.h"
39
+
40
+static void
41
+stub_compress_init (struct compress_context *compctx)
42
+{
43
+}
44
+
45
+static void
46
+stub_compress_uninit (struct compress_context *compctx)
47
+{
48
+}
49
+
50
+static void
51
+stub_compress (struct buffer *buf, struct buffer work,
52
+	       struct compress_context *compctx,
53
+	       const struct frame* frame)
54
+{
55
+  if (buf->len <= 0)
56
+    return;
57
+  if (compctx->flags & COMP_F_SWAP)
58
+    {
59
+      uint8_t *head = BPTR (buf);
60
+      uint8_t *tail  = BEND (buf);
61
+      ASSERT (buf_safe (buf, 1));
62
+      ++buf->len;
63
+
64
+      /* move head byte of payload to tail */
65
+      *tail = *head;
66
+      *head = NO_COMPRESS_BYTE_SWAP;
67
+    }
68
+  else
69
+    {
70
+      uint8_t *header = buf_prepend (buf, 1);
71
+      *header = NO_COMPRESS_BYTE;
72
+    }
73
+}
74
+
75
+static void
76
+stub_decompress (struct buffer *buf, struct buffer work,
77
+		 struct compress_context *compctx,
78
+		 const struct frame* frame)
79
+{
80
+  uint8_t c;
81
+  if (buf->len <= 0)
82
+    return;
83
+  if (compctx->flags & COMP_F_SWAP)
84
+    {
85
+      uint8_t *head = BPTR (buf);
86
+      c = *head;
87
+      --buf->len;
88
+      *head = *BEND (buf);
89
+      if (c != NO_COMPRESS_BYTE_SWAP)
90
+	{
91
+	  dmsg (D_COMP_ERRORS, "Bad compression stub (swap) decompression header byte: %d", c);
92
+	  buf->len = 0;
93
+	}
94
+    }
95
+  else
96
+    {
97
+      c = *BPTR (buf);
98
+      ASSERT (buf_advance (buf, 1));
99
+      if (c != NO_COMPRESS_BYTE)
100
+	{
101
+	  dmsg (D_COMP_ERRORS, "Bad compression stub decompression header byte: %d", c);
102
+	  buf->len = 0;
103
+	}
104
+    }
105
+}
106
+
107
+const struct compress_alg comp_stub_alg = {
108
+  "stub",
109
+  stub_compress_init,
110
+  stub_compress_uninit,
111
+  stub_compress,
112
+  stub_decompress
113
+};
114
+
115
+#else
116
+static void dummy(void) {}
117
+#endif /* USE_STUB */
... ...
@@ -444,10 +444,10 @@ encrypt_sign (struct context *c, bool comp_frag)
444 444
 
445 445
   if (comp_frag)
446 446
     {
447
-#ifdef ENABLE_LZO
447
+#ifdef USE_COMP
448 448
       /* Compress the packet. */
449
-      if (lzo_defined (&c->c2.lzo_compwork))
450
-	lzo_compress (&c->c2.buf, b->lzo_compress_buf, &c->c2.lzo_compwork, &c->c2.frame);
449
+      if (c->c2.comp_context)
450
+	(*c->c2.comp_context->alg.compress)(&c->c2.buf, b->compress_buf, c->c2.comp_context, &c->c2.frame);
451 451
 #endif
452 452
 #ifdef ENABLE_FRAGMENT
453 453
       if (c->c2.fragment)
... ...
@@ -846,10 +846,10 @@ process_incoming_link (struct context *c)
846 846
 	fragment_incoming (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment);
847 847
 #endif
848 848
 
849
-#ifdef ENABLE_LZO
849
+#ifdef USE_COMP
850 850
       /* decompress the incoming packet */
851
-      if (lzo_defined (&c->c2.lzo_compwork))
852
-	lzo_decompress (&c->c2.buf, c->c2.buffers->lzo_decompress_buf, &c->c2.lzo_compwork, &c->c2.frame);
851
+      if (c->c2.comp_context)
852
+	(*c->c2.comp_context->alg.decompress)(&c->c2.buf, c->c2.buffers->decompress_buf, c->c2.comp_context, &c->c2.frame);
853 853
 #endif
854 854
 
855 855
 #ifdef PACKET_TRUNCATION_CHECK
... ...
@@ -1770,14 +1770,12 @@ do_deferred_options (struct context *c, const unsigned int found)
1770 1770
     }
1771 1771
 #endif
1772 1772
 
1773
-#ifdef ENABLE_LZO
1773
+#ifdef USE_COMP
1774 1774
   if (found & OPT_P_COMP)
1775 1775
     {
1776
-      if (lzo_defined (&c->c2.lzo_compwork))
1777
-	{
1778
-	  msg (D_PUSH, "OPTIONS IMPORT: LZO parms modified");
1779
-	  lzo_modify_flags (&c->c2.lzo_compwork, c->options.lzo);
1780
-	}
1776
+      msg (D_PUSH, "OPTIONS IMPORT: compression parms modified");
1777
+      comp_uninit (c->c2.comp_context);
1778
+      c->c2.comp_context = comp_init (&c->options.comp);
1781 1779
     }
1782 1780
 #endif
1783 1781
 
... ...
@@ -2272,6 +2270,10 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
2272 2272
 #endif
2273 2273
 #endif
2274 2274
 
2275
+#ifdef USE_COMP
2276
+  to.comp_options = options->comp;
2277
+#endif
2278
+
2275 2279
   /* TLS handshake authentication (--tls-auth) */
2276 2280
   if (options->tls_auth_file)
2277 2281
     {
... ...
@@ -2354,30 +2356,50 @@ do_init_crypto (struct context *c, const unsigned int flags)
2354 2354
 static void
2355 2355
 do_init_frame (struct context *c)
2356 2356
 {
2357
-#ifdef ENABLE_LZO
2357
+#ifdef USE_COMP
2358 2358
   /*
2359
-   * Initialize LZO compression library.
2359
+   * modify frame parameters if compression is enabled
2360 2360
    */
2361
-  if (c->options.lzo & LZO_SELECTED)
2361
+  if (comp_enabled(&c->options.comp))
2362 2362
     {
2363
-      lzo_adjust_frame_parameters (&c->c2.frame);
2363
+      comp_add_to_extra_frame (&c->c2.frame);
2364 2364
 
2365
+#if !defined(ENABLE_SNAPPY)
2365 2366
       /*
2366
-       * LZO usage affects buffer alignment.
2367
+       * Compression usage affects buffer alignment when non-swapped algs
2368
+       * such as LZO is used.
2369
+       * Newer algs like Snappy and comp-stub with COMP_F_SWAP don't need
2370
+       * any special alignment because of the control-byte swap approach.
2371
+       * LZO alignment (on the other hand) is problematic because
2372
+       * the presence of the control byte means that either the output of
2373
+       * decryption must be written to an unaligned buffer, or the input
2374
+       * to compression (or packet dispatch if packet is uncompressed)
2375
+       * must be read from an unaligned buffer.
2376
+       * This code tries to align the input to compression (or packet
2377
+       * dispatch if packet is uncompressed) at the cost of requiring
2378
+       * decryption output to be written to an unaligned buffer, so
2379
+       * it's more of a tradeoff than an optimal solution and we don't
2380
+       * include it when we are doing a modern build with Snappy.
2381
+       * Strictly speaking, on the server it would be better to execute
2382
+       * this code for every connection after we decide the compression
2383
+       * method, but currently the frame code doesn't appear to be
2384
+       * flexible enough for this, since the frame is already established
2385
+       * before it is known which compression options will be pushed.
2367 2386
        */
2368
-      if (CIPHER_ENABLED (c))
2387
+      if (comp_unswapped_prefix (&c->options.comp) && CIPHER_ENABLED (c))
2369 2388
 	{
2370
-	  frame_add_to_align_adjust (&c->c2.frame, LZO_PREFIX_LEN);
2389
+	  frame_add_to_align_adjust (&c->c2.frame, COMP_PREFIX_LEN);
2371 2390
 	  frame_or_align_flags (&c->c2.frame,
2372 2391
 				FRAME_HEADROOM_MARKER_FRAGMENT
2373 2392
 				|FRAME_HEADROOM_MARKER_DECRYPT);
2374 2393
 	}
2394
+#endif
2375 2395
 
2376 2396
 #ifdef ENABLE_FRAGMENT
2377
-      lzo_adjust_frame_parameters (&c->c2.frame_fragment_omit);	/* omit LZO frame delta from final frame_fragment */
2397
+      comp_add_to_extra_frame (&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */
2378 2398
 #endif
2379 2399
     }
2380
-#endif /* ENABLE_LZO */
2400
+#endif /* USE_COMP */
2381 2401
 
2382 2402
 #ifdef ENABLE_SOCKS
2383 2403
   /*
... ...
@@ -2406,6 +2428,17 @@ do_init_frame (struct context *c)
2406 2406
    */
2407 2407
   frame_finalize_options (c, NULL);
2408 2408
 
2409
+#ifdef USE_COMP
2410
+  /*
2411
+   * Modify frame parameters if compression is compiled in.
2412
+   * Should be called after frame_finalize_options.
2413
+   */
2414
+  comp_add_to_extra_buffer (&c->c2.frame);
2415
+#ifdef ENABLE_FRAGMENT
2416
+  comp_add_to_extra_buffer (&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */
2417
+#endif
2418
+#endif /* USE_COMP */
2419
+
2409 2420
 #ifdef ENABLE_FRAGMENT
2410 2421
   /*
2411 2422
    * Set frame parameter for fragment code.  This is necessary because
... ...
@@ -2537,9 +2570,9 @@ init_context_buffers (const struct frame *frame)
2537 2537
   b->decrypt_buf = alloc_buf (BUF_SIZE (frame));
2538 2538
 #endif
2539 2539
 
2540
-#ifdef ENABLE_LZO
2541
-  b->lzo_compress_buf = alloc_buf (BUF_SIZE (frame));
2542
-  b->lzo_decompress_buf = alloc_buf (BUF_SIZE (frame));
2540
+#ifdef USE_COMP
2541
+  b->compress_buf = alloc_buf (BUF_SIZE (frame));
2542
+  b->decompress_buf = alloc_buf (BUF_SIZE (frame));
2543 2543
 #endif
2544 2544
 
2545 2545
   return b;
... ...
@@ -2554,9 +2587,9 @@ free_context_buffers (struct context_buffers *b)
2554 2554
       free_buf (&b->read_tun_buf);
2555 2555
       free_buf (&b->aux_buf);
2556 2556
 
2557
-#ifdef ENABLE_LZO
2558
-      free_buf (&b->lzo_compress_buf);
2559
-      free_buf (&b->lzo_decompress_buf);
2557
+#ifdef USE_COMP
2558
+      free_buf (&b->compress_buf);
2559
+      free_buf (&b->decompress_buf);
2560 2560
 #endif
2561 2561
 
2562 2562
 #ifdef ENABLE_CRYPTO
... ...
@@ -3388,10 +3421,10 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
3388 3388
       goto sig;
3389 3389
   }
3390 3390
 
3391
-#ifdef ENABLE_LZO
3392
-  /* initialize LZO compression library. */
3393
-  if ((options->lzo & LZO_SELECTED) && (c->mode == CM_P2P || child))
3394
-    lzo_compress_init (&c->c2.lzo_compwork, options->lzo);
3391
+#ifdef USE_COMP
3392
+  /* initialize compression library. */
3393
+  if (comp_enabled(&options->comp) && (c->mode == CM_P2P || child))
3394
+    c->c2.comp_context = comp_init (&options->comp);
3395 3395
 #endif
3396 3396
 
3397 3397
   /* initialize MTU variables */
... ...
@@ -3505,9 +3538,12 @@ close_instance (struct context *c)
3505 3505
 	/* if xinetd/inetd mode, don't allow restart */
3506 3506
 	do_close_check_if_restart_permitted (c);
3507 3507
 
3508
-#ifdef ENABLE_LZO
3509
-	if (lzo_defined (&c->c2.lzo_compwork))
3510
-	  lzo_compress_uninit (&c->c2.lzo_compwork);
3508
+#ifdef USE_COMP
3509
+	if (c->c2.comp_context)
3510
+	  {
3511
+	    comp_uninit (c->c2.comp_context);
3512
+	    c->c2.comp_context = NULL;
3513
+	  }
3511 3514
 #endif
3512 3515
 
3513 3516
 	/* free buffers */
... ...
@@ -3631,6 +3667,10 @@ inherit_context_child (struct context *dest,
3631 3631
       dest->c2.link_socket_info->lsa = &dest->c1.link_socket_addr;
3632 3632
       dest->c2.link_socket_info->connection_established = false;
3633 3633
     }
3634
+
3635
+#ifdef USE_COMP
3636
+  dest->c2.comp_context = NULL;
3637
+#endif
3634 3638
 }
3635 3639
 
3636 3640
 void
... ...
@@ -3679,6 +3719,10 @@ inherit_context_top (struct context *dest,
3679 3679
   dest->c2.event_set = NULL;
3680 3680
   if (proto_is_dgram(src->options.ce.proto))
3681 3681
     do_event_set_init (dest, false);
3682
+
3683
+#ifdef USE_COMP
3684
+  dest->c2.comp_context = NULL;
3685
+#endif
3682 3686
 }
3683 3687
 
3684 3688
 void
... ...
@@ -34,15 +34,17 @@
34 34
 
35 35
 #include "syshead.h"
36 36
 
37
-#ifdef ENABLE_LZO
37
+#if defined(ENABLE_LZO)
38 38
 
39
-#include "lzo.h"
39
+#include "comp.h"
40 40
 #include "error.h"
41 41
 #include "otime.h"
42 42
 
43 43
 #include "memdbg.h"
44 44
 
45
-#ifndef ENABLE_LZO_STUB
45
+/* Initial command byte to tell our peer if we compressed */
46
+#define LZO_COMPRESS_BYTE 0x66
47
+
46 48
 /**
47 49
  * Perform adaptive compression housekeeping.
48 50
  *
... ...
@@ -97,101 +99,69 @@ lzo_adaptive_compress_data (struct lzo_adaptive_compress *ac, int n_total, int n
97 97
   ac->n_comp += n_comp;
98 98
 }
99 99
 
100
-#endif /* ENABLE_LZO_STUB */
101
-
102
-void lzo_adjust_frame_parameters (struct frame *frame)
103
-{
104
-  /* Leave room for our one-byte compressed/didn't-compress prefix byte. */
105
-  frame_add_to_extra_frame (frame, LZO_PREFIX_LEN);
106
-
107
-  /* Leave room for compression buffer to expand in worst case scenario
108
-     where data is totally uncompressible */
109
-  frame_add_to_extra_buffer (frame, LZO_EXTRA_BUFFER (EXPANDED_SIZE(frame)));
110
-}
111
-
112
-void
113
-lzo_compress_init (struct lzo_compress_workspace *lzowork, unsigned int flags)
100
+static void
101
+lzo_compress_init (struct compress_context *compctx)
114 102
 {
115
-  CLEAR (*lzowork);
116
-
117
-  lzowork->flags = flags;
118
-#ifndef ENABLE_LZO_STUB
119
-  lzowork->wmem_size = LZO_WORKSPACE;
120
-
103
+  msg (D_INIT_MEDIUM, "LZO compression initializing");
104
+  ASSERT(!(compctx->flags & COMP_F_SWAP));
105
+  compctx->wu.lzo.wmem_size = LZO_WORKSPACE;
121 106
   if (lzo_init () != LZO_E_OK)
122 107
     msg (M_FATAL, "Cannot initialize LZO compression library");
123
-  lzowork->wmem = (lzo_voidp) lzo_malloc (lzowork->wmem_size);
124
-  check_malloc_return (lzowork->wmem);
125
-  msg (D_INIT_MEDIUM, "LZO compression initialized");
126
-#else
127
-  msg (D_INIT_MEDIUM, "LZO stub compression initialized");
128
-#endif
129
-  lzowork->defined = true;
108
+  compctx->wu.lzo.wmem = (lzo_voidp) lzo_malloc (compctx->wu.lzo.wmem_size);
109
+  check_malloc_return (compctx->wu.lzo.wmem);
130 110
 }
131 111
 
132
-void
133
-lzo_compress_uninit (struct lzo_compress_workspace *lzowork)
112
+static void
113
+lzo_compress_uninit (struct compress_context *compctx)
134 114
 {
135
-  if (lzowork)
136
-    {
137
-      ASSERT (lzowork->defined);
138
-#ifndef ENABLE_LZO_STUB
139
-      lzo_free (lzowork->wmem);
140
-      lzowork->wmem = NULL;
141
-#endif
142
-      lzowork->defined = false;
143
-    }
115
+  lzo_free (compctx->wu.lzo.wmem);
116
+  compctx->wu.lzo.wmem = NULL;
144 117
 }
145 118
 
146 119
 static inline bool
147
-lzo_compression_enabled (struct lzo_compress_workspace *lzowork)
120
+lzo_compression_enabled (struct compress_context *compctx)
148 121
 {
149
-#ifndef ENABLE_LZO_STUB
150
-  if ((lzowork->flags & (LZO_SELECTED|LZO_ON)) == (LZO_SELECTED|LZO_ON))
122
+  if (compctx->flags & COMP_F_ASYM)
123
+    return false;
124
+  else
151 125
     {
152
-      if (lzowork->flags & LZO_ADAPTIVE)
153
-	return lzo_adaptive_compress_test (&lzowork->ac);
126
+      if (compctx->flags & COMP_F_ADAPTIVE)
127
+	return lzo_adaptive_compress_test (&compctx->wu.lzo.ac);
154 128
       else
155 129
 	return true;
156 130
     }
157
-#endif
158
-  return false;
159 131
 }
160 132
 
161
-void
133
+static void
162 134
 lzo_compress (struct buffer *buf, struct buffer work,
163
-	      struct lzo_compress_workspace *lzowork,
135
+	      struct compress_context *compctx,
164 136
 	      const struct frame* frame)
165 137
 {
166
-#ifndef ENABLE_LZO_STUB
167 138
   lzo_uint zlen = 0;
168 139
   int err;
169 140
   bool compressed = false;
170
-#endif
171
-
172
-  ASSERT (lzowork->defined);
173 141
 
174 142
   if (buf->len <= 0)
175 143
     return;
176 144
 
177
-#ifndef ENABLE_LZO_STUB
178 145
   /*
179 146
    * In order to attempt compression, length must be at least COMPRESS_THRESHOLD,
180 147
    * and our adaptive level must give the OK.
181 148
    */
182
-  if (buf->len >= COMPRESS_THRESHOLD && lzo_compression_enabled (lzowork))
149
+  if (buf->len >= COMPRESS_THRESHOLD && lzo_compression_enabled (compctx))
183 150
     {
151
+      const size_t ps = PAYLOAD_SIZE (frame);
184 152
       ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
185
-      ASSERT (buf_safe (&work, LZO_EXTRA_BUFFER (PAYLOAD_SIZE (frame))));
153
+      ASSERT (buf_safe (&work, ps + COMP_EXTRA_BUFFER (ps)));
186 154
 
187
-      if (!(buf->len <= PAYLOAD_SIZE (frame)))
155
+      if (buf->len > ps)
188 156
 	{
189 157
 	  dmsg (D_COMP_ERRORS, "LZO compression buffer overflow");
190 158
 	  buf->len = 0;
191 159
 	  return;
192 160
 	}
193 161
 
194
-      err = LZO_COMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, lzowork->wmem);
162
+      err = LZO_COMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, compctx->wu.lzo.wmem);
195 163
       if (err != LZO_E_OK)
196 164
 	{
197 165
 	  dmsg (D_COMP_ERRORS, "LZO compression error: %d", err);
... ...
@@ -203,43 +173,38 @@ lzo_compress (struct buffer *buf, struct buffer work,
203 203
       work.len = zlen;
204 204
       compressed = true;
205 205
 
206
-      dmsg (D_COMP, "compress %d -> %d", buf->len, work.len);
207
-      lzowork->pre_compress += buf->len;
208
-      lzowork->post_compress += work.len;
206
+      dmsg (D_COMP, "LZO compress %d -> %d", buf->len, work.len);
207
+      compctx->pre_compress += buf->len;
208
+      compctx->post_compress += work.len;
209 209
 
210 210
       /* tell adaptive level about our success or lack thereof in getting any size reduction */
211
-      if (lzowork->flags & LZO_ADAPTIVE)
212
-	lzo_adaptive_compress_data (&lzowork->ac, buf->len, work.len);
211
+      if (compctx->flags & COMP_F_ADAPTIVE)
212
+	lzo_adaptive_compress_data (&compctx->wu.lzo.ac, buf->len, work.len);
213 213
     }
214 214
 
215 215
   /* did compression save us anything ? */
216 216
   if (compressed && work.len < buf->len)
217 217
     {
218 218
       uint8_t *header = buf_prepend (&work, 1);
219
-      *header = YES_COMPRESS;
219
+      *header = LZO_COMPRESS_BYTE;
220 220
       *buf = work;
221 221
     }
222 222
   else
223
-#endif
224 223
     {
225 224
       uint8_t *header = buf_prepend (buf, 1);
226
-      *header = NO_COMPRESS;
225
+      *header = NO_COMPRESS_BYTE;
227 226
     }
228 227
 }
229 228
 
230
-void
229
+static void
231 230
 lzo_decompress (struct buffer *buf, struct buffer work,
232
-		struct lzo_compress_workspace *lzowork,
231
+		struct compress_context *compctx,
233 232
 		const struct frame* frame)
234 233
 {
235
-#ifndef ENABLE_LZO_STUB
236 234
   lzo_uint zlen = EXPANDED_SIZE (frame);
237 235
   int err;
238
-#endif
239 236
   uint8_t c;		/* flag indicating whether or not our peer compressed */
240 237
 
241
-  ASSERT (lzowork->defined);
242
-
243 238
   if (buf->len <= 0)
244 239
     return;
245 240
 
... ...
@@ -248,12 +213,11 @@ lzo_decompress (struct buffer *buf, struct buffer work,
248 248
   c = *BPTR (buf);
249 249
   ASSERT (buf_advance (buf, 1));
250 250
 
251
-  if (c == YES_COMPRESS)	/* packet was compressed */
251
+  if (c == LZO_COMPRESS_BYTE)	/* packet was compressed */
252 252
     {
253
-#ifndef ENABLE_LZO_STUB
254 253
       ASSERT (buf_safe (&work, zlen));
255 254
       err = LZO_DECOMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen,
256
-			    lzowork->wmem);
255
+			    compctx->wu.lzo.wmem);
257 256
       if (err != LZO_E_OK)
258 257
 	{
259 258
 	  dmsg (D_COMP_ERRORS, "LZO decompression error: %d", err);
... ...
@@ -264,18 +228,13 @@ lzo_decompress (struct buffer *buf, struct buffer work,
264 264
       ASSERT (buf_safe (&work, zlen));
265 265
       work.len = zlen;
266 266
 
267
-      dmsg (D_COMP, "decompress %d -> %d", buf->len, work.len);
268
-      lzowork->pre_decompress += buf->len;
269
-      lzowork->post_decompress += work.len;
267
+      dmsg (D_COMP, "LZO decompress %d -> %d", buf->len, work.len);
268
+      compctx->pre_decompress += buf->len;
269
+      compctx->post_decompress += work.len;
270 270
 
271 271
       *buf = work;
272
-#else
273
-      dmsg (D_COMP_ERRORS, "LZO decompression error: LZO capability not compiled");
274
-      buf->len = 0;
275
-      return;
276
-#endif
277 272
     }
278
-  else if (c == NO_COMPRESS)	/* packet was not compressed */
273
+  else if (c == NO_COMPRESS_BYTE)	/* packet was not compressed */
279 274
     {
280 275
       ;
281 276
     }
... ...
@@ -286,24 +245,13 @@ lzo_decompress (struct buffer *buf, struct buffer work,
286 286
     }
287 287
 }
288 288
 
289
-void
290
-lzo_modify_flags (struct lzo_compress_workspace *lzowork, unsigned int flags)
291
-{
292
-  ASSERT (lzowork->defined);
293
-  lzowork->flags = flags;
294
-}
295
-
296
-void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct status_output *so)
297
-{
298
-  ASSERT (lzo_compwork->defined);
299
-
300
-#ifndef ENABLE_LZO_STUB
301
-  status_printf (so, "pre-compress bytes," counter_format, lzo_compwork->pre_compress);
302
-  status_printf (so, "post-compress bytes," counter_format, lzo_compwork->post_compress);
303
-  status_printf (so, "pre-decompress bytes," counter_format, lzo_compwork->pre_decompress);
304
-  status_printf (so, "post-decompress bytes," counter_format, lzo_compwork->post_decompress);
305
-#endif
306
-}
289
+const struct compress_alg lzo_alg = {
290
+  "lzo",
291
+  lzo_compress_init,
292
+  lzo_compress_uninit,
293
+  lzo_compress,
294
+  lzo_decompress
295
+};
307 296
 
308 297
 #else
309 298
 static void dummy(void) {}
... ...
@@ -32,14 +32,13 @@
32 32
  */
33 33
 
34 34
 
35
-#ifdef ENABLE_LZO
35
+#if defined(ENABLE_LZO)
36 36
 
37 37
 /**
38 38
  * @addtogroup compression
39 39
  * @{
40 40
  */
41 41
 
42
-#ifndef ENABLE_LZO_STUB
43 42
 #if defined(HAVE_LZO_LZOUTIL_H)
44 43
 #include "lzo/lzoutil.h"
45 44
 #elif defined(HAVE_LZOUTIL_H)
... ...
@@ -50,28 +49,16 @@
50 50
 #elif defined(HAVE_LZO1X_H)
51 51
 #include "lzo1x.h"
52 52
 #endif
53
-#endif
54 53
 
55 54
 #include "buffer.h"
56 55
 #include "mtu.h"
57 56
 #include "common.h"
58 57
 #include "status.h"
59 58
 
60
-/**************************************************************************/
61
-/** @name Bit-flags which control data channel packet compression *//******/
62
-/** @{ */
63
-#define LZO_SELECTED   (1<<0)   /**< Bit-flag indicating that compression
64
-                                 *   of data channel packets is enabled. */
65
-#define LZO_ON         (1<<1)   /**< Bit-flag indicating that compression
66
-                                 *   of data channel packets is active. */
67
-#define LZO_ADAPTIVE   (1<<2)   /**< Bit-flag indicating that adaptive
68
-                                 *   compression of data channel packets
69
-                                 *   has been selected. */
70
-/** @} name Bit-flags which control data channel packet compression *//****/
59
+extern const struct compress_alg lzo_alg;
71 60
 
72 61
 /**************************************************************************/
73 62
 /** @name LZO library interface defines *//** @{ *//***********************/
74
-#ifndef ENABLE_LZO_STUB
75 63
 #define LZO_COMPRESS    lzo1x_1_15_compress
76 64
                                 /**< LZO library compression function.
77 65
                                  *
... ...
@@ -93,36 +80,11 @@
93 93
                                  *   verify the integrity of incoming
94 94
                                  *   packets, you might want to consider
95 95
                                  *   using the non-safe version. */
96
-#endif /* ENABLE_LZO_STUB */
97 96
 /** @} name LZO library interface *//**************************************/
98 97
 
99 98
 
100 99
 /**************************************************************************/
101
-/** @name Miscellaneous compression defines *//** @{ *//*******************/
102
-#define LZO_EXTRA_BUFFER(len) ((len)/8 + 128 + 3)
103
-                                /**< LZO 2.0 worst-case size expansion. */
104
-#ifndef ENABLE_LZO_STUB
105
-#define COMPRESS_THRESHOLD 100  /**< Minimum packet size to attempt
106
-                                 *   compression. */
107
-#endif /* ENABLE_LZO_STUB */
108
-/** @} name Miscellaneous compression defines *//**************************/
109
-
110
-
111
-/**************************************************************************/
112
-/** @name Compression header defines *//** @{ *//**************************/
113
-#define LZO_PREFIX_LEN 1        /**< Length in bytes of prepended
114
-                                 *   compression header. */
115
-#define YES_COMPRESS 0x66       /**< Single-byte compression header
116
-                                 *   indicating this packet has been
117
-                                 *   compressed. */
118
-#define NO_COMPRESS  0xFA       /**< Single-byte compression header
119
-                                 *   indicating this packet has not been
120
-                                 *   compressed. */
121
-/** @} name Compression header defines *//*********************************/
122
-
123
-/**************************************************************************/
124 100
 /** @name Adaptive compression defines *//** @{ *//************************/
125
-#ifndef ENABLE_LZO_STUB
126 101
 #define AC_SAMP_SEC    2        /**< Number of seconds in a sample period. */
127 102
 #define AC_MIN_BYTES   1000     /**< Minimum number of bytes a sample
128 103
                                  *   period must contain for it to be
... ...
@@ -132,11 +94,8 @@
132 132
                                  *   turned off. */
133 133
 #define AC_OFF_SEC     60       /**< Seconds to wait after compression has
134 134
                                  *   been turned off before retesting. */
135
-#endif /* ENABLE_LZO_STUB */
136 135
 /** @} name Adaptive compression defines *//*******************************/
137 136
 
138
-#ifndef ENABLE_LZO_STUB
139
-
140 137
 /**
141 138
  * Adaptive compression state.
142 139
  */
... ...
@@ -147,8 +106,6 @@ struct lzo_adaptive_compress {
147 147
   int n_comp;
148 148
 };
149 149
 
150
-#endif /* ENABLE_LZO_STUB */
151
-
152 150
 
153 151
 /**
154 152
  * State for the compression and decompression routines.
... ...
@@ -162,186 +119,13 @@ struct lzo_adaptive_compress {
162 162
  */
163 163
 struct lzo_compress_workspace
164 164
 {
165
-  bool defined;
166
-  unsigned int flags;
167
-#ifndef ENABLE_LZO_STUB
168 165
   lzo_voidp wmem;
169 166
   int wmem_size;
170 167
   struct lzo_adaptive_compress ac;
171
-
172
-  /* statistics */
173
-  counter_type pre_decompress;
174
-  counter_type post_decompress;
175
-  counter_type pre_compress;
176
-  counter_type post_compress;
177
-#endif
178 168
 };
179 169
 
180
-
181
-/**************************************************************************/
182
-/** @name Functions for initialization and cleanup *//** @{ *//************/
183
-
184
-/**
185
- * Adjust %frame parameters for data channel payload compression.
186
- *
187
- * Data channel packet compression requires a single-byte header to
188
- * indicate whether a packet has been compressed or not. The packet
189
- * handling buffers must also allow for worst-case payload compression
190
- * where the compressed content size is actually larger than the original
191
- * content size. This function adjusts the parameters of a given frame
192
- * structure to include the header and allow for worst-case compression
193
- * expansion.
194
- *
195
- * @param frame        - The frame structure to adjust.
196
- */
197
-void lzo_adjust_frame_parameters(struct frame *frame);
198
-
199
-/**
200
- * Initialize a compression workspace structure.
201
- *
202
- * This function initializes the given workspace structure \a lzowork.
203
- * This includes allocating a work buffer for internal use and setting its
204
- * flags to the given value of \a flags.
205
- *
206
- * This function also initializes the lzo library.
207
- *
208
- * @param lzowork      - A pointer to the workspace structure to
209
- *                       initialize.
210
- * @param flags        - The initial flags to set in the workspace
211
- *                       structure.
212
- */
213
-void lzo_compress_init (struct lzo_compress_workspace *lzowork, unsigned int flags);
214
-
215
-/**
216
- * Cleanup a compression workspace structure.
217
- *
218
- * This function cleans up the given workspace structure \a lzowork.  This
219
- * includes freeing the structure's internal work buffer.
220
- *
221
- * @param lzowork      - A pointer to the workspace structure to clean up.
222
- */
223
-void lzo_compress_uninit (struct lzo_compress_workspace *lzowork);
224
-
225
-/**
226
- * Set a workspace structure's flags.
227
- *
228
- * @param lzowork      - The workspace structure of which to modify the
229
- *                       flags.
230
- * @param flags        - The new value to assign to the workspace
231
- *                       structure's flags.
232
- */
233
-void lzo_modify_flags (struct lzo_compress_workspace *lzowork, unsigned int flags);
234
-
235
-/** @} name Functions for initialization and cleanup *//*******************/
236
-
237
-
238
-/**************************************************************************/
239
-/** @name Function for packets to be sent to a remote OpenVPN peer *//*****/
240
-/** @{ */
241
-
242
-/**
243
- * Process an outgoing packet according to a VPN tunnel's settings.
244
- * @ingroup compression
245
- *
246
- * This function processes the packet contained in \a buf.  Its behavior
247
- * depends on the settings contained within \a lzowork.  If compression is
248
- * enabled and active, this function compresses the packet.  After
249
- * compression, the size of the uncompressed and compressed packets are
250
- * compared, and the smallest is used.
251
- *
252
- * This function prepends a one-byte header indicating whether the packet
253
- * was or was not compressed, so as to let the peer know how to handle the
254
- * packet.
255
- *
256
- * If an error occurs during processing, an error message is logged and
257
- * the length of \a buf is set to zero.
258
- *
259
- * @param buf          - A pointer to the buffer containing the outgoing
260
- *                       packet.  This pointer will be modified to point
261
- *                       to the processed packet on return.
262
- * @param work         - A preallocated working buffer.
263
- * @param lzowork      - The compression workspace structure associated
264
- *                       with this VPN tunnel.
265
- * @param frame        - The frame parameters of this tunnel.
266
- *
267
- * @return Void.\n  On return, \a buf will point to a buffer containing
268
- *     the processed, possibly compressed, packet data with a compression
269
- *     header prepended.
270
- */
271
-void lzo_compress (struct buffer *buf, struct buffer work,
272
-		   struct lzo_compress_workspace *lzowork,
273
-		   const struct frame* frame);
274
-
275
-/** @} name Function for packets to be sent to a remote OpenVPN peer *//***/
276
-
277
-
278
-/**************************************************************************/
279
-/** @name Function for packets received from a remote OpenVPN peer *//*****/
280
-/** @{ */
281
-
282
-/**
283
- * Inspect an incoming packet and decompress if it is compressed.
284
- *
285
- * This function inspects the incoming packet contained in \a buf.  If its
286
- * one-byte compression header indicates that it was compressed (i.e. \c
287
- * YES_COMPRESS), then it will be decompressed.  If its header indicates
288
- * that it was not compressed (i.e. \c NO_COMPRESS), then the buffer is
289
- * not modified except for removing the compression header.
290
- *
291
- * If an error occurs during processing, for example if the compression
292
- * header has a value other than \c YES_COMPRESS or \c NO_COMPRESS, then
293
- * the error is logged and the length of \a buf is set to zero.
294
- *
295
- * @param buf          - A pointer to the buffer containing the incoming
296
- *                       packet.  This pointer will be modified to point
297
- *                       to the processed packet on return.
298
- * @param work         - A preallocated working buffer.
299
- * @param lzowork      - The compression workspace structure associated
300
- *                       with this VPN tunnel.
301
- * @param frame        - The frame parameters of this tunnel.
302
- *
303
- * @return Void.\n  On return, \a buf will point to a buffer containing
304
- *     the uncompressed packet data and the one-byte compression header
305
- *     will have been removed.
306
- */
307
-void lzo_decompress (struct buffer *buf, struct buffer work,
308
-		     struct lzo_compress_workspace *lzowork,
309
-		     const struct frame* frame);
310
-
311
-/** @} name Function for packets received from a remote OpenVPN peer *//***/
312
-
313
-
314
-/**************************************************************************/
315
-/** @name Utility functions *//** @{ *//***********************************/
316
-
317
-/**
318
- * Print statistics on compression and decompression performance.
319
- *
320
- * @param lzo_compwork - The workspace structure from which to get the
321
- *                       statistics.
322
- * @param so           - The status output structure to which to write the
323
- *                       statistics.
324
- */
325
-void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct status_output *so);
326
-
327
-/**
328
- * Check whether compression is enabled for a workspace structure.
329
- *
330
- * @param lzowork      - The workspace structure to check.
331
- *
332
- * @return true if compression is enabled; false otherwise.
333
- */
334
-static inline bool
335
-lzo_defined (const struct lzo_compress_workspace *lzowork)
336
-{
337
-  return lzowork->defined;
338
-}
339
-
340
-/** @} name Utility functions *//******************************************/
341
-
342
-
343 170
 /** @} addtogroup compression */
344 171
 
345 172
 
346
-#endif /* ENABLE_LZO */
173
+#endif /* ENABLE_LZO && USE_COMP */
347 174
 #endif
... ...
@@ -31,7 +31,7 @@
31 31
 #include "crypto.h"
32 32
 #include "ssl.h"
33 33
 #include "packet_id.h"
34
-#include "lzo.h"
34
+#include "comp.h"
35 35
 #include "tun.h"
36 36
 #include "interval.h"
37 37
 #include "status.h"
... ...
@@ -104,10 +104,10 @@ struct context_buffers
104 104
   struct buffer decrypt_buf;
105 105
 #endif
106 106
 
107
-  /* workspace buffers for LZO compression */
108
-#ifdef ENABLE_LZO
109
-  struct buffer lzo_compress_buf;
110
-  struct buffer lzo_decompress_buf;
107
+  /* workspace buffers for compression */
108
+#ifdef USE_COMP
109
+  struct buffer compress_buf;
110
+  struct buffer decompress_buf;
111 111
 #endif
112 112
 
113 113
   /*
... ...
@@ -372,9 +372,9 @@ struct context_2
372 372
 
373 373
 #endif /* ENABLE_CRYPTO */
374 374
 
375
-#ifdef ENABLE_LZO
376
-  struct lzo_compress_workspace lzo_compwork;
377
-                                /**< Compression workspace used by the
375
+#ifdef USE_COMP
376
+  struct compress_context *comp_context;
377
+                                /**< Compression context used by the
378 378
                                  *   \link compression Data Channel
379 379
                                  *   Compression module\endlink. */
380 380
 #endif
... ...
@@ -87,13 +87,17 @@ const char title_string[] =
87 87
 #endif /* defined(ENABLE_CRYPTO_POLARSSL) */
88 88
 #endif /* ENABLE_SSL */
89 89
 #endif /* ENABLE_CRYPTO */
90
+#ifdef USE_COMP
90 91
 #ifdef ENABLE_LZO
91
-#ifdef ENABLE_LZO_STUB
92
-  " [LZO (STUB)]"
93
-#else
94 92
   " [LZO]"
95 93
 #endif
94
+#ifdef ENABLE_SNAPPY
95
+  " [SNAPPY]"
96
+#endif
97
+#ifdef ENABLE_COMP_STUB
98
+  " [COMP_STUB]"
96 99
 #endif
100
+#endif /* USE_COMP */
97 101
 #if EPOLL
98 102
   " [EPOLL]"
99 103
 #endif
... ...
@@ -365,12 +369,15 @@ static const char usage_message[] =
365 365
 #ifdef ENABLE_DEBUG
366 366
   "--gremlin mask  : Special stress testing mode (for debugging only).\n"
367 367
 #endif
368
-#ifdef ENABLE_LZO
369
-  "--comp-lzo      : Use fast LZO compression -- may add up to 1 byte per\n"
368
+#if defined(USE_COMP)
369
+  "--compress alg  : Use compression algorithm alg\n"
370
+#if defined(ENABLE_LZO)
371
+  "--comp-lzo      : Use LZO compression -- may add up to 1 byte per\n"
370 372
   "                  packet for uncompressible data.\n"
371 373
   "--comp-noadapt  : Don't use adaptive compression when --comp-lzo\n"
372 374
   "                  is specified.\n"
373 375
 #endif
376
+#endif
374 377
 #ifdef ENABLE_MANAGEMENT
375 378
   "--management ip port [pass] : Enable a TCP server on ip:port to handle\n"
376 379
   "                  management functions.  pass is a password file\n"
... ...
@@ -1514,8 +1521,9 @@ show_settings (const struct options *o)
1514 1514
 
1515 1515
   SHOW_BOOL (fast_io);
1516 1516
 
1517
-#ifdef ENABLE_LZO
1518
-  SHOW_INT (lzo);
1517
+#ifdef USE_COMP
1518
+  SHOW_INT (comp.alg);
1519
+  SHOW_INT (comp.flags);
1519 1520
 #endif
1520 1521
 
1521 1522
   SHOW_STR (route_script);
... ...
@@ -2886,6 +2894,7 @@ pre_pull_restore (struct options *o)
2886 2886
  *                 the other end of the connection]
2887 2887
  *
2888 2888
  * --comp-lzo
2889
+ * --compress alg
2889 2890
  * --fragment
2890 2891
  *
2891 2892
  * Crypto Options:
... ...
@@ -2967,9 +2976,9 @@ options_string (const struct options *o,
2967 2967
       tt = NULL;
2968 2968
     }
2969 2969
 
2970
-#ifdef ENABLE_LZO
2971
-  if (o->lzo & LZO_SELECTED)
2972
-    buf_printf (&out, ",comp-lzo");
2970
+#ifdef USE_COMP
2971
+  if (o->comp.alg != COMP_ALG_UNDEF)
2972
+    buf_printf (&out, ",comp-lzo"); /* for compatibility, this simply indicates that compression context is active, not necessarily LZO per-se */
2973 2973
 #endif
2974 2974
 
2975 2975
 #ifdef ENABLE_FRAGMENT
... ...
@@ -6137,18 +6146,31 @@ add_option (struct options *options,
6137 6137
       options->passtos = true;
6138 6138
     }
6139 6139
 #endif
6140
-#ifdef ENABLE_LZO
6140
+#if defined(USE_COMP)
6141 6141
   else if (streq (p[0], "comp-lzo"))
6142 6142
     {
6143 6143
       VERIFY_PERMISSION (OPT_P_COMP);
6144
-      if (p[1])
6144
+
6145
+#if defined(ENABLE_LZO)
6146
+      if (p[1] && streq (p[1], "no"))
6147
+#endif
6148
+	{
6149
+	  options->comp.alg = COMP_ALG_STUB;
6150
+	  options->comp.flags = 0;
6151
+	}
6152
+#if defined(ENABLE_LZO)
6153
+      else if (p[1])
6145 6154
 	{
6146 6155
 	  if (streq (p[1], "yes"))
6147
-	    options->lzo = LZO_SELECTED|LZO_ON;
6148
-	  else if (streq (p[1], "no"))
6149
-	    options->lzo = LZO_SELECTED;
6156
+	    {
6157
+	      options->comp.alg = COMP_ALG_LZO;
6158
+	      options->comp.flags = 0;
6159
+	    }
6150 6160
 	  else if (streq (p[1], "adaptive"))
6151
-	    options->lzo = LZO_SELECTED|LZO_ON|LZO_ADAPTIVE;
6161
+	    {
6162
+	      options->comp.alg = COMP_ALG_LZO;
6163
+	      options->comp.flags = COMP_F_ADAPTIVE;
6164
+	    }
6152 6165
 	  else
6153 6166
 	    {
6154 6167
 	      msg (msglevel, "bad comp-lzo option: %s -- must be 'yes', 'no', or 'adaptive'", p[1]);
... ...
@@ -6156,14 +6178,54 @@ add_option (struct options *options,
6156 6156
 	    }
6157 6157
 	}
6158 6158
       else
6159
-	options->lzo = LZO_SELECTED|LZO_ON|LZO_ADAPTIVE;
6159
+	{
6160
+	  options->comp.alg = COMP_ALG_LZO;
6161
+	  options->comp.flags = COMP_F_ADAPTIVE;
6162
+	}
6163
+#endif
6160 6164
     }
6161 6165
   else if (streq (p[0], "comp-noadapt"))
6162 6166
     {
6163 6167
       VERIFY_PERMISSION (OPT_P_COMP);
6164
-      options->lzo &= ~LZO_ADAPTIVE;
6168
+      options->comp.flags &= ~COMP_F_ADAPTIVE;
6169
+    }
6170
+  else if (streq (p[0], "compress"))
6171
+    {
6172
+      VERIFY_PERMISSION (OPT_P_COMP);
6173
+      if (p[1])
6174
+	{
6175
+	  if (streq (p[1], "stub"))
6176
+	    {
6177
+	      options->comp.alg = COMP_ALG_STUB;
6178
+	      options->comp.flags = (COMP_F_SWAP|COMP_F_ADVERTISE_STUBS_ONLY);
6179
+	    }
6180
+#if defined(ENABLE_LZO)
6181
+	  else if (streq (p[1], "lzo"))
6182
+	    {
6183
+	      options->comp.alg = COMP_ALG_LZO;
6184
+	      options->comp.flags = 0;
6185
+	    }
6186
+#endif
6187
+#if defined(ENABLE_SNAPPY)
6188
+	  else if (streq (p[1], "snappy"))
6189
+	    {
6190
+	      options->comp.alg = COMP_ALG_SNAPPY;
6191
+	      options->comp.flags = COMP_F_SWAP;
6192
+	    }
6193
+#endif
6194
+	  else
6195
+	    {
6196
+	      msg (msglevel, "bad comp option: %s", p[1]);
6197
+	      goto err;
6198
+	    }
6199
+	}
6200
+      else
6201
+	{
6202
+	  options->comp.alg = COMP_ALG_STUB;
6203
+	  options->comp.flags = COMP_F_SWAP;
6204
+	}
6165 6205
     }
6166
-#endif /* ENABLE_LZO */
6206
+#endif /* USE_COMP */
6167 6207
 #ifdef ENABLE_CRYPTO
6168 6208
   else if (streq (p[0], "show-ciphers"))
6169 6209
     {
... ...
@@ -39,7 +39,7 @@
39 39
 #include "plugin.h"
40 40
 #include "manage.h"
41 41
 #include "proxy.h"
42
-#include "lzo.h"
42
+#include "comp.h"
43 43
 #include "pushlist.h"
44 44
 #include "clinat.h"
45 45
 
... ...
@@ -312,9 +312,8 @@ struct options
312 312
   /* optimize TUN/TAP/UDP writes */
313 313
   bool fast_io;
314 314
 
315
-#ifdef ENABLE_LZO
316
-  /* LZO_x flags from lzo.h */
317
-  unsigned int lzo;
315
+#ifdef USE_COMP
316
+  struct compress_options comp;
318 317
 #endif
319 318
 
320 319
   /* buffer sizes */
... ...
@@ -265,9 +265,9 @@ print_status (const struct context *c, struct status_output *so)
265 265
   status_printf (so, "TCP/UDP read bytes," counter_format, c->c2.link_read_bytes);
266 266
   status_printf (so, "TCP/UDP write bytes," counter_format, c->c2.link_write_bytes);
267 267
   status_printf (so, "Auth read bytes," counter_format, c->c2.link_read_bytes_auth);
268
-#ifdef ENABLE_LZO
269
-  if (lzo_defined (&c->c2.lzo_compwork))
270
-    lzo_print_stats (&c->c2.lzo_compwork, so);
268
+#ifdef USE_COMP
269
+  if (c->c2.comp_context)
270
+    comp_print_stats (c->c2.comp_context, so);
271 271
 #endif
272 272
 #ifdef PACKET_TRUNCATION_CHECK
273 273
   status_printf (so, "TUN read truncations," counter_format, c->c2.n_trunc_tun_read);
274 274
new file mode 100644
... ...
@@ -0,0 +1,189 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single UDP 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) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
8
+ *
9
+ *  This program is free software; you can redistribute it and/or modify
10
+ *  it under the terms of the GNU General Public License version 2
11
+ *  as published by the Free Software Foundation.
12
+ *
13
+ *  This program is distributed in the hope that it will be useful,
14
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ *  GNU General Public License for more details.
17
+ *
18
+ *  You should have received a copy of the GNU General Public License
19
+ *  along with this program (see the file COPYING included with this
20
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
21
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+#ifdef HAVE_CONFIG_H
25
+#include "config.h"
26
+#elif defined(_MSC_VER)
27
+#include "config-msvc.h"
28
+#endif
29
+
30
+#include "syshead.h"
31
+
32
+#if defined(ENABLE_SNAPPY)
33
+
34
+#include "snappy-c.h"
35
+
36
+#include "comp.h"
37
+#include "error.h"
38
+#include "otime.h"
39
+
40
+#include "memdbg.h"
41
+
42
+/* Initial command byte to tell our peer if we compressed */
43
+#define SNAPPY_COMPRESS_BYTE 0x68
44
+
45
+static void
46
+snap_compress_init (struct compress_context *compctx)
47
+{
48
+  msg (D_INIT_MEDIUM, "Snappy compression initializing");
49
+  ASSERT(compctx->flags & COMP_F_SWAP);
50
+}
51
+
52
+static void
53
+snap_compress_uninit (struct compress_context *compctx)
54
+{
55
+}
56
+
57
+static void
58
+snap_compress (struct buffer *buf, struct buffer work,
59
+	       struct compress_context *compctx,
60
+	       const struct frame* frame)
61
+{
62
+  snappy_status status;
63
+  bool compressed = false;
64
+
65
+  if (buf->len <= 0)
66
+    return;
67
+
68
+  /*
69
+   * In order to attempt compression, length must be at least COMPRESS_THRESHOLD.
70
+   */
71
+  if (buf->len >= COMPRESS_THRESHOLD)
72
+    {
73
+      const size_t ps = PAYLOAD_SIZE (frame);
74
+      size_t zlen = ps + COMP_EXTRA_BUFFER (ps);
75
+
76
+      ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
77
+      ASSERT (buf_safe (&work, zlen));
78
+
79
+      if (buf->len > ps)
80
+	{
81
+	  dmsg (D_COMP_ERRORS, "Snappy compression buffer overflow");
82
+	  buf->len = 0;
83
+	  return;
84
+	}
85
+
86
+      status = snappy_compress((const char *)BPTR(buf), (size_t)BLEN(buf), (char *)BPTR(&work), &zlen);
87
+      if (status != SNAPPY_OK)
88
+	{
89
+	  dmsg (D_COMP_ERRORS, "Snappy compression error: %d", status);
90
+	  buf->len = 0;
91
+	  return;
92
+	}
93
+
94
+      ASSERT (buf_safe (&work, zlen));
95
+      work.len = zlen;
96
+      compressed = true;
97
+
98
+      dmsg (D_COMP, "Snappy compress %d -> %d", buf->len, work.len);
99
+      compctx->pre_compress += buf->len;
100
+      compctx->post_compress += work.len;
101
+    }
102
+
103
+  /* did compression save us anything? */
104
+  {
105
+    uint8_t comp_head_byte = NO_COMPRESS_BYTE_SWAP;
106
+    if (compressed && work.len < buf->len)
107
+      {
108
+	*buf = work;
109
+	comp_head_byte = SNAPPY_COMPRESS_BYTE;
110
+      }
111
+
112
+    {
113
+      uint8_t *head = BPTR (buf);
114
+      uint8_t *tail  = BEND (buf);
115
+      ASSERT (buf_safe (buf, 1));
116
+      ++buf->len;
117
+
118
+      /* move head byte of payload to tail */
119
+      *tail = *head;
120
+      *head = comp_head_byte;
121
+    }
122
+  }
123
+}
124
+
125
+static void
126
+snap_decompress (struct buffer *buf, struct buffer work,
127
+		 struct compress_context *compctx,
128
+		 const struct frame* frame)
129
+{
130
+  size_t zlen = EXPANDED_SIZE (frame);
131
+  snappy_status status;
132
+  uint8_t c;		/* flag indicating whether or not our peer compressed */
133
+
134
+  if (buf->len <= 0)
135
+    return;
136
+
137
+  ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
138
+
139
+  /* do unframing/swap (assumes buf->len > 0) */
140
+  {
141
+    uint8_t *head = BPTR (buf);
142
+    c = *head;
143
+    --buf->len;
144
+    *head = *BEND (buf);
145
+  }
146
+
147
+  if (c == SNAPPY_COMPRESS_BYTE)	/* packet was compressed */
148
+    {
149
+      ASSERT (buf_safe (&work, zlen));
150
+      status = snappy_uncompress((const char *)BPTR(buf), (size_t)BLEN(buf), (char *)BPTR(&work), &zlen);
151
+      if (status != SNAPPY_OK)
152
+	{
153
+	  dmsg (D_COMP_ERRORS, "Snappy decompression error: %d", status);
154
+	  buf->len = 0;
155
+	  return;
156
+	}
157
+
158
+      ASSERT (buf_safe (&work, zlen));
159
+      work.len = zlen;
160
+
161
+      dmsg (D_COMP, "Snappy decompress %d -> %d", buf->len, work.len);
162
+      compctx->pre_decompress += buf->len;
163
+      compctx->post_decompress += work.len;
164
+
165
+      *buf = work;
166
+    }
167
+  else if (c == NO_COMPRESS_BYTE_SWAP)	/* packet was not compressed */
168
+    {
169
+      ;
170
+    }
171
+  else
172
+    {
173
+      dmsg (D_COMP_ERRORS, "Bad Snappy decompression header byte: %d", c);
174
+      buf->len = 0;
175
+    }
176
+}
177
+
178
+const struct compress_alg snappy_alg = {
179
+  "snappy",
180
+  snap_compress_init,
181
+  snap_compress_uninit,
182
+  snap_compress,
183
+  snap_decompress
184
+};
185
+
186
+#else
187
+static void dummy(void) {}
188
+#endif /* ENABLE_SNAPPY */
0 189
new file mode 100644
... ...
@@ -0,0 +1,39 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single UDP 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) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
8
+ *
9
+ *  This program is free software; you can redistribute it and/or modify
10
+ *  it under the terms of the GNU General Public License version 2
11
+ *  as published by the Free Software Foundation.
12
+ *
13
+ *  This program is distributed in the hope that it will be useful,
14
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ *  GNU General Public License for more details.
17
+ *
18
+ *  You should have received a copy of the GNU General Public License
19
+ *  along with this program (see the file COPYING included with this
20
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
21
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+#ifndef OPENVPN_SNAPPY_H
25
+#define OPENVPN_SNAPPY_H
26
+
27
+#if defined(ENABLE_SNAPPY)
28
+
29
+#include "buffer.h"
30
+
31
+extern const struct compress_alg snappy_alg;
32
+
33
+struct snappy_workspace
34
+{
35
+};
36
+
37
+#endif /* ENABLE_SNAPPY */
38
+#endif
... ...
@@ -1811,9 +1811,9 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
1811 1811
 	  buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc));
1812 1812
       }
1813 1813
 
1814
-      /* push LZO status */
1815
-#ifdef ENABLE_LZO_STUB
1816
-      buf_printf (&out, "IV_LZO_STUB=1\n");
1814
+      /* push compression status */
1815
+#ifdef USE_COMP
1816
+      comp_generate_peer_info_string(&session->opt->comp_options, &out);
1817 1817
 #endif
1818 1818
 
1819 1819
       /* push env vars that begin with UV_ */
... ...
@@ -285,6 +285,11 @@ struct tls_options
285 285
   struct env_set *es;
286 286
   const struct plugin_list *plugins;
287 287
 
288
+  /* compression parms */
289
+#ifdef USE_COMP
290
+  struct compress_options comp_options;
291
+#endif
292
+
288 293
   /* configuration file boolean options */
289 294
 # define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0)
290 295
 # define SSLF_USERNAME_AS_COMMON_NAME  (1<<1)
... ...
@@ -713,6 +713,13 @@ socket_defined (const socket_descriptor_t sd)
713 713
 #define ENABLE_CLIENT_NAT
714 714
 
715 715
 /*
716
+ * Compression support
717
+ */
718
+#if defined(ENABLE_SNAPPY) || defined(ENABLE_LZO) || defined(ENABLE_COMP_STUB)
719
+#define USE_COMP
720
+#endif
721
+
722
+/*
716 723
  * Enable --memstats option
717 724
  */
718 725
 #ifdef TARGET_LINUX