int ssl3_read_n(SSL *s, int n, int max, int extend)
	{
	/* If extend == 0, obtain new n-byte packet; if extend == 1, increase
	 * packet by another n bytes.
	 * The packet will be in the sub-array of s->s3->rbuf.buf specified
	 * by s->packet and s->packet_length.
	 * (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;

	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;
		s->packet_length = 0;
		/* ... now we can act as if 'extend' was set */
		}

	/* For DTLS/UDP reads should not span multiple packets
	 * because the read operation returns the whole packet
	 * at once (as long as it fits into the buffer). */
	if (SSL_version(s) == DTLS1_VERSION)
		{
		if ( s->s3->rbuf.left > 0 && n > s->s3->rbuf.left)
			n = s->s3->rbuf.left;
		}

	/* if there is enough in the buffer from a previous read, take some */
	if (s->s3->rbuf.left >= (int)n)
		{
		s->packet_length+=n;
		s->s3->rbuf.left-=n;
		s->s3->rbuf.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;
	}
	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;
		}

	while (newb < 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) */

		clear_sys_error();
		if (s->rbio != NULL)
			{
			s->rwstate=SSL_READING;
			i=BIO_read(s->rbio,	&(s->s3->rbuf.buf[off+newb]), max-newb);
			}
		else
			{
			SSLerr(SSL_F_SSL3_READ_N,SSL_R_READ_BIO_NOT_SET);
			i = -1;
			}

		if (i <= 0)
			{
			s->s3->rbuf.left = newb;
			return(i);
			}
		newb+=i;
		/* reads should *never* span multiple packets for DTLS because
		 * the underlying transport protocol is message oriented as opposed
		 * to byte oriented as in the TLS case. */
		if (SSL_version(s) == DTLS1_VERSION)
			{
			if (n > newb)
				n = newb; /* makes the while condition false */
			}
		}

	/* done reading, now the book-keeping */
	s->s3->rbuf.offset = off + n;
	s->s3->rbuf.left = newb - n;
	s->packet_length += n;
	s->rwstate=SSL_NOTHING;
	return(n);
	}
int ssl3_read_n(SSL *s, int n, int max, int extend)
	{
	 
	int i,off,newb;

	if (!extend)
		{
		 
		if (s->s3->rbuf.left == 0)
			s->s3->rbuf.offset = 0;
		s->packet = s->s3->rbuf.buf + s->s3->rbuf.offset;
		s->packet_length = 0;
		 
		}

	 
	if (SSL_version(s) == DTLS1_VERSION)
		{
		if ( s->s3->rbuf.left > 0 && n > s->s3->rbuf.left)
			n = s->s3->rbuf.left;
		}

	 
	if (s->s3->rbuf.left >= (int)n)
		{
		s->packet_length+=n;
		s->s3->rbuf.left-=n;
		s->s3->rbuf.offset+=n;
		return(n);
		}

	 
	if (!s->read_ahead)
		max=n;

	{
		 
		int max_max = s->s3->rbuf.len - s->packet_length;
		if (max > max_max)
			max = max_max;
	}
	if (n > max)  
		{
		SSLerr(SSL_F_SSL3_READ_N,ERR_R_INTERNAL_ERROR);
		return -1;
		}

	off = s->packet_length;
	newb = s->s3->rbuf.left;
	 
	if (s->packet != s->s3->rbuf.buf)
		{
		 
		memmove(s->s3->rbuf.buf, s->packet, off+newb);
		s->packet = s->s3->rbuf.buf;
		}

	while (newb < n)
		{
		 

		clear_sys_error();
		if (s->rbio != NULL)
			{
			s->rwstate=SSL_READING;
			i=BIO_read(s->rbio,	&(s->s3->rbuf.buf[off+newb]), max-newb);
			}
		else
			{
			SSLerr(SSL_F_SSL3_READ_N,SSL_R_READ_BIO_NOT_SET);
			i = -1;
			}

		if (i <= 0)
			{
			s->s3->rbuf.left = newb;
			return(i);
			}
		newb+=i;
		 
		if (SSL_version(s) == DTLS1_VERSION)
			{
			if (n > newb)
				n = newb;  
			}
		}

	 
	s->s3->rbuf.offset = off + n;
	s->s3->rbuf.left = newb - n;
	s->packet_length += n;
	s->rwstate=SSL_NOTHING;
	return(n);
	}