diff options
author | Max Khon <fjoe@FreeBSD.org> | 2002-01-07 20:26:38 +0000 |
---|---|---|
committer | Max Khon <fjoe@FreeBSD.org> | 2002-01-07 20:26:38 +0000 |
commit | efce757995697686c97291c8519d36ff87badd02 (patch) | |
tree | 614e212ba22dd1ae25f9fa5d0ed382443fc7d8da /net/tinyfugue | |
parent | 92ac3393ed0f2cf44ca8d45c031c085c0327a241 (diff) | |
download | ports-efce757995697686c97291c8519d36ff87badd02.tar.gz ports-efce757995697686c97291c8519d36ff87badd02.zip |
Notes
Diffstat (limited to 'net/tinyfugue')
-rw-r--r-- | net/tinyfugue/Makefile | 19 | ||||
-rw-r--r-- | net/tinyfugue/files/mccp-patch | 218 | ||||
-rw-r--r-- | net/tinyfugue/files/mccp.c | 426 | ||||
-rw-r--r-- | net/tinyfugue/files/mccp.h | 141 |
4 files changed, 802 insertions, 2 deletions
diff --git a/net/tinyfugue/Makefile b/net/tinyfugue/Makefile index 5585af693765..b827178eb9c6 100644 --- a/net/tinyfugue/Makefile +++ b/net/tinyfugue/Makefile @@ -13,7 +13,7 @@ MASTER_SITES= ftp://tf.tcp.com/pub/tinyfugue/ \ ftp://ftp.ci.uminho.pt/pub/mirrors/tinyfugue/ DISTNAME= tf-40s1 -MAINTAINER= ports@FreeBSD.org +MAINTAINER= fjoe@FreeBSD.org .if defined(PARALLEL_PACKAGE_BUILD) BROKEN= tries to cd to directory that do not exist yet @@ -26,4 +26,19 @@ MAKE_ENV= TFVER=${DISTNAME:S/^tf-//} MAN1= tf.1 -.include <bsd.port.mk> +.include <bsd.port.pre.mk> + +.if defined(WITH_MCCP) +EXTRA_PATCHES= ${FILESDIR}/mccp-patch +PKGNAMESUFFIX= -mccp + +post-extract: + @${CP} ${FILESDIR}/mccp.[ch] ${WRKSRC}/src +.else +pre-extract: + @${ECHO_MSG} + @${ECHO_MSG} "You can enable MCCP v1/v2 support by defining WITH_MCCP" + @${ECHO_MSG} +.endif + +.include <bsd.port.post.mk> diff --git a/net/tinyfugue/files/mccp-patch b/net/tinyfugue/files/mccp-patch new file mode 100644 index 000000000000..047a6d96cc8f --- /dev/null +++ b/net/tinyfugue/files/mccp-patch @@ -0,0 +1,218 @@ +--- src/rules.mak.orig Sun Mar 7 04:43:25 1999 ++++ src/rules.mak Fri Jun 23 05:46:38 2000 +@@ -50,6 +50,7 @@ main.$O: main.c config.h port.h dstring. + variable.h tty.h $(BUILDERS) + makehelp.$O: makehelp.c config.h port.h $(BUILDERS) + malloc.$O: malloc.c config.h port.h signals.h malloc.h $(BUILDERS) ++mccp.$O: mccp.c mccp.h + output.$O: output.c config.h port.h dstring.h $(TF_H) util.h tfio.h socket.h \ + output.h macro.h search.h tty.h variable.h expr.h $(BUILDERS) + process.$O: process.c config.h port.h dstring.h $(TF_H) util.h tfio.h \ +@@ -59,7 +60,7 @@ signals.$O: signals.c config.h port.h ds + process.h tty.h output.h signals.h variable.h $(BUILDERS) + socket.$O: socket.c config.h port.h dstring.h $(TF_H) util.h tfio.h tfselect.h \ + history.h world.h socket.h output.h process.h macro.h keyboard.h \ +- commands.h command.h signals.h search.h $(BUILDERS) ++ commands.h command.h signals.h search.h mccp.h $(BUILDERS) + tfio.$O: tfio.c config.h port.h dstring.h $(TF_H) util.h tfio.h tfselect.h \ + output.h macro.h history.h search.h signals.h variable.h $(BUILDERS) + tty.$O: tty.c config.h port.h $(TF_H) dstring.h util.h tty.h output.h macro.h \ +--- src/socket.c.orig Sun Mar 7 04:43:25 1999 ++++ src/socket.c Sat Jul 1 06:22:52 2000 +@@ -67,6 +67,10 @@ struct sockaddr_in { + #include "search.h" + #include "variable.h" /* set_var_by_*() */ + ++#ifdef MUDCOMPRESS ++# include "mccp.h" ++#endif ++ + #ifdef _POSIX_VERSION + # include <sys/wait.h> + #endif +@@ -206,6 +210,9 @@ typedef struct Sock { /* an open connec + TIME_T time[2]; /* time of last receive/send */ + char state; /* state of parser finite state automaton */ + long pid; /* pid of name resolution process */ ++#ifdef MUDCOMPRESS ++ mc_state *mccp; /* mud compression struct */ ++#endif + } Sock; + + +@@ -806,6 +813,9 @@ int opensock(world, autologin, quietlogi + tsock = *(tsock ? &tsock->next : &hsock) = xsock; + xsock->activity = 0; + Stringinit(xsock->buffer); ++#ifdef MUDCOMPRESS ++ xsock->mccp = mudcompress_new(); ++#endif + xsock->prompt = NULL; + init_queue(xsock->queue = (Queue *)XMALLOC(sizeof(Queue))); + xsock->next = NULL; +@@ -1297,6 +1307,9 @@ static void nukesock(sock) + #endif /* NONBLOCKING_GETHOST */ + } + Stringfree(sock->buffer); ++#ifdef MUDCOMPRESS ++ mudcompress_delete(sock->mccp); ++#endif + if (sock->prompt) free_aline(sock->prompt); + while(sock->queue->head) + free_aline((Aline*)unlist(sock->queue->head, sock->queue)); +@@ -1728,8 +1741,25 @@ static int handle_socket_input() + } + + do { /* while (n > 0 && !interrupted() && (received += count) < SPAM) */ +- do count = recv(xsock->fd, buffer, sizeof(buffer), 0); +- while (count < 0 && errno == EINTR); ++#ifdef MUDCOMPRESS ++ if (!mudcompress_pending(xsock->mccp)) ++ { ++ do count = recv(xsock->fd, buffer, sizeof(buffer), 0); ++ while (count < 0 && errno == EINTR); ++ ++ if (count > 0) { ++ mudcompress_receive(xsock->mccp, buffer, count); ++ if (mudcompress_error(xsock->mccp)) { ++ count = -1; ++ errno = EIO; ++ } ++ } ++ } ++#else ++ do count = recv(xsock->fd, buffer, sizeof(buffer), 0); ++ while (count < 0 && errno == EINTR); ++#endif ++ + if (count <= 0) { + int err = errno; + #ifdef SUNOS_5_4 +@@ -1761,6 +1791,25 @@ static int handle_socket_input() + return received; + } + ++ received += count; ++ ++#ifdef MUDCOMPRESS ++ { ++ const char *resp; ++ ++ count = 0; ++ while (count < sizeof(buffer) ++ && mudcompress_pending(xsock->mccp)) { ++ count += mudcompress_get(xsock->mccp, buffer + count, ++ sizeof(buffer) - count); ++ } ++ ++ resp = mudcompress_response(xsock->mccp); ++ if (resp) ++ transmit(resp,strlen(resp)); ++ } ++#endif ++ + for (place = buffer; place - buffer < count; place++) { + + /* We always accept 8-bit data, even though RFCs 854 and 1123 +@@ -1958,7 +2007,6 @@ static int handle_socket_input() + } + + /* See if anything arrived while we were parsing */ +- + FD_ZERO(&readfds); + FD_SET(xsock->fd, &readfds); + tv.tv_sec = tv.tv_usec = 0; +@@ -1976,7 +2024,13 @@ static int handle_socket_input() + if (errno != EINTR) die("handle_socket_input: select", errno); + } + +- } while (n > 0 && !interrupted() && (received += count) < SPAM); ++#ifdef MUDCOMPRESS ++ if (mudcompress_pending(xsock->mccp)) { ++ n = 1; ++ } ++#endif ++ ++ } while (n > 0 && !interrupted() && received < SPAM); + + /* If lpflag is on and we got a partial line from the fg world, + * assume the line is a prompt. +--- src/tf.1.catman.orig Sun Mar 7 04:43:25 1999 ++++ src/tf.1.catman Sat Jun 24 01:25:46 2000 +@@ -152,6 +152,8 @@ TF(1) + + Recall previously received text. + ++ Support for the Mud Client Compression Protocol version 1 and 2. ++ + + CCOONNFFIIGGUURRAATTIIOONN FFIILLEESS + _T_F will attempt to read two files when starting. The +--- src/tf.1.nroffman.orig Sun Mar 7 04:43:25 1999 ++++ src/tf.1.nroffman Sat Jun 24 01:25:04 2000 +@@ -112,6 +112,8 @@ Separate LP and Diku style prompts from + Page output using a --More-- prompt. + .sp + Recall previously received text. ++.sp ++Support for Mud Client Compression Protocol versions 1 and 2. + + .SH "CONFIGURATION FILES" + .PP +--- src/vars.mak.orig Sun Mar 7 04:43:25 1999 ++++ src/vars.mak Fri Jun 23 06:07:44 2000 +@@ -15,14 +15,14 @@ + # Predefined variables: + # O - object file suffix (e.g., "o" or "obj") + +-TFVER=40s1 ++TFVER=40s1-mccp + + SOURCE = command.c dstring.c expand.c help.c history.c keyboard.c \ + macro.c main.c malloc.c output.c process.c search.c signals.c \ + socket.c tfio.c tty.c util.c variable.c world.c + + OBJS = command.$O dstring.$O expand.$O expr.$O help.$O history.$O keyboard.$O \ +- macro.$O main.$O malloc.$O output.$O process.$O search.$O signals.$O \ ++ macro.$O main.$O malloc.$O mccp.$O output.$O process.$O search.$O signals.$O \ + socket.$O tfio.$O tty.$O util.$O variable.$O world.$O \ + regexp.$O $(OTHER_OBJS) + +--- unix/tfconfig.orig Sun Mar 7 04:43:28 1999 ++++ unix/tfconfig Wed Jul 5 05:56:02 2000 +@@ -482,6 +482,14 @@ else + echo "I can't find <pwd.h>. Filename '~user' expansion won't be supported." + fi + ++### Find zlib.h ++if echo '#include <zlib.h>' >test.c; ${CPP} test.c >/dev/null 2>&1; then ++ echo "#define MUDCOMPRESS" >&4 ++ echo "Found <zlib.h>." ++else ++ echo "I can't find <zlib.h>. The Mud Client Compression Protocol will not be supported." ++fi ++ + ### Figure out how to do varadic args. + if [ "$STD_C" = "1" ] || [ "$GNU_C" = "1" ]; then + if echo '#include <stdarg.h>' >test.c; ${CPP} test.c >/dev/null 2>&1; then +@@ -756,6 +764,12 @@ elif eval "${LIBTEST} -lsocket ${LIBS} > + else + echo "Warning: can't find connect() or a library that might have it." + echo "/* warning: tfconfig couldn't find connect() */" >&4 ++fi ++ ++### Test for zlib for mud compression ++if eval "${LIBTEST} -lz ${LIBS} >/dev/null 2>&1" && test -f ${AOUT}; then ++ echo "Will link with -lz." ++ LIBS="-lz $LIBS" + fi + + ### Test for SOCKS firewall proxy server. +--- unixmake.orig Sun Mar 7 04:43:24 1999 ++++ unixmake Sat Jul 1 06:27:28 2000 +@@ -20,4 +20,4 @@ export PATH + + MAKE=${MAKE-make} + export MAKE +-${MAKE} -f unix/Makefile `egrep '^TFVER=' src/vars.mak` MAKE="${MAKE}" $* ++${MAKE} -j 1 -f unix/Makefile `egrep '^TFVER=' src/vars.mak` MAKE="${MAKE}" $* diff --git a/net/tinyfugue/files/mccp.c b/net/tinyfugue/files/mccp.c new file mode 100644 index 000000000000..79dd82b4952a --- /dev/null +++ b/net/tinyfugue/files/mccp.c @@ -0,0 +1,426 @@ +/* + * Client decompression module for the mud client compression protocol. + * See http://homepages.ihug.co.nz/~icecube/compress/ for more details. + * + * mccpDecompress.c - module code. Link this with your client code. + * + * Oliver Jowett <icecube$ihug.co.nz>. Demangle address as needed. + * + * This code is placed in the public domain. + * + */ + +/* Modified: 20000530 */ + +/* See mccp.h for API information */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "config.h" +#ifdef MUDCOMPRESS + +#include <zlib.h> + +#include "mccp.h" + +/* Telnet values we're interested in */ + +#define IAC 255 +#define DONT 254 +#define DO 253 +#define WONT 252 +#define WILL 251 +#define SB 250 +#define SE 240 + +#define TELOPT_COMPRESS 85 +#define TELOPT_COMPRESS2 86 + +/* We say DO COMPRESS2 to WILL COMPRESS2, then DONT COMPRESS to WILL COMPRESS + * -or- + * We say DO COMPRESS to WILL COMPRESS if it arrives before any COMPRESS2. + * + * Later the server sends IAC SB COMPRESS IAC SE (v2) or IAC SB COMPRESS WILL + * SE (v1), and immediately following + * that, begins compressing + * + * Compression ends on a Z_STREAM_END, no other marker is used + */ + +static char will_v1[] = { IAC, WILL, TELOPT_COMPRESS, 0 }; +static char do_v1[] = { IAC, DO, TELOPT_COMPRESS, 0 }; +static char dont_v1[] = { IAC, DONT, TELOPT_COMPRESS, 0 }; +static char on_v1[] = { IAC, SB, TELOPT_COMPRESS, WILL, SE, 0 }; + +static char will_v2[] = { IAC, WILL, TELOPT_COMPRESS2, 0 }; +static char do_v2[] = { IAC, DO, TELOPT_COMPRESS2, 0 }; +static char on_v2[] = { IAC, SB, TELOPT_COMPRESS2, IAC, SE, 0 }; + +/* "Opaque" state object */ + +struct mc_state_s { + z_stream *stream; /* stream we're using */ + + unsigned char *inbuf; /* input buffer (data from mud) */ + unsigned int insize; /* .. and how much is used */ + unsigned int inalloc; /* .. and how much is allocated */ + + unsigned char *outbuf; /* output buffer (data to user) */ + unsigned int outsize; /* .. and how much is used */ + unsigned int outalloc; /* .. and how much is allocated */ + + int error; + int resp_v1; /* waiting to send IAC DO/DONT COMPRESS */ + int resp_v2; /* waiting to send IAC DO COMPRESS2 */ + int got_v2; /* responded to a IAC WILL COMPRESS2 already */ + + unsigned long comp; + unsigned long uncomp; +}; + +/* Initialise a new state object */ +mc_state *mudcompress_new(void) +{ + mc_state *state; + + state = malloc(sizeof(*state)); + state->stream = NULL; /* Not decompressing */ + state->inalloc = 2048; + state->outalloc = 2048; + state->inbuf = malloc(state->inalloc); + state->outbuf = malloc(state->outalloc); + state->insize = 0; + state->outsize = 0; + state->error = 0; + state->comp = 0; + state->uncomp = 0; + state->resp_v1 = 0; + state->resp_v2 = 0; + state->got_v2 = 0; + + return state; +} + +/* Clean up a state object */ +void mudcompress_delete(mc_state *state) +{ + if (state->stream) { + inflateEnd(state->stream); + free(state->stream); + } + + free(state->inbuf); + free(state->outbuf); + free(state); +} + +/* zlib helpers */ + +static void *zlib_alloc(void *opaque, unsigned int items, unsigned int size) +{ + return calloc(items, size); +} + +static void zlib_free(void *opaque, void *address) +{ + free(address); +} + +static void grow_inbuf(mc_state *state, int needed) +{ + int old = state->inalloc; + + while (state->inalloc < state->insize + needed) + state->inalloc *= 2; + + if (old != state->inalloc) + state->inbuf = realloc(state->inbuf, state->inalloc); +} + +static void grow_outbuf(mc_state *state, int needed) +{ + int old = state->outalloc; + + while (state->outalloc < state->outsize + needed) + state->outalloc *= 2; + + if (old != state->outalloc) + state->outbuf = realloc(state->outbuf, state->outalloc); +} + +static void decompress_inbuf(mc_state *state) +{ + int status; + + /* We are now decompressing from inbuf to outbuf */ + + if (!state->insize) + return; /* nothing to decompress? */ + + state->stream->next_in = state->inbuf; + state->stream->next_out = state->outbuf + state->outsize; + state->stream->avail_in = state->insize; + state->stream->avail_out = state->outalloc - state->outsize; + + status = inflate(state->stream, Z_PARTIAL_FLUSH); + + if (status == Z_OK || status == Z_STREAM_END) { + /* Successful decompression */ + + /* Remove used data from inbuf */ + state->comp += state->insize - state->stream->avail_in; + state->uncomp += state->stream->next_out - state->outbuf; + + memmove(state->inbuf, state->stream->next_in, state->stream->avail_in); + state->insize = state->stream->avail_in; + + /* Update outbuf pointers */ + state->outsize = state->stream->next_out - state->outbuf; + + /* Done */ + + if (status == Z_STREAM_END) { + /* Turn off compression too */ + + grow_outbuf(state, state->insize); + + memcpy(state->outbuf + state->outsize, state->inbuf, state->insize); + state->outsize += state->insize; + state->insize = 0; + + inflateEnd(state->stream); + free(state->stream); + state->stream = NULL; + } + + return; + } + + if (status == Z_BUF_ERROR) { + /* Full buffers? Maybe we need more output space.. */ + + if (state->outsize * 2 > state->outalloc) { + grow_outbuf(state, state->outalloc); + decompress_inbuf(state); + } + + return; + } + + /* Error */ + state->error = 1; +} + +/* We received some data */ +void mudcompress_receive(mc_state *state, const char *data, unsigned len) +{ + int i; + + if (state->error) + return; + + if (!state->stream) { + int residual = -1; + int clen; + + /* Just copy to outbuf. Also copy any residual inbuf */ + + grow_outbuf(state, len + state->insize); + memcpy(state->outbuf + state->outsize, data, len); + state->outsize += len; + memcpy(state->outbuf + state->outsize, state->inbuf, state->insize); + state->outsize += state->insize; + state->insize = 0; + + /* Check for Magic Marker. ugh this is messy */ + for (i=0; i < state->outsize; i++) { + if (state->outbuf[i] == IAC) { + if (i + 1 < state->outsize && state->outbuf[i+1] == IAC) { + /* IAC IAC - ignore */ + i++; + continue; + } + + clen = (i + strlen(will_v1) < state->outsize) ? strlen(will_v1) : state->outsize - i; + + if (!memcmp(&state->outbuf[i], will_v1, clen)) { + if (clen != strlen(will_v1)) { + /* Partial match. Save it. */ + residual = i; + break; + } + + /* If we got WILL COMPRESS2 then refuse COMPRESS, otherwise + * accept it + */ + + if (state->got_v2) + state->resp_v1 = -1; + else + state->resp_v1 = 1; + + memmove(&state->outbuf[i], + &state->outbuf[i + strlen(will_v1)], + state->outsize - strlen(will_v1)); + state->outsize -= strlen(will_v1); + i--; + continue; + } + + if (!memcmp(&state->outbuf[i], will_v2, clen)) { + if (clen != strlen(will_v2)) { + /* Partial match. Save it. */ + residual = i; + break; + } + + state->resp_v2 = 1; + state->got_v2 = 1; + + memmove(&state->outbuf[i], + &state->outbuf[i + strlen(will_v2)], + state->outsize - strlen(will_v2)); + state->outsize -= strlen(will_v2); + i--; + continue; + } + + clen = (i + strlen(on_v1) < state->outsize) ? strlen(on_v1) : state->outsize - i; + + if ((!memcmp(&state->outbuf[i], on_v1, clen) && !state->got_v2) || + (!memcmp(&state->outbuf[i], on_v2, clen) && state->got_v2)) { + if (clen != strlen(on_v1)) { + /* Partial match. Save it. */ + residual = i; + break; + } + + /* Switch to compression */ + /* copy any compressible bits to our inbuf */ + + grow_inbuf(state, state->outsize - i - strlen(on_v1)); + + memcpy(state->inbuf, + state->outbuf + i + strlen(on_v1), + state->outsize - i - strlen(on_v1)); + + state->insize = state->outsize - i - strlen(on_v1); + + /* clean up our output buffer */ + state->outsize = i; + + /* init stream */ + state->stream = malloc(sizeof(z_stream)); + state->stream->zalloc = zlib_alloc; + state->stream->zfree = zlib_free; + state->stream->opaque = NULL; + + if (inflateInit(state->stream) != Z_OK) { + state->error = 1; + free(state->stream); + state->stream = NULL; + return; + } + + /* Continue with decompression */ + break; + } + } + } + + if (!state->stream) { /* didn't start decompressing? */ + /* We might have some residual, copy to inbuf for later checking */ + + if (residual != -1) { + grow_inbuf(state, state->outsize - residual); + memcpy(state->inbuf + state->insize, state->outbuf + residual, state->outsize - residual); + state->outsize = residual; + } + + return; + } + } else { + /* New data to decompress. Copy to inbuf */ + grow_inbuf(state, len); + memcpy(state->inbuf + state->insize, data, len); + state->insize += len; + } + + decompress_inbuf(state); +} + +/* How much data is available? */ +int mudcompress_pending(mc_state *state) +{ + return state->error ? 0 : state->outsize; +} + +/* Was there an error? */ +int mudcompress_error(mc_state *state) +{ + return state->error; +} + +/* Get some data */ +int mudcompress_get(mc_state *state, char *buf, int size) +{ + int copied; + + if (state->error || !state->outsize) + return 0; + + if (size > state->outsize) + copied = state->outsize; + else + copied = size; + + memcpy(buf, state->outbuf, copied); + state->outsize -= copied; + if (state->outsize) + memmove(state->outbuf, state->outbuf + copied, state->outsize); + + /* Do some more decompression */ + decompress_inbuf(state); + + return copied; +} + +void mudcompress_stats(mc_state *state, unsigned long *comp, unsigned long *uncomp) +{ + *comp = state->comp; + *uncomp = state->uncomp; +} + +const char *mudcompress_response(mc_state *state) +{ + if (state->resp_v1 == 1) { + state->resp_v1 = 0; + return do_v1; + } + + if (state->resp_v1 == -1) { + state->resp_v1 = 0; + return dont_v1; + } + + if (state->resp_v2) { + state->resp_v2 = 0; + return do_v2; + } + + return NULL; +} + +int mudcompress_compressing(mc_state *state) +{ + return (state->stream != NULL); +} + +int mudcompress_v2(mc_state *state) +{ + return (state->stream != NULL && state->got_v2); +} + +#endif /* MUDCOMPRESS */ diff --git a/net/tinyfugue/files/mccp.h b/net/tinyfugue/files/mccp.h new file mode 100644 index 000000000000..d0086db09750 --- /dev/null +++ b/net/tinyfugue/files/mccp.h @@ -0,0 +1,141 @@ +/* + * Client decompression module for the mud client compression protocol. + * See http://homepages.ihug.co.nz/~icecube/compress/ for more details. + * + * mccpDecompress.h - header definitions. #include this in your client code. + * + * Oliver Jowett <icecube$ihug.co.nz>. Demangle address as needed. + * + * This code is placed in the public domain. + * + */ + +/* Modified: 981203 */ + +/* + * + * mc_state is an opaque type representing the current compression state of + * a connection. You should include a (mc_state *) in the information you + * store for a server connection. + * + * Initialization / cleanup: + * + * When a connection is initiated, call mudcompress_new, and store the + * resulting pointer in your server connection information. This pointer is + * used as a handle for all other functions. This does NOT begin compression + * - it just initialises various internal structures. + * + * When a connection is terminated, call mudcompress_delete with the handle + * to delete all memory allocated by the decompressor for the connection. + * + * Reading / writing: + * + * Reading from the server connection must go through the decompressor at + * all times. The decompressor handles both negotiation and decompression + * transparently - it receives input directly from the server, then provides + * the main client code with decompressed data, hiding all protocol details. + * + * When data is received from the mud server, call mudcompress_receive, + * passing it the handle for the connection, a pointer to the data read, + * and the length of data read. It is VITAL that ALL data read is passed + * to the decompressor - including data with embedded NULs! + * + * After mudcompress_receive has been called, call mudcompress_pending() to + * see if any decompressed data is available. It returns the number of + * bytes pending. + * + * If there is pending data waiting, call mudcompress_get to retrieve it. + * This fills up to "size" bytes in the provided buffer "buf", and returns + * the number of bytes copied. Your client can now process this data as if + * it had been directly read from the server. + * + * Be sure to check mudcompress_pending again after calling mudcompress_get! + * Removing some data from the decompress buffer may have allowed the + * decompressor to decompress some more data - in which case, you want to + * process it immediately, rather than waiting for another read from the + * mud server. + * + * Regularly call mudcompress_response. If non-NULL, you need to write the + * returned string to the mud server. This is needed when the decompressor + * is negotiating compression with the server. When called, + * mudcompress_response clears any pending string, so be sure to save its + * return value! + * + * Status information: + * + * mudcompress_error returns non-0 if there has been a (fatal) decompression + * error. In this case, all you can do is tell the user that something went + * wrong and close the connection. + * + * mudcompress_stats fills in the two (unsigned long *) values passed, with + * the number of compressed bytes read, and the number of bytes that they + * decompressed to. + * + * mudcompress_compressing returns non-0 if the connection is currently + * using compression. + * + */ + +#ifndef MUDCOMPRESS_H +#define MUDCOMPRESS_H + +#ifdef __cplusplus +extern "C" { +#endif + + /* Opaque handle for a decompressor. Details defined in Compress.c - you + * should never need to see them externally. + */ + struct mc_state_s; + typedef struct mc_state_s mc_state; + + /* Create a new decompressor. Return a handle to it. + */ + mc_state *mudcompress_new(void); + + /* Deallocate a decompressor and associated data. 'state' is invalid + * afterthis call. + */ + void mudcompress_delete(mc_state *state); + + /* Perform decompression and negotiation on some received data. + * 'data' is a pointer to the received data, 'len' is its length. + */ + void mudcompress_receive(mc_state *state, const char *data, unsigned len); + + /* Return the number of pending decompressed bytes that can currently + * be read by mudcompress_get + */ + int mudcompress_pending(mc_state *state); + + /* Return true (non-0) if this decompressor encountered a fatal error. + */ + int mudcompress_error(mc_state *state); + + /* Read decompressed data from the decompressor into 'buf', up to a + * maximum of 'size' bytes. Returns the number of bytes actually copied. + */ + int mudcompress_get(mc_state *state, char *buf, int size); + + /* Set *comp to the number of compressed bytes read, and *uncomp to the + * number of bytes they expanded to, for this decompressor. + */ + void mudcompress_stats(mc_state *state, unsigned long *comp, unsigned long *uncomp); + + /* Check for a negotiation response. If this returns NULL, no output is + * needed. If it returns non-NULL, it points to a NUL-terminated string + * that should be sent to the mud server. Calling this function clears + * the pending string (so be sure to save the result). + */ + const char *mudcompress_response(mc_state *state); + + /* Return true (non-0) if this decompressor has successfully negotiated + * compression and is currently performing decompression. + */ + int mudcompress_compressing(mc_state *state); + +#ifdef __cplusplus +} +#endif + +#endif |