From a4d64c7f49d76d659b6ad482c4f788fc7274f651 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Fri, 20 Oct 2006 11:26:00 +0000 Subject: [PATCH] Align data payload for better performance. --- ssl/s3_both.c | 12 ++-- ssl/s3_pkt.c | 148 ++++++++++++++++++++++++++++++++++---------------- ssl/ssl3.h | 22 ++++++-- 3 files changed, 126 insertions(+), 56 deletions(-) diff --git a/ssl/s3_both.c b/ssl/s3_both.c index 09d72e545d..aaf1c2f625 100644 --- a/ssl/s3_both.c +++ b/ssl/s3_both.c @@ -589,13 +589,17 @@ int ssl_verify_alarm_type(long type) int ssl3_setup_buffers(SSL *s) { unsigned char *p; - size_t len; + size_t len,align=0; + +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + align = (-SSL3_RT_HEADER_LENGTH)&(SSL3_ALIGN_PAYLOAD-1); +#endif if (s->s3->rbuf.buf == NULL) { len = SSL3_RT_MAX_PLAIN_LENGTH + SSL3_RT_MAX_ENCRYPTED_OVERHEAD - + SSL3_RT_HEADER_LENGTH; + + SSL3_RT_HEADER_LENGTH + align; if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) { s->s3->init_extra = 1; @@ -615,13 +619,13 @@ int ssl3_setup_buffers(SSL *s) { len = s->max_send_fragment + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD - + SSL3_RT_HEADER_LENGTH; + + SSL3_RT_HEADER_LENGTH + align; #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 + len += SSL3_RT_HEADER_LENGTH + align + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; if ((p=OPENSSL_malloc(len)) == NULL) goto err; diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index fc913c2d9e..1d34cec324 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -129,14 +129,44 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) * (If s->read_ahead is set, 'max' bytes may be stored in rbuf * [plus s->packet_length bytes if extend == 1].) */ - int i,off,newb; + int i,len,left,align=0; + unsigned char *pkt; + SSL3_BUFFER *rb; + + if (n <= 0) return n; + + rb = &(s->s3->rbuf); + left = rb->left; +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + align = (int)rb->buf + SSL3_RT_HEADER_LENGTH; + align = (-align)&(SSL3_ALIGN_PAYLOAD-1); +#endif if (!extend) { /* start with empty packet ... */ - if (s->s3->rbuf.left == 0) - s->s3->rbuf.offset = 0; - s->packet = s->s3->rbuf.buf + s->s3->rbuf.offset; + if (left == 0) + rb->offset = align; + else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH) + { + /* check if next packet length is large + * enough to justify payload alignment... */ + pkt = rb->buf + rb->offset; + if (pkt[0] == SSL3_RT_APPLICATION_DATA + && (pkt[3]<<8|pkt[4]) >= 128) + { + /* Note that even if packet is corrupted + * and its length field is insane, we can + * only be led to wrong decision about + * whether memmove will occur or not. + * Header values has no effect on memmove + * arguments and therefore no buffer + * overrun can be triggered. */ + memmove (rb->buf+align,pkt,left); + rb->offset = align; + } + } + s->packet = rb->buf + rb->offset; s->packet_length = 0; /* ... now we can act as if 'extend' was set */ } @@ -145,57 +175,54 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) if ( SSL_version(s) == DTLS1_VERSION && extend) { - if ( s->s3->rbuf.left > 0 && n > s->s3->rbuf.left) - n = s->s3->rbuf.left; + if ( left > 0 && n > left) + n = left; } /* if there is enough in the buffer from a previous read, take some */ - if (s->s3->rbuf.left >= (int)n) + if (left >= n) { s->packet_length+=n; - s->s3->rbuf.left-=n; - s->s3->rbuf.offset+=n; + rb->left=left-n; + rb->offset+=n; return(n); } /* else we need to read more data */ - if (!s->read_ahead) - max=n; - { - /* avoid buffer overflow */ - int max_max = s->s3->rbuf.len - s->packet_length; - if (max > max_max) - max = max_max; - } + len = s->packet_length; + pkt = rb->buf+align; + /* Move any available bytes to front of buffer: + * 'len' bytes already pointed to by 'packet', + * 'left' extra ones at the end */ + if (s->packet != pkt) /* len > 0 */ + { + memmove(pkt, s->packet, len+left); + s->packet = pkt; + rb->offset = len + align; + } + + max = rb->len - rb->offset; if (n > max) /* does not happen */ { SSLerr(SSL_F_SSL3_READ_N,ERR_R_INTERNAL_ERROR); return -1; } - off = s->packet_length; - newb = s->s3->rbuf.left; - /* Move any available bytes to front of buffer: - * 'off' bytes already pointed to by 'packet', - * 'newb' extra ones at the end */ - if (s->packet != s->s3->rbuf.buf) - { - /* off > 0 */ - memmove(s->s3->rbuf.buf, s->packet, off+newb); - s->packet = s->s3->rbuf.buf; - } + if (!s->read_ahead) + max=n; - while (newb < n) + while (left < n) { - /* Now we have off+newb bytes at the front of s->s3->rbuf.buf and need - * to read in more until we have off+n (up to off+max if possible) */ + /* Now we have len+left bytes at the front of s->s3->rbuf.buf + * and need to read in more until we have len+n (up to + * len+max if possible) */ clear_sys_error(); if (s->rbio != NULL) { s->rwstate=SSL_READING; - i=BIO_read(s->rbio, &(s->s3->rbuf.buf[off+newb]), max-newb); + i=BIO_read(s->rbio,pkt+len+left, max-left); } else { @@ -205,15 +232,15 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) if (i <= 0) { - s->s3->rbuf.left = newb; + rb->left = left; return(i); } - newb+=i; + left+=i; } /* done reading, now the book-keeping */ - s->s3->rbuf.offset = off + n; - s->s3->rbuf.left = newb - n; + rb->offset += n; + rb->left = left - n; s->packet_length += n; s->rwstate=SSL_NOTHING; return(n); @@ -579,14 +606,14 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, { unsigned char *p,*plen; int i,mac_size,clear=0; - int prefix_len = 0; + int prefix_len=0,align=0; SSL3_RECORD *wr; - SSL3_BUFFER *wb; + SSL3_BUFFER *wb=&(s->s3->wbuf); SSL_SESSION *sess; /* first check if there is a SSL3_BUFFER still being written * out. This will happen with non blocking IO */ - if (s->s3->wbuf.left != 0) + if (wb->left != 0) return(ssl3_write_pending(s,type,buf,len)); /* If we have an alert to send, lets send it */ @@ -602,7 +629,6 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, return 0; wr= &(s->s3->wrec); - wb= &(s->s3->wbuf); sess=s->session; if ( (sess == NULL) || @@ -643,7 +669,32 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, s->s3->empty_fragment_done = 1; } - p = wb->buf + prefix_len; + if (create_empty_fragment) + { +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + /* extra fragment would be couple of cipher blocks, + * which would be multiple of SSL3_ALIGN_PAYLOAD, so + * if we want to align the real payload, then we can + * just pretent we simply have two headers. */ + align = (int)wb->buf + 2*SSL3_RT_HEADER_LENGTH; + align = (-align)&(SSL3_ALIGN_PAYLOAD-1); +#endif + p = wb->buf + align; + wb->offset = align; + } + else if (prefix_len) + { + p = wb->buf + wb->offset + prefix_len; + } + else + { +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + align = (int)wb->buf + SSL3_RT_HEADER_LENGTH; + align = (-align)&(SSL3_ALIGN_PAYLOAD-1); +#endif + p = wb->buf + align; + wb->offset = align; + } /* write the header */ @@ -714,7 +765,6 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, /* now let's set up wb */ wb->left = prefix_len + wr->length; - wb->offset = 0; /* memorize arguments so that ssl3_write_pending can detect bad write retries later */ s->s3->wpend_tot=len; @@ -733,6 +783,7 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, unsigned int len) { int i; + SSL3_BUFFER *wb=&(s->s3->wbuf); /* XXXX */ if ((s->s3->wpend_tot > (int)len) @@ -751,24 +802,25 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, { s->rwstate=SSL_WRITING; i=BIO_write(s->wbio, - (char *)&(s->s3->wbuf.buf[s->s3->wbuf.offset]), - (unsigned int)s->s3->wbuf.left); + (char *)&(wb->buf[wb->offset]), + (unsigned int)wb->left); } else { SSLerr(SSL_F_SSL3_WRITE_PENDING,SSL_R_BIO_NOT_SET); i= -1; } - if (i == s->s3->wbuf.left) + if (i == wb->left) { - s->s3->wbuf.left=0; + wb->left=0; + wb->offset+=i; s->rwstate=SSL_NOTHING; return(s->s3->wpend_ret); } else if (i <= 0) return(i); - s->s3->wbuf.offset+=i; - s->s3->wbuf.left-=i; + wb->offset+=i; + wb->left-=i; } } diff --git a/ssl/ssl3.h b/ssl/ssl3.h index 2129759623..5ddadb2cd1 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -248,12 +248,27 @@ extern "C" { #define SSL3_SESSION_ID_SIZE 32 #define SSL3_RT_HEADER_LENGTH 5 +#ifndef SSL3_ALIGN_PAYLOAD + /* Some will argue that this increases memory footprint, but it's + * not actually true. Point is that malloc has to return at least + * 64-bit aligned pointers, meaning that allocating 5 bytes wastes + * 3 bytes in either case. Suggested pre-gaping simply moves these + * wasted bytes from the end of allocated region to its front, + * but makes data payload aligned, which improves performance:-) */ +# define SSL3_ALIGN_PAYLOAD 8 +#else +# if (SSL3_ALIGN_PAYLOAD&(SSL3_ALIGN_PAYLOAD-1))!=0 +# error "insane SSL3_ALIGN_PAYLOAD" +# undef SSL3_ALIGN_PAYLOAD +# endif +#endif + /* 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. + * Currently maximum of 20 is used by SHA1, but we reserve for + * future extension for 512-bit hashes. */ -#define SSL3_RT_MAX_MD_SIZE 20 +#define SSL3_RT_MAX_MD_SIZE 64 /* Maximum block size used in all ciphersuites. Currently 16 for AES. */ @@ -292,7 +307,6 @@ extern "C" { (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" #define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52" -- 2.25.1