/***************************************************************************** * DikuMUD (C) 1990, 1991 by: * * Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen, * * and Katja Nyboe. * *---------------------------------------------------------------------------* * MERC 2.1 (C) 1992, 1993 by: * * Michael Chastain, Michael Quan, and Mitchell Tse. * *---------------------------------------------------------------------------* * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider. * * Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, * * gorog, Grishnakh, Nivek, Tricops, and Fireblade. * *---------------------------------------------------------------------------* * SMAUG 1.7 FUSS by: Samson and others of the SMAUG community. * * Their contributions are greatly appreciated. * *---------------------------------------------------------------------------* * LoP (C) 2006, 2007, 2008 by: the LoP team. * *---------------------------------------------------------------------------* * Client Compression Module * *****************************************************************************/ /* * mccp.c - support functions for mccp (the Mud Client Compression Protocol) * * see http://mccp.afkmud.com * * Copyright (c) 1999, Oliver Jowett <oliver@randomly.org>. * * This code may be freely distributed and used if this copyright notice is * retained intact. */ #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #ifndef WIN32 #include <arpa/telnet.h> #else #define TELOPT_ECHO '\x01' #define GA '\xF9' #define SB '\xFA' #define SE '\xF0' #define WILL '\xFB' #define WONT '\xFC' #define DO '\xFD' #define DONT '\xFE' #define IAC '\xFF' #define ENOSR 63 #endif #include "h/mud.h" #include "h/mccp.h" #if defined(__OpenBSD__) || defined(__FreeBSD__) #define ENOSR 63 #endif int mccpusers; char will_compress2_str[] = { IAC, WILL, TELOPT_COMPRESS2, '\0' }; char start_compress2_str[] = { IAC, SB, TELOPT_COMPRESS2, IAC, SE, '\0' }; bool write_to_descriptor( DESCRIPTOR_DATA *d, char *txt, int length ); bool process_compressed( DESCRIPTOR_DATA *d ) { int iStart = 0, nBlock, nWrite, len; if( !d->mccp->out_compress ) return true; /* Try to write out some data.. */ len = d->mccp->out_compress->next_out - d->mccp->out_compress_buf; if( len > 0 ) { /* we have some data to write */ for( iStart = 0; iStart < len; iStart += nWrite ) { nBlock = UMIN( len - iStart, 4096 ); if( ( nWrite = write( d->descriptor, d->mccp->out_compress_buf + iStart, nBlock ) ) < 0 ) { if( errno == EAGAIN || errno == ENOSR ) break; return false; } if( !nWrite ) break; } if( iStart ) { /* We wrote "iStart" bytes */ if( iStart < len ) memmove( d->mccp->out_compress_buf, d->mccp->out_compress_buf + iStart, len - iStart ); d->mccp->out_compress->next_out = d->mccp->out_compress_buf + len - iStart; } } return true; } bool compressStart( DESCRIPTOR_DATA *d ) { z_stream *s; if( d->mccp->out_compress ) return true; CREATE( s, z_stream, 1 ); CREATE( d->mccp->out_compress_buf, unsigned char, COMPRESS_BUF_SIZE ); s->next_in = NULL; s->avail_in = 0; s->next_out = d->mccp->out_compress_buf; s->avail_out = COMPRESS_BUF_SIZE; s->zalloc = Z_NULL; s->zfree = Z_NULL; s->opaque = NULL; if( deflateInit( s, 9 ) != Z_OK ) { DISPOSE( d->mccp->out_compress_buf ); DISPOSE( s ); return false; } write_to_descriptor( d, start_compress2_str, 0 ); d->can_compress = true; d->mccp->out_compress = s; mccpusers++; return true; } bool compressEnd( DESCRIPTOR_DATA *d ) { unsigned char dummy[1]; if( !d->mccp->out_compress ) return true; d->mccp->out_compress->avail_in = 0; d->mccp->out_compress->next_in = dummy; if( deflate( d->mccp->out_compress, Z_FINISH ) != Z_STREAM_END ) return false; if( !process_compressed( d ) ) /* try to send any residual data */ return false; deflateEnd( d->mccp->out_compress ); DISPOSE( d->mccp->out_compress_buf ); DISPOSE( d->mccp->out_compress ); mccpusers--; return true; } CMDF( do_compress ) { if( !ch->desc ) { send_to_char( "What descriptor?!\n", ch ); return; } if( !ch->desc->mccp->out_compress ) { if( !compressStart( ch->desc ) ) send_to_char( "&RCompression failed to start.\r\n", ch ); else send_to_char( "&GOk, compression enabled.\r\n", ch ); } else { compressEnd( ch->desc ); ch->desc->can_compress = false; send_to_char( "&ROk, compression disabled.\r\n", ch ); } }