New option SSL_OP_NO_COMP to disable compression. New ctrls to set
maximum send fragment size. Allocate I/O buffers accordingly.
diff --git a/CHANGES b/CHANGES
index f220bbe..cc2d55f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,12 @@
 
  Changes between 0.9.8a and 0.9.9  [xx XXX xxxx]
 
+  *) New option SSL_OP_NO_COMP to disable use of compression selectively
+     in SSL structures. New SSL ctrl to set maximum send fragment size. 
+     Save memory by seeting the I/O buffer sizes dynamically instead of
+     using the maximum available value.
+     [Steve Henson]
+
   *) New option -V for 'openssl ciphers'. This prints the ciphersuite code
      in addition to the text details.
      [Bodo Moeller]
diff --git a/apps/s_client.c b/apps/s_client.c
index 96ae832..efd8b06 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -450,6 +450,8 @@
 			off|=SSL_OP_NO_SSLv3;
 		else if (strcmp(*argv,"-no_ssl2") == 0)
 			off|=SSL_OP_NO_SSLv2;
+		else if	(strcmp(*argv,"-no_comp") == 0)
+			{ off|=SSL_OP_NO_COMPRESSION; }
 		else if (strcmp(*argv,"-serverpref") == 0)
 			off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
 		else if	(strcmp(*argv,"-cipher") == 0)
diff --git a/apps/s_server.c b/apps/s_server.c
index 8c6fcc2..27c0e43 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -754,6 +754,8 @@
 			{ off|=SSL_OP_NO_SSLv3; }
 		else if	(strcmp(*argv,"-no_tls1") == 0)
 			{ off|=SSL_OP_NO_TLSv1; }
+		else if	(strcmp(*argv,"-no_comp") == 0)
+			{ off|=SSL_OP_NO_COMPRESSION; }
 #ifndef OPENSSL_NO_SSL2
 		else if	(strcmp(*argv,"-ssl2") == 0)
 			{ meth=SSLv2_server_method(); }
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
index 045a953..3cbc642 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -349,7 +349,8 @@
 			p+=i;
 
 			/* COMPRESSION */
-			if (s->ctx->comp_methods == NULL)
+			if ((s->options & SSL_OP_NO_COMPRESSION)
+						|| !s->ctx->comp_methods)
 				j=0;
 			else
 				j=sk_SSL_COMP_num(s->ctx->comp_methods);
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 2ecfbb7..09d72e5 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -589,16 +589,22 @@
 int ssl3_setup_buffers(SSL *s)
 	{
 	unsigned char *p;
-	unsigned int extra;
 	size_t len;
 
 	if (s->s3->rbuf.buf == NULL)
 		{
+		len = SSL3_RT_MAX_PLAIN_LENGTH
+			+ SSL3_RT_MAX_ENCRYPTED_OVERHEAD
+			+ SSL3_RT_HEADER_LENGTH;
 		if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
-			extra=SSL3_RT_MAX_EXTRA;
-		else
-			extra=0;
-		len = SSL3_RT_MAX_PACKET_SIZE + extra;
+			{
+			s->s3->init_extra = 1;
+			len += SSL3_RT_MAX_EXTRA;
+			}
+#ifndef OPENSSL_NO_COMP
+		if (!(s->options & SSL_OP_NO_COMPRESSION))
+			len += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+#endif
 		if ((p=OPENSSL_malloc(len)) == NULL)
 			goto err;
 		s->s3->rbuf.buf = p;
@@ -607,8 +613,16 @@
 
 	if (s->s3->wbuf.buf == NULL)
 		{
-		len = SSL3_RT_MAX_PACKET_SIZE;
-		len += SSL3_RT_HEADER_LENGTH + 256; /* extra space for empty fragment */
+		len = s->max_send_fragment
+			+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD
+			+ SSL3_RT_HEADER_LENGTH;
+#ifndef OPENSSL_NO_COMP
+		if (!(s->options & SSL_OP_NO_COMPRESSION))
+			len += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+#endif
+		if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS))
+			len += SSL3_RT_HEADER_LENGTH
+				+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
 		if ((p=OPENSSL_malloc(len)) == NULL)
 			goto err;
 		s->s3->wbuf.buf = p;
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index cc9df91..7284c0a 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -588,7 +588,9 @@
 #ifdef OPENSSL_NO_COMP
 		*(p++)=1;
 #else
-		if (s->ctx->comp_methods == NULL)
+
+		if ((s->options & SSL_OP_NO_COMPRESSION)
+					|| !s->ctx->comp_methods)
 			j=0;
 		else
 			j=sk_SSL_COMP_num(s->ctx->comp_methods);
@@ -768,7 +770,7 @@
 		}
 #else
 	j= *(p++);
-	if (j == 0)
+	if ((j == 0) || (s->options & SSL_OP_NO_COMPRESSION))
 		comp=NULL;
 	else
 		comp=ssl3_comp_find(s->ctx->comp_methods,j);
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index d0f54e2..fc913c2 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -250,9 +250,9 @@
 		extra=SSL3_RT_MAX_EXTRA;
 	else
 		extra=0;
-	if (extra != s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE)
+	if (extra && !s->s3->init_extra)
 		{
-		/* actually likely an application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
+		/* An application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
 		 * set after ssl3_setup_buffers() was done */
 		SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR);
 		return -1;
@@ -275,6 +275,9 @@
 		ssl_minor= *(p++);
 		version=(ssl_major<<8)|ssl_minor;
 		n2s(p,rr->length);
+#if 0
+fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length);
+#endif
 
 		/* Lets check version */
 		if (s->first_packet)
@@ -300,7 +303,7 @@
 			goto err;
 			}
 
-		if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH+extra)
+		if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH)
 			{
 			al=SSL_AD_RECORD_OVERFLOW;
 			SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PACKET_LENGTH_TOO_LONG);
@@ -466,6 +469,10 @@
 	/* just read a 0 length packet */
 	if (rr->length == 0) goto again;
 
+#if 0
+fprintf(stderr, "Ultimate Record type=%d, Length=%d\n", rr->type, rr->length);
+#endif
+
 	return(1);
 
 f_err:
@@ -539,8 +546,8 @@
 	n=(len-tot);
 	for (;;)
 		{
-		if (n > SSL3_RT_MAX_PLAIN_LENGTH)
-			nw=SSL3_RT_MAX_PLAIN_LENGTH;
+		if (n > s->max_send_fragment)
+			nw=s->max_send_fragment;
 		else
 			nw=n;
 
@@ -624,7 +631,8 @@
 			if (prefix_len <= 0)
 				goto err;
 
-			if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
+			if (prefix_len >
+		(SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD))
 				{
 				/* insufficient space */
 				SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 775bac3..96a2602 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -900,7 +900,7 @@
 	 * algorithms from the client, starting at q. */
 	s->s3->tmp.new_compression=NULL;
 #ifndef OPENSSL_NO_COMP
-	if (s->ctx->comp_methods != NULL)
+	if (!(s->options & SSL_OP_NO_COMPRESSION) && s->ctx->comp_methods)
 		{ /* See if we have a match */
 		int m,nn,o,v,done=0;
 
diff --git a/ssl/ssl.h b/ssl/ssl.h
index f06b069..120c7a3 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -503,6 +503,8 @@
 
 /* As server, disallow session resumption on renegotiation */
 #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION	0x00010000L
+/* Don't use compression even if supported */
+#define SSL_OP_NO_COMPRESSION				0x00020000L
 /* If set, always create a new key when using tmp_ecdh parameters */
 #define SSL_OP_SINGLE_ECDH_USE				0x00080000L
 /* If set, always create a new key when using tmp_dh parameters */
@@ -747,6 +749,12 @@
 #endif
 
 	int quiet_shutdown;
+
+	/* Maximum amount of data to send in one fragment.
+	 * actual record size can be more than this due to
+	 * padding and MAC overheads.
+	 */
+	int max_send_fragment;
 	};
 
 #define SSL_SESS_CACHE_OFF			0x0000
@@ -968,6 +976,7 @@
 	int first_packet;
 	int client_version;	/* what was passed, used for
 				 * SSLv3/TLS rollback check */
+	int max_send_fragment;
 	};
 
 #ifdef __cplusplus
@@ -1171,6 +1180,8 @@
 #define SSL_CTRL_GET_MAX_CERT_LIST		50
 #define SSL_CTRL_SET_MAX_CERT_LIST		51
 
+#define SSL_CTRL_SET_MAX_SEND_FRAGMENT		52
+
 #define SSL_session_reused(ssl) \
 	SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL)
 #define SSL_num_renegotiations(ssl) \
@@ -1492,6 +1503,11 @@
 #define SSL_set_max_cert_list(ssl,m) \
 	SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
 
+#define SSL_CTX_set_max_send_fragment(ctx,m) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
+#define SSL_set_max_send_fragment(ssl,m) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
+
      /* NB: the keylength is only applicable when is_export is true */
 #ifndef OPENSSL_NO_RSA
 void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,
diff --git a/ssl/ssl3.h b/ssl/ssl3.h
index f0fbf82..2c6c79b 100644
--- a/ssl/ssl3.h
+++ b/ssl/ssl3.h
@@ -244,6 +244,18 @@
 #define SSL3_SESSION_ID_SIZE			32
 #define SSL3_RT_HEADER_LENGTH			5
 
+/* This is the maximum MAC (digest) size used by the SSL library.
+ * Currently this is 20 when SHA1 is used. This must be updated if larger
+ * digests are used in future.
+ */
+
+#define SSL3_RT_MAX_MD_SIZE			20
+
+/* Maximum block size used in all ciphersuites. Currently 16 for AES.
+ */
+
+#define	SSL_RT_MAX_CIPHER_BLOCK_SIZE		16
+
 /* Due to MS stuffing up, this can change.... */
 #if defined(OPENSSL_SYS_WIN16) || \
 	(defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32))
@@ -252,14 +264,36 @@
 #define SSL3_RT_MAX_EXTRA			(16384)
 #endif
 
+/* Maximum plaintext length: defined by SSL/TLS standards */
 #define SSL3_RT_MAX_PLAIN_LENGTH		16384
+/* Maximum compression overhead: defined by SSL/TLS standards */
+#define SSL3_RT_MAX_COMPRESSED_OVERHEAD		1024
+
+/* The standards give a maximum encryption overhead of 1024 bytes.
+ * In practice the value is lower than this. The overhead is the maximum
+ * number of padding bytes (256) plus the mac size.
+ */
+#define SSL3_RT_MAX_ENCRYPTED_OVERHEAD	(256 + SSL3_RT_MAX_MD_SIZE)
+
+/* OpenSSL currently only uses a padding length of at most one block so
+ * the send overhead is smaller.
+ */
+
+#define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \
+			(SSL_RT_MAX_CIPHER_BLOCK_SIZE + SSL3_RT_MAX_MD_SIZE)
+
+/* If compression isn't used don't include the compression overhead */
+
 #ifdef OPENSSL_NO_COMP
-#define SSL3_RT_MAX_COMPRESSED_LENGTH	SSL3_RT_MAX_PLAIN_LENGTH
+#define SSL3_RT_MAX_COMPRESSED_LENGTH		SSL3_RT_MAX_PLAIN_LENGTH
 #else
-#define SSL3_RT_MAX_COMPRESSED_LENGTH	(1024+SSL3_RT_MAX_PLAIN_LENGTH)
+#define SSL3_RT_MAX_COMPRESSED_LENGTH	\
+		(SSL3_RT_MAX_PLAIN_LENGTH+SSL3_RT_MAX_COMPRESSED_OVERHEAD)
 #endif
-#define SSL3_RT_MAX_ENCRYPTED_LENGTH	(1024+SSL3_RT_MAX_COMPRESSED_LENGTH)
-#define SSL3_RT_MAX_PACKET_SIZE		(SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
+#define SSL3_RT_MAX_ENCRYPTED_LENGTH	\
+		(SSL3_RT_MAX_ENCRYPTED_OVERHEAD+SSL3_RT_MAX_COMPRESSED_LENGTH)
+#define SSL3_RT_MAX_PACKET_SIZE		\
+		(SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
 #define SSL3_RT_MAX_DATA_SIZE			(1024*1024)
 
 #define SSL3_MD_CLIENT_FINISHED_CONST	"\x43\x4C\x4E\x54"
@@ -347,6 +381,9 @@
 	int need_empty_fragments;
 	int empty_fragment_done;
 
+	/* The value of 'extra' when the buffers were initialized */
+	int init_extra;
+
 	SSL3_BUFFER rbuf;	/* read IO goes into here */
 	SSL3_BUFFER wbuf;	/* write IO goes into here */
 
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 6fb9364..f524f63 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -303,6 +303,7 @@
 	s->trust = ctx->trust;
 #endif
 	s->quiet_shutdown=ctx->quiet_shutdown;
+	s->max_send_fragment = ctx->max_send_fragment;
 
 	CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
 	s->ctx=ctx;
@@ -973,6 +974,11 @@
 			return larg;
 			}
 		return 0;
+	case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
+		if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
+			return 0;
+		s->max_send_fragment = larg;
+		return 1;
 	default:
 		return(s->method->ssl_ctrl(s,cmd,larg,parg));
 		}
@@ -1061,6 +1067,11 @@
 		return(ctx->options|=larg);
 	case SSL_CTRL_MODE:
 		return(ctx->mode|=larg);
+	case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
+		if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
+			return 0;
+		ctx->max_send_fragment = larg;
+		return 1;
 	default:
 		return(ctx->method->ssl_ctx_ctrl(ctx,cmd,larg,parg));
 		}
@@ -1453,6 +1464,8 @@
 	ret->extra_certs=NULL;
 	ret->comp_methods=SSL_COMP_get_compression_methods();
 
+	ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
+
 	return(ret);
 err:
 	SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE);