aboutsummaryrefslogtreecommitdiff
path: root/ircd/s_zip.c
diff options
context:
space:
mode:
Diffstat (limited to 'ircd/s_zip.c')
-rw-r--r--ircd/s_zip.c261
1 files changed, 261 insertions, 0 deletions
diff --git a/ircd/s_zip.c b/ircd/s_zip.c
new file mode 100644
index 0000000..819c9a9
--- /dev/null
+++ b/ircd/s_zip.c
@@ -0,0 +1,261 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_zip.c
+ * Copyright (C) 1996 Christophe Kalt
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_zip.c,v 1.7 1998/12/24 16:29:17 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_ZIP_C
+#include "s_externs.h"
+#undef S_ZIP_C
+
+#ifdef ZIP_LINKS
+
+/*
+** Important note:
+** The provided buffers for compression *MUST* be big
+** enough for any operation to complete.
+**
+** s_bsd.c current settings are that the biggest packet size is 16k
+** (but socket buffers are set to 8k..)
+*/
+
+/*
+** size of the buffer holding compressed data
+**
+** outgoing data:
+** must be enough to hold compressed data resulting of the compression
+** of up to ZIP_MAXIMUM bytes
+** incoming data:
+** must be enough to hold what was just read
+** (cptr->zip->inbuf should never hold more than ONE compression block.
+** The biggest block allowed for compression is ZIP_MAXIMUM bytes)
+*/
+#define ZIP_BUFFER_SIZE (MAX(ZIP_MAXIMUM, READBUF_SIZE))
+
+/*
+** size of the buffer where zlib puts compressed data
+** should be enough to hold uncompressed data resulting of the
+** uncompression of zipbuffer
+**
+** tests show that an average ratio is around 40%,
+** in some very particular cases, ratio can be VERY low, BUT:
+**
+** s_bsd.c/read_packet() is now smart enough to detect when uncompression
+** stopped because the buffer is too small, and calls dopacket() again
+** to finish the work (as many times as needed).
+*/
+#define UNZIP_BUFFER_SIZE 4*ZIP_BUFFER_SIZE
+
+/* buffers */
+static char unzipbuf[UNZIP_BUFFER_SIZE];
+static char zipbuf[ZIP_BUFFER_SIZE];
+
+/*
+** zip_init
+** Initialize compression structures for a server.
+** If failed, zip_free() has to be called.
+*/
+int zip_init(cptr)
+aClient *cptr;
+{
+ cptr->zip = (aZdata *) MyMalloc(sizeof(aZdata));
+ cptr->zip->outcount = 0;
+
+ cptr->zip->in = (z_stream *) MyMalloc(sizeof(z_stream));
+ cptr->zip->in->avail_in = 0;
+ cptr->zip->in->total_in = 0;
+ cptr->zip->in->total_out = 0;
+ cptr->zip->in->zalloc = (alloc_func)0;
+ cptr->zip->in->zfree = (free_func)0;
+ cptr->zip->in->data_type = Z_ASCII;
+ if (inflateInit(cptr->zip->in) != Z_OK)
+ {
+ cptr->zip->out = NULL;
+ return -1;
+ }
+
+ cptr->zip->out = (z_stream *) MyMalloc(sizeof(z_stream));
+ cptr->zip->out->total_in = 0;
+ cptr->zip->out->total_out = 0;
+ cptr->zip->out->zalloc = (alloc_func)0;
+ cptr->zip->out->zfree = (free_func)0;
+ cptr->zip->out->data_type = Z_ASCII;
+ if (deflateInit(cptr->zip->out, ZIP_LEVEL) != Z_OK)
+ return -1;
+
+ return 0;
+}
+
+/*
+** zip_free
+*/
+void zip_free(cptr)
+aClient *cptr;
+{
+ cptr->flags &= ~FLAGS_ZIP;
+ if (cptr->zip)
+ {
+ if (cptr->zip->in)
+ inflateEnd(cptr->zip->in);
+ MyFree((char *)cptr->zip->in);
+ if (cptr->zip->out)
+ deflateEnd(cptr->zip->out);
+ MyFree((char *)cptr->zip->out);
+ MyFree((char *)cptr->zip);
+ cptr->zip = NULL;
+ }
+}
+
+/*
+** unzip_packet
+** Unzip the content of the buffer, don't worry about any leftover.
+**
+** will return the uncompressed buffer, length will be updated.
+** if a fatal error occurs, length will be set to -1
+*/
+char * unzip_packet(cptr, buffer, length)
+aClient *cptr;
+char *buffer;
+int *length;
+{
+ Reg z_stream *zin = cptr->zip->in;
+ int r;
+
+ if (*length != 0 && zin->avail_in != 0)
+ {
+ sendto_flag(SCH_ERROR,
+ "assertion failed in unzip_packet(): %d %d",
+ *length, zin->avail_in);
+ sendto_flag(SCH_ERROR, "Please report to ircd-bugs@irc.org");
+ *length = -1;
+ return NULL;
+ }
+ if (*length)
+ {
+ zin->next_in = buffer;
+ zin->avail_in = *length;
+ }
+ zin->next_out = unzipbuf;
+ zin->avail_out = UNZIP_BUFFER_SIZE;
+ switch (r = inflate(zin, Z_PARTIAL_FLUSH))
+ {
+ case Z_OK:
+ cptr->flags &= ~FLAGS_ZIPRQ;
+ *length = UNZIP_BUFFER_SIZE - zin->avail_out;
+ return unzipbuf;
+
+ case Z_BUF_ERROR: /*no progress possible or output buffer too small*/
+ if (zin->avail_out == 0)
+ {
+ sendto_flag(SCH_ERROR,
+ "inflate() returned Z_BUF_ERROR: %s",
+ (zin->msg) ? zin->msg : "?");
+ *length = -1;
+ }
+ break;
+
+ case Z_DATA_ERROR: /* the buffer might not be compressed.. */
+ if ((cptr->flags & FLAGS_ZIPRQ) &&
+ !strncmp("ERROR ", buffer, 6))
+ {
+ cptr->flags &= ~(FLAGS_ZIP | FLAGS_ZIPRQ);
+ /*
+ * This is not sane at all. But if other server
+ * has sent an error now, it is probably closing
+ * the link as well.
+ */
+ return buffer;
+ }
+
+ /* no break */
+
+ default: /* error ! */
+ /* should probably mark link as dead or something... */
+ sendto_flag(SCH_ERROR, "inflate() error(%d): %s", r,
+ (zin->msg) ? zin->msg : "?");
+ *length = -1; /* report error condition */
+ break;
+ }
+ return NULL;
+}
+
+/*
+** zip_buffer
+** Zip the content of cptr->zip->outbuf and of the buffer,
+** put anything left in cptr->zip->outbuf, update cptr->zip->outcount
+**
+** if flush is set, then all available data will be compressed,
+** otherwise, compression only occurs if there's enough to compress,
+** or if we are reaching the maximum allowed size during a connect burst.
+**
+** will return the uncompressed buffer, length will be updated.
+** if a fatal error occurs, length will be set to -1
+*/
+char * zip_buffer(cptr, buffer, length, flush)
+aClient *cptr;
+char *buffer;
+int *length, flush;
+{
+ Reg z_stream *zout = cptr->zip->out;
+ int r;
+
+ if (buffer)
+ {
+ /* concatenate buffer in cptr->zip->outbuf */
+ bcopy(buffer, cptr->zip->outbuf + cptr->zip->outcount,*length);
+ cptr->zip->outcount += *length;
+ }
+ *length = 0;
+
+ if (!flush && ((cptr->zip->outcount < ZIP_MINIMUM) ||
+ ((cptr->zip->outcount < (ZIP_MAXIMUM - BUFSIZE)) &&
+ CBurst(cptr))))
+ return NULL;
+
+ zout->next_in = cptr->zip->outbuf;
+ zout->avail_in = cptr->zip->outcount;
+ zout->next_out = zipbuf;
+ zout->avail_out = ZIP_BUFFER_SIZE;
+
+ switch (r = deflate(zout, Z_PARTIAL_FLUSH))
+ {
+ case Z_OK:
+ if (zout->avail_in)
+ {
+ /* can this occur?? I hope not... */
+ sendto_flag(SCH_ERROR,
+ "deflate() didn't process all available data!");
+ }
+ cptr->zip->outcount = 0;
+ *length = ZIP_BUFFER_SIZE - zout->avail_out;
+ return zipbuf;
+
+ default: /* error ! */
+ sendto_flag(SCH_ERROR, "deflate() error(%d): %s", r,
+ (zout->msg) ? zout->msg : "?");
+ *length = -1;
+ break;
+ }
+ return NULL;
+}
+
+#endif /* ZIP_LINKS */