From 329991d51a49ffe0fe4aff0a85a93c4573316660 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Thu, 15 Jan 2015 19:12:12 +0100 Subject: [PATCH] Added support for LZ4 Signed-off-by: Nikos Mavrogiannopoulos Signed-off-by: David Woodhouse --- Makefile.am | 4 +-- configure.ac | 19 +++++++++++++++ cstp.c | 55 +++++++++++++++++++++++++++++++++++++++--- main.c | 4 +++ openconnect-internal.h | 6 +++++ 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 93b32163..80a665a7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,8 +65,8 @@ library_srcs += $(lib_srcs_posix) endif libopenconnect_la_SOURCES = version.c $(library_srcs) -libopenconnect_la_CFLAGS = $(AM_CFLAGS) $(SSL_CFLAGS) $(DTLS_SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS) $(ZLIB_CFLAGS) $(P11KIT_CFLAGS) $(TSS_CFLAGS) $(LIBSTOKEN_CFLAGS) $(LIBOATH_CFLAGS) $(LIBPSKC_CFLAGS) $(GSSAPI_CFLAGS) $(INTL_CFLAGS) $(ICONV_CFLAGS) $(LIBPCSCLITE_CFLAGS) $(LIBP11_CFLAGS) -libopenconnect_la_LIBADD = $(SSL_LIBS) $(DTLS_SSL_LIBS) $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(ZLIB_LIBS) $(P11KIT_LIBS) $(TSS_LIBS) $(LIBSTOKEN_LIBS) $(LIBOATH_LIBS) $(LIBPSKC_LIBS) $(GSSAPI_LIBS) $(INTL_LIBS) $(ICONV_LIBS) $(LIBPCSCLITE_LIBS) $(LIBP11_LIBS) +libopenconnect_la_CFLAGS = $(AM_CFLAGS) $(SSL_CFLAGS) $(DTLS_SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS) $(ZLIB_CFLAGS) $(P11KIT_CFLAGS) $(TSS_CFLAGS) $(LIBSTOKEN_CFLAGS) $(LIBOATH_CFLAGS) $(LIBPSKC_CFLAGS) $(GSSAPI_CFLAGS) $(INTL_CFLAGS) $(ICONV_CFLAGS) $(LIBPCSCLITE_CFLAGS) $(LIBP11_CFLAGS) $(LIBLZ4_CFLAGS) +libopenconnect_la_LIBADD = $(SSL_LIBS) $(DTLS_SSL_LIBS) $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(ZLIB_LIBS) $(P11KIT_LIBS) $(TSS_LIBS) $(LIBSTOKEN_LIBS) $(LIBOATH_LIBS) $(LIBPSKC_LIBS) $(GSSAPI_LIBS) $(INTL_LIBS) $(ICONV_LIBS) $(LIBPCSCLITE_LIBS) $(LIBP11_LIBS) $(LIBLZ4_LIBS) if OPENBSD_LIBTOOL # OpenBSD's libtool doesn't have -version-number, but its -version-info arg # does what GNU libtool's -version-number does. Which arguably is what the diff --git a/configure.ac b/configure.ac index 835745da..cb595bc2 100644 --- a/configure.ac +++ b/configure.ac @@ -514,6 +514,25 @@ Add --without-openssl-version-check to configure args to avoid this check, or perhaps consider building with GnuTLS instead.])]) fi +AC_ARG_WITH(lz4, + AS_HELP_STRING([--without-lz4], [disable support for LZ4 compression]), + test_for_lz4=$withval, + test_for_lz4=yes) + +enable_lz4=no +if test "$test_for_lz4" = yes;then +PKG_CHECK_MODULES([LIBLZ4], [liblz4], [ +enable_lz4=yes +AC_DEFINE([HAVE_LZ4], [], [LZ4 was found]) +], +[ + AC_MSG_WARN([[ +*** +*** lz4 not found. +*** ]]) +]) +fi + # For some bizarre reason now that we use AM_ICONV, the mingw32 build doesn't # manage to set EGREP properly in the created ./libtool script. Make sure it's # found. diff --git a/cstp.c b/cstp.c index 2cc40655..b3fb41f7 100644 --- a/cstp.c +++ b/cstp.c @@ -28,6 +28,9 @@ #include #include #include +#ifdef HAVE_LZ4 +#include +#endif #include "openconnect-internal.h" @@ -155,6 +158,10 @@ static void append_compr_types(struct oc_text_buf *buf, const char *proto, int a if (avail) { char sep = ' '; buf_append(buf, "X-%s-Accept-Encoding:", proto); + if (avail & COMPR_LZ4) { + buf_append(buf, "%coc-lz4", sep); + sep = ','; + } if (avail & COMPR_LZS) { buf_append(buf, "%clzs", sep); sep = ','; @@ -365,6 +372,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo) } else if (!strcmp(buf + 7, "Content-Encoding")) { if (!strcmp(colon, "lzs")) vpninfo->dtls_compr = COMPR_LZS; + else if (!strcmp(colon, "oc-lz4")) + vpninfo->dtls_compr = COMPR_LZ4; else { vpn_progress(vpninfo, PRG_ERR, _("Unknown DTLS-Content-Encoding %s\n"), @@ -399,6 +408,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo) vpninfo->cstp_compr = COMPR_DEFLATE; else if (!strcmp(colon, "lzs")) vpninfo->cstp_compr = COMPR_LZS; + else if (!strcmp(colon, "oc-lz4")) + vpninfo->cstp_compr = COMPR_LZ4; else { vpn_progress(vpninfo, PRG_ERR, _("Unknown CSTP-Content-Encoding %s\n"), @@ -583,7 +594,7 @@ int openconnect_make_cstp_connection(struct openconnect_info *vpninfo) goto out; /* This will definitely be smaller than zlib's */ - if (vpninfo->cstp_compr == COMPR_LZS) + if (vpninfo->cstp_compr == COMPR_LZS || vpninfo->cstp_compr == COMPR_LZ4) deflate_bufsize = vpninfo->ip_info.mtu; /* If deflate compression is enabled (which is CSTP-only), it needs its @@ -685,7 +696,7 @@ int decompress_and_queue_packet(struct openconnect_info *vpninfo, unsigned char *buf, int len) { struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->ip_info.mtu); - const char *comprtype; + const char *comprtype = ""; if (!new) return -ENOMEM; @@ -722,16 +733,36 @@ int decompress_and_queue_packet(struct openconnect_info *vpninfo, if (vpninfo->inflate_adler32 != pkt_sum) vpninfo->quit_reason = "Compression (inflate) adler32 failure"; - } else { + } else if (vpninfo->cstp_compr == COMPR_LZS) { comprtype = "LZS"; new->len = lzs_decompress(new->data, vpninfo->ip_info.mtu, buf, len); if (new->len < 0) { + len = new->len; + if (len == 0) + len = -EINVAL; vpn_progress(vpninfo, PRG_ERR, _("LZS decompression failed: %s\n"), - strerror(-new->len)); + strerror(-len)); free(new); return len; } +#ifdef HAVE_LZ4 + } else if (vpninfo->cstp_compr == COMPR_LZ4) { + comprtype = "LZ4"; + new->len = LZ4_decompress_safe((void *)buf, (void *)new->data, len, vpninfo->ip_info.mtu); + if (new->len <= 0) { + len = new->len; + if (len == 0) + len = -EINVAL; + vpn_progress(vpninfo, PRG_ERR, _("LZ4 decompression failed\n")); + free(new); + return len; + } +#endif + } else { + vpn_progress(vpninfo, PRG_ERR, + _("Unknown compression type %d\n"), (int)vpninfo->cstp_compr); + return -EINVAL; } vpn_progress(vpninfo, PRG_TRACE, _("Received %s compressed data packet of %d bytes (was %d)\n"), @@ -785,6 +816,22 @@ int compress_packet(struct openconnect_info *vpninfo, int compr_type, struct pkt vpninfo->deflate_pkt->len = ret; return 0; +#ifdef HAVE_LZ4 + } else if (vpninfo->cstp_compr == COMPR_LZ4) { + if (this->len < 40) + return -EFBIG; + + ret = LZ4_compress_limitedOutput((void*)this->data, (void*)vpninfo->deflate_pkt->data, this->len, + this->len); + if (ret <= 0) { + if (ret == 0) + ret = -EFBIG; + return ret; + } + + vpninfo->deflate_pkt->len = ret; + return 0; +#endif } else return -EINVAL; diff --git a/main.c b/main.c index 9e26daaf..f05a228d 100644 --- a/main.c +++ b/main.c @@ -1430,11 +1430,15 @@ int main(int argc, char **argv) compr = " + deflate"; else if (vpninfo->cstp_compr == COMPR_LZS) compr = " + lzs"; + else if (vpninfo->cstp_compr == COMPR_LZ4) + compr = " + lz4"; } else { if (vpninfo->dtls_compr == COMPR_DEFLATE) compr = " + deflate"; else if (vpninfo->dtls_compr == COMPR_LZS) compr = " + lzs"; + else if (vpninfo->dtls_compr == COMPR_LZ4) + compr = " + lz4"; } vpn_progress(vpninfo, PRG_INFO, _("Connected %s as %s%s%s, using %s%s\n"), openconnect_get_ifname(vpninfo), diff --git a/openconnect-internal.h b/openconnect-internal.h index 95b5d6e4..fbbce8af 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -142,7 +142,13 @@ struct pkt { #define COMPR_DEFLATE (1<<0) #define COMPR_LZS (1<<1) +#define COMPR_LZ4 (1<<2) + +#ifdef HAVE_LZ4 +#define COMPR_ALL (COMPR_DEFLATE | COMPR_LZS | COMPR_LZ4) +#else #define COMPR_ALL (COMPR_DEFLATE | COMPR_LZS) +#endif struct keepalive_info { int dpd;