⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bsd-comp.c

📁 经典的ppp程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Because this code is derived from the 4.3BSD compress source: * * * Copyright (c) 1985, 1986 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * James A. Woods, derived from original work by Spencer Thomas * and Joseph Orost. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * This version is for use with STREAMS under SunOS 4.x, * Digital UNIX, AIX 4.x, and SVR4 systems including Solaris 2. * * $Id: bsd-comp.c,v 1.20 1996/08/28 06:31:57 paulus Exp $ */#ifdef AIX4#include <net/net_globals.h>#endif#include <sys/param.h>#include <sys/types.h>#include <sys/stream.h>#include <net/ppp_defs.h>#include "ppp_mod.h"#ifdef SVR4#include <sys/byteorder.h>#ifndef _BIG_ENDIAN#define BSD_LITTLE_ENDIAN#endif#endif#ifdef __osf__#undef FIRST#undef LAST#define BSD_LITTLE_ENDIAN#endif#define PACKETPTR	mblk_t *#include <net/ppp-comp.h>#if DO_BSD_COMPRESS/* * PPP "BSD compress" compression *  The differences between this compression and the classic BSD LZW *  source are obvious from the requirement that the classic code worked *  with files while this handles arbitrarily long streams that *  are broken into packets.  They are: * *	When the code size expands, a block of junk is not emitted by *	    the compressor and not expected by the decompressor. * *	New codes are not necessarily assigned every time an old *	    code is output by the compressor.  This is because a packet *	    end forces a code to be emitted, but does not imply that a *	    new sequence has been seen. * *	The compression ratio is checked at the first end of a packet *	    after the appropriate gap.	Besides simplifying and speeding *	    things up, this makes it more likely that the transmitter *	    and receiver will agree when the dictionary is cleared when *	    compression is not going well. *//* * A dictionary for doing BSD compress. */struct bsd_db {    int	    totlen;			/* length of this structure */    u_int   hsize;			/* size of the hash table */    u_char  hshift;			/* used in hash function */    u_char  n_bits;			/* current bits/code */    u_char  maxbits;    u_char  debug;    u_char  unit;    u_short seqno;			/* sequence number of next packet */    u_int   hdrlen;			/* header length to preallocate */    u_int   mru;    u_int   maxmaxcode;			/* largest valid code */    u_int   max_ent;			/* largest code in use */    u_int   in_count;			/* uncompressed bytes, aged */    u_int   bytes_out;			/* compressed bytes, aged */    u_int   ratio;			/* recent compression ratio */    u_int   checkpoint;			/* when to next check the ratio */    u_int   clear_count;		/* times dictionary cleared */    u_int   incomp_count;		/* incompressible packets */    u_int   incomp_bytes;		/* incompressible bytes */    u_int   uncomp_count;		/* uncompressed packets */    u_int   uncomp_bytes;		/* uncompressed bytes */    u_int   comp_count;			/* compressed packets */    u_int   comp_bytes;			/* compressed bytes */    u_short *lens;			/* array of lengths of codes */    struct bsd_dict {	union {				/* hash value */	    u_int32_t	fcode;	    struct {#ifdef BSD_LITTLE_ENDIAN		u_short prefix;		/* preceding code */		u_char	suffix;		/* last character of new code */		u_char	pad;#else		u_char	pad;		u_char	suffix;		/* last character of new code */		u_short prefix;		/* preceding code */#endif	    } hs;	} f;	u_short codem1;			/* output of hash table -1 */	u_short cptr;			/* map code to hash table entry */    } dict[1];};#define BSD_OVHD	2		/* BSD compress overhead/packet */#define BSD_INIT_BITS	BSD_MIN_BITSstatic void	*bsd_comp_alloc __P((u_char *options, int opt_len));static void	*bsd_decomp_alloc __P((u_char *options, int opt_len));static void	bsd_free __P((void *state));static int	bsd_comp_init __P((void *state, u_char *options, int opt_len,				   int unit, int hdrlen, int debug));static int	bsd_decomp_init __P((void *state, u_char *options, int opt_len,				     int unit, int hdrlen, int mru, int debug));static int	bsd_compress __P((void *state, mblk_t **mret,				  mblk_t *mp, int slen, int maxolen));static void	bsd_incomp __P((void *state, mblk_t *dmsg));static int	bsd_decompress __P((void *state, mblk_t *cmp, mblk_t **dmpp));static void	bsd_reset __P((void *state));static void	bsd_comp_stats __P((void *state, struct compstat *stats));/* * Procedures exported to ppp_comp.c. */struct compressor ppp_bsd_compress = {    CI_BSD_COMPRESS,		/* compress_proto */    bsd_comp_alloc,		/* comp_alloc */    bsd_free,			/* comp_free */    bsd_comp_init,		/* comp_init */    bsd_reset,			/* comp_reset */    bsd_compress,		/* compress */    bsd_comp_stats,		/* comp_stat */    bsd_decomp_alloc,		/* decomp_alloc */    bsd_free,			/* decomp_free */    bsd_decomp_init,		/* decomp_init */    bsd_reset,			/* decomp_reset */    bsd_decompress,		/* decompress */    bsd_incomp,			/* incomp */    bsd_comp_stats,		/* decomp_stat */};/* * the next two codes should not be changed lightly, as they must not * lie within the contiguous general code space. */#define CLEAR	256			/* table clear output code */#define FIRST	257			/* first free entry */#define LAST	255#define MAXCODE(b)	((1 << (b)) - 1)#define BADCODEM1	MAXCODE(BSD_MAX_BITS)#define BSD_HASH(prefix,suffix,hshift)	((((u_int32_t)(suffix)) << (hshift)) \					 ^ (u_int32_t)(prefix))#define BSD_KEY(prefix,suffix)		((((u_int32_t)(suffix)) << 16) \					 + (u_int32_t)(prefix))#define CHECK_GAP	10000		/* Ratio check interval */#define RATIO_SCALE_LOG	8#define RATIO_SCALE	(1<<RATIO_SCALE_LOG)#define RATIO_MAX	(0x7fffffff>>RATIO_SCALE_LOG)#define DECOMP_CHUNK	256/* * clear the dictionary */static voidbsd_clear(db)    struct bsd_db *db;{    db->clear_count++;    db->max_ent = FIRST-1;    db->n_bits = BSD_INIT_BITS;    db->ratio = 0;    db->bytes_out = 0;    db->in_count = 0;    db->checkpoint = CHECK_GAP;}/* * If the dictionary is full, then see if it is time to reset it. * * Compute the compression ratio using fixed-point arithmetic * with 8 fractional bits. * * Since we have an infinite stream instead of a single file, * watch only the local compression ratio. * * Since both peers must reset the dictionary at the same time even in * the absence of CLEAR codes (while packets are incompressible), they * must compute the same ratio. */static int				/* 1=output CLEAR */bsd_check(db)    struct bsd_db *db;{    u_int new_ratio;    if (db->in_count >= db->checkpoint) {	/* age the ratio by limiting the size of the counts */	if (db->in_count >= RATIO_MAX	    || db->bytes_out >= RATIO_MAX) {	    db->in_count -= db->in_count/4;	    db->bytes_out -= db->bytes_out/4;	}	db->checkpoint = db->in_count + CHECK_GAP;	if (db->max_ent >= db->maxmaxcode) {	    /* Reset the dictionary only if the ratio is worse,	     * or if it looks as if it has been poisoned	     * by incompressible data.	     *	     * This does not overflow, because	     *	db->in_count <= RATIO_MAX.	     */	    new_ratio = db->in_count << RATIO_SCALE_LOG;	    if (db->bytes_out != 0)		new_ratio /= db->bytes_out;	    if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) {		bsd_clear(db);		return 1;	    }	    db->ratio = new_ratio;	}    }    return 0;}/* * Return statistics. */static voidbsd_comp_stats(state, stats)    void *state;    struct compstat *stats;{    struct bsd_db *db = (struct bsd_db *) state;    u_int out;    stats->unc_bytes = db->uncomp_bytes;    stats->unc_packets = db->uncomp_count;    stats->comp_bytes = db->comp_bytes;    stats->comp_packets = db->comp_count;    stats->inc_bytes = db->incomp_bytes;    stats->inc_packets = db->incomp_count;    stats->ratio = db->in_count;    out = db->bytes_out;    if (stats->ratio <= 0x7fffff)	stats->ratio <<= 8;    else	out >>= 8;    if (out != 0)	stats->ratio /= out;}/* * Reset state, as on a CCP ResetReq. */static voidbsd_reset(state)    void *state;{    struct bsd_db *db = (struct bsd_db *) state;    db->seqno = 0;    bsd_clear(db);    db->clear_count = 0;}/* * Allocate space for a (de) compressor. */static void *bsd_alloc(options, opt_len, decomp)    u_char *options;    int opt_len, decomp;{    int bits;    u_int newlen, hsize, hshift, maxmaxcode;    struct bsd_db *db;    if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3	|| BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)	return NULL;    bits = BSD_NBITS(options[2]);    switch (bits) {    case 9:			/* needs 82152 for both directions */    case 10:			/* needs 84144 */    case 11:			/* needs 88240 */    case 12:			/* needs 96432 */	hsize = 5003;	hshift = 4;	break;    case 13:			/* needs 176784 */	hsize = 9001;	hshift = 5;	break;    case 14:			/* needs 353744 */	hsize = 18013;	hshift = 6;	break;    case 15:			/* needs 691440 */	hsize = 35023;	hshift = 7;	break;    case 16:			/* needs 1366160--far too much, */	/* hsize = 69001; */	/* and 69001 is too big for cptr */	/* hshift = 8; */	/* in struct bsd_db */	/* break; */    default:	return NULL;    }    maxmaxcode = MAXCODE(bits);    newlen = sizeof(*db) + (hsize-1) * (sizeof(db->dict[0]));#ifdef __osf__    db = (struct bsd_db *) ALLOC_SLEEP(newlen);#else    db = (struct bsd_db *) ALLOC_NOSLEEP(newlen);#endif    if (!db)	return NULL;    bzero(db, sizeof(*db) - sizeof(db->dict));    if (!decomp) {	db->lens = NULL;    } else {#ifdef __osf__	db->lens = (u_short *) ALLOC_SLEEP((maxmaxcode+1) * sizeof(db->lens[0]));#else	db->lens = (u_short *) ALLOC_NOSLEEP((maxmaxcode+1) * sizeof(db->lens[0]));#endif	if (!db->lens) {	    FREE(db, newlen);	    return NULL;	}    }    db->totlen = newlen;    db->hsize = hsize;    db->hshift = hshift;    db->maxmaxcode = maxmaxcode;    db->maxbits = bits;    return (void *) db;}static voidbsd_free(state)    void *state;{    struct bsd_db *db = (struct bsd_db *) state;    if (db->lens)	FREE(db->lens, (db->maxmaxcode+1) * sizeof(db->lens[0]));    FREE(db, db->totlen);}static void *bsd_comp_alloc(options, opt_len)    u_char *options;    int opt_len;{    return bsd_alloc(options, opt_len, 0);}static void *bsd_decomp_alloc(options, opt_len)    u_char *options;    int opt_len;{    return bsd_alloc(options, opt_len, 1);}/* * Initialize the database. */static intbsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp)    struct bsd_db *db;    u_char *options;    int opt_len, unit, hdrlen, mru, debug, decomp;{    int i;    if (opt_len < CILEN_BSD_COMPRESS	|| options[0] != CI_BSD_COMPRESS || options[1] != CILEN_BSD_COMPRESS	|| BSD_VERSION(options[2]) != BSD_CURRENT_VERSION	|| BSD_NBITS(options[2]) != db->maxbits	|| decomp && db->lens == NULL)	return 0;    if (decomp) {	i = LAST+1;	while (i != 0)	    db->lens[--i] = 1;    }    i = db->hsize;    while (i != 0) {	db->dict[--i].codem1 = BADCODEM1;	db->dict[i].cptr = 0;    }    db->unit = unit;    db->hdrlen = hdrlen;    db->mru = mru;    if (debug)	db->debug = 1;    bsd_reset(db);    return 1;}static intbsd_comp_init(state, options, opt_len, unit, hdrlen, debug)    void *state;    u_char *options;    int opt_len, unit, hdrlen, debug;{    return bsd_init((struct bsd_db *) state, options, opt_len,		    unit, hdrlen, 0, debug, 0);}static intbsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug)    void *state;    u_char *options;    int opt_len, unit, hdrlen, mru, debug;{    return bsd_init((struct bsd_db *) state, options, opt_len,		    unit, hdrlen, mru, debug, 1);}/* * compress a packet *	One change from the BSD compress command is that when the *	code size expands, we do not output a bunch of padding. * * N.B. at present, we ignore the hdrlen specified in the comp_init call. */static int			/* new slen */bsd_compress(state, mretp, mp, slen, maxolen)    void *state;    mblk_t **mretp;		/* return compressed mbuf chain here */    mblk_t *mp;			/* from here */    int slen;			/* uncompressed length */    int maxolen;		/* max compressed length */{    struct bsd_db *db = (struct bsd_db *) state;    int hshift = db->hshift;    u_int max_ent = db->max_ent;    u_int n_bits = db->n_bits;    u_int bitno = 32;    u_int32_t accm = 0, fcode;    struct bsd_dict *dictp;    u_char c;    int hval, disp, ent, ilen;    mblk_t *np, *mret;    u_char *rptr, *wptr;    u_char *cp_end;    int olen;    mblk_t *m, **mnp;#define PUTBYTE(v) {					\    if (wptr) {						\	*wptr++ = (v);					\	if (wptr >= cp_end) {				\	    m->b_wptr = wptr;				\	    m = m->b_cont;				\	    if (m) {					\		wptr = m->b_wptr;			\		cp_end = m->b_datap->db_lim;		\	    } else					\		wptr = NULL;				\	}						\    }							\    ++olen;						\}#define OUTPUT(ent) {					\    bitno -= n_bits;					\    accm |= ((ent) << bitno);				\    do {						\	PUTBYTE(accm >> 24);				\	accm <<= 8;					\	bitno += 8;					\    } while (bitno <= 24);				\}    /*     * First get the protocol and check that we're     * interested in this packet.     */    *mretp = NULL;    rptr = mp->b_rptr;    if (rptr + PPP_HDRLEN > mp->b_wptr) {	if (!pullupmsg(mp, PPP_HDRLEN))	    return 0;	rptr = mp->b_rptr;    }    ent = PPP_PROTOCOL(rptr);		/* get the protocol */    if (ent < 0x21 || ent > 0xf9)	return 0;    /* Don't generate compressed packets which are larger than       the uncompressed packet. */    if (maxolen > slen)	maxolen = slen;    /* Allocate enough message blocks to give maxolen total space. */    mnp = &mret;    for (olen = maxolen; olen > 0; ) {	m = allocb((olen < 4096? olen: 4096), BPRI_MED);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -