if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg);
int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)	{	int al,i,j,ret;	unsigned int n;	SSL3_RECORD *rr;	void (*cb)()=NULL;	if (s->s3->rbuf.buf == NULL) /* Not initialized yet */		if (!ssl3_setup_buffers(s))			return(-1);	if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type) ||	    (peek && (type != SSL3_RT_APPLICATION_DATA)))		{		SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);		return -1;		}	if ((type == SSL3_RT_HANDSHAKE) && (s->s3->handshake_fragment_len > 0))		/* (partially) satisfy request from storage */		{		unsigned char *src = s->s3->handshake_fragment;		unsigned char *dst = buf;		unsigned int k;		/* peek == 0 */		n = 0;		while ((len > 0) && (s->s3->handshake_fragment_len > 0))			{			*dst++ = *src++;			len--; s->s3->handshake_fragment_len--;			n++;			}		/* move any remaining fragment bytes: */		for (k = 0; k < s->s3->handshake_fragment_len; k++)			s->s3->handshake_fragment[k] = *src++;		return n;	}	/* Now s->s3->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */	if (!s->in_handshake && SSL_in_init(s))		{		/* type == SSL3_RT_APPLICATION_DATA */		i=s->handshake_func(s);		if (i < 0) return(i);		if (i == 0)			{			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);			return(-1);			}		}start:	s->rwstate=SSL_NOTHING;	/* s->s3->rrec.type	    - is the type of record	 * s->s3->rrec.data,    - data	 * s->s3->rrec.off,     - offset into 'data' for next read	 * s->s3->rrec.length,  - number of bytes. */	rr = &(s->s3->rrec);	/* get new packet if necessary */	if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))		{		ret=ssl3_get_record(s);		if (ret <= 0) return(ret);		}	/* we now have a packet which can be read and processed */	if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,	                               * reset by ssl3_get_finished */		&& (rr->type != SSL3_RT_HANDSHAKE))		{		al=SSL_AD_UNEXPECTED_MESSAGE;		SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);		goto err;		}	/* If the other end has shut down, throw anything we read away	 * (even in 'peek' mode) */	if (s->shutdown & SSL_RECEIVED_SHUTDOWN)		{		rr->length=0;		s->rwstate=SSL_NOTHING;		return(0);		}	if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */		{		/* make sure that we are not getting application data when we		 * are doing a handshake for the first time */		if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&			(s->enc_read_ctx == NULL))			{			al=SSL_AD_UNEXPECTED_MESSAGE;			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_APP_DATA_IN_HANDSHAKE);			goto f_err;			}		if (len <= 0) return(len);		if ((unsigned int)len > rr->length)			n = rr->length;		else			n = (unsigned int)len;		memcpy(buf,&(rr->data[rr->off]),n);		if (!peek)			{			rr->length-=n;			rr->off+=n;			if (rr->length == 0)				{				s->rstate=SSL_ST_READ_HEADER;				rr->off=0;				}			}		return(n);		}	/* If we get here, then type != rr->type; if we have a handshake	 * message, then it was unexpected (Hello Request or Client Hello). */	/* In case of record types for which we have 'fragment' storage,	 * fill that so that we can process the data at a fixed place.	 */		{		unsigned int dest_maxlen = 0;		unsigned char *dest = NULL;		unsigned int *dest_len = NULL;		if (rr->type == SSL3_RT_HANDSHAKE)			{			dest_maxlen = sizeof s->s3->handshake_fragment;			dest = s->s3->handshake_fragment;			dest_len = &s->s3->handshake_fragment_len;			}		else if (rr->type == SSL3_RT_ALERT)			{			dest_maxlen = sizeof s->s3->alert_fragment;			dest = s->s3->alert_fragment;			dest_len = &s->s3->alert_fragment_len;			}		if (dest_maxlen > 0)			{			n = dest_maxlen - *dest_len; /* available space in 'dest' */			if (rr->length < n)				n = rr->length; /* available bytes */			/* now move 'n' bytes: */			while (n-- > 0)				{				dest[(*dest_len)++] = rr->data[rr->off++];				rr->length--;				}			if (*dest_len < dest_maxlen)				goto start; /* fragment was too small */			}		}	/* s->s3->handshake_fragment_len == 4  iff  rr->type == SSL3_RT_HANDSHAKE;	 * s->s3->alert_fragment_len == 2      iff  rr->type == SSL3_RT_ALERT.	 * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */	/* If we are a client, check for an incoming 'Hello Request': */	if ((!s->server) &&		(s->s3->handshake_fragment_len >= 4) &&		(s->s3->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&		(s->session != NULL) && (s->session->cipher != NULL))		{		s->s3->handshake_fragment_len = 0;		if ((s->s3->handshake_fragment[1] != 0) ||			(s->s3->handshake_fragment[2] != 0) ||			(s->s3->handshake_fragment[3] != 0))			{			al=SSL_AD_DECODE_ERROR;			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_HELLO_REQUEST);			goto err;			}		if (SSL_is_init_finished(s) &&			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&			!s->s3->renegotiate)			{			ssl3_renegotiate(s);			if (ssl3_renegotiate_check(s))				{				i=s->handshake_func(s);				if (i < 0) return(i);				if (i == 0)					{					SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);					return(-1);					}				if (!(s->mode & SSL_MODE_AUTO_RETRY))					{					if (s->s3->rbuf.left == 0) /* no read-ahead left? */						{						BIO *bio;						/* In the case where we try to read application data,						 * but we trigger an SSL handshake, we return -1 with						 * the retry option set.  Otherwise renegotiation may						 * cause nasty problems in the blocking world */						s->rwstate=SSL_READING;						bio=SSL_get_rbio(s);						BIO_clear_retry_flags(bio);						BIO_set_retry_read(bio);						return(-1);						}					}				}			}		/* we either finished a handshake or ignored the request,		 * now try again to obtain the (application) data we were asked for */		goto start;		}	if (s->s3->alert_fragment_len >= 2)		{		int alert_level = s->s3->alert_fragment[0];		int alert_descr = s->s3->alert_fragment[1];		s->s3->alert_fragment_len = 0;		if (s->info_callback != NULL)			cb=s->info_callback;		else if (s->ctx->info_callback != NULL)			cb=s->ctx->info_callback;		if (cb != NULL)			{			j = (alert_level << 8) | alert_descr;			cb(s, SSL_CB_READ_ALERT, j);			}		if (alert_level == 1) /* warning */			{			s->s3->warn_alert = alert_descr;			if (alert_descr == SSL_AD_CLOSE_NOTIFY)				{				s->shutdown |= SSL_RECEIVED_SHUTDOWN;				return(0);				}			}		else if (alert_level == 2) /* fatal */			{			char tmp[16];			s->rwstate=SSL_NOTHING;			s->s3->fatal_alert = alert_descr;			SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr);			BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);			ERR_add_error_data(2,"SSL alert number ",tmp);			s->shutdown|=SSL_RECEIVED_SHUTDOWN;			SSL_CTX_remove_session(s->ctx,s->session);			return(0);			}		else			{			al=SSL_AD_ILLEGAL_PARAMETER;			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNKNOWN_ALERT_TYPE);			goto f_err;			}		goto start;		}	if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */		{		s->rwstate=SSL_NOTHING;		rr->length=0;		return(0);		}	if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)		{		/* 'Change Cipher Spec' is just a single byte, so we know		 * exactly what the record payload has to look like */		if (	(rr->length != 1) || (rr->off != 0) ||			(rr->data[0] != SSL3_MT_CCS))			{			i=SSL_AD_ILLEGAL_PARAMETER;			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);			goto err;			}		rr->length=0;		s->s3->change_cipher_spec=1;		if (!do_change_cipher_spec(s))			goto err;		else			goto start;		}	/* Unexpected handshake message (Client Hello, or protocol violation) */	if ((s->s3->handshake_fragment_len >= 4) &&	!s->in_handshake)		{		if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))			{#if 0 /* worked only because C operator preferences are not as expected (and       * because this is not really needed for clients except for detecting       * protocol violations): */			s->state=SSL_ST_BEFORE|(s->server)				?SSL_ST_ACCEPT				:SSL_ST_CONNECT;#else			s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;#endif			s->new_session=1;			}		i=s->handshake_func(s);		if (i < 0) return(i);		if (i == 0)			{			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);			return(-1);			}		if (!(s->mode & SSL_MODE_AUTO_RETRY))			{			if (s->s3->rbuf.left == 0) /* no read-ahead left? */				{				BIO *bio;				/* In the case where we try to read application data,				 * but we trigger an SSL handshake, we return -1 with				 * the retry option set.  Otherwise renegotiation may				 * cause nasty problems in the blocking world */				s->rwstate=SSL_READING;				bio=SSL_get_rbio(s);				BIO_clear_retry_flags(bio);				BIO_set_retry_read(bio);				return(-1);				}			}		goto start;		}	switch (rr->type)		{	default:#ifndef OPENSSL_NO_TLS		/* TLS just ignores unknown message types */		if (s->version == TLS1_VERSION)			{			goto start;			}#endif		al=SSL_AD_UNEXPECTED_MESSAGE;		SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNEXPECTED_RECORD);		goto f_err;	case SSL3_RT_CHANGE_CIPHER_SPEC:	case SSL3_RT_ALERT:	case SSL3_RT_HANDSHAKE:		/* we already handled all of these, with the possible exception		 * of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that		 * should not happen when type != rr->type */		al=SSL_AD_UNEXPECTED_MESSAGE;		SSLerr(SSL_F_SSL3_READ_BYTES,ERR_R_INTERNAL_ERROR);		goto f_err;	case SSL3_RT_APPLICATION_DATA:		/* At this point, we were expecting handshake data,		 * but have application data.  If the library was		 * running inside ssl3_read() (i.e. in_read_app_data		 * is set) and it makes sense to read application data		 * at this point (session renegotiation not yet started),		 * we will indulge it.		 */		if (s->s3->in_read_app_data &&			(s->s3->total_renegotiations != 0) &&			((				(s->state & SSL_ST_CONNECT) &&				(s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&				(s->state <= SSL3_ST_CR_SRVR_HELLO_A)				) || (					(s->state & SSL_ST_ACCEPT) &&					(s->state <= SSL3_ST_SW_HELLO_REQ_A) &&					(s->state >= SSL3_ST_SR_CLNT_HELLO_A)					)				))			{			s->s3->in_read_app_data=0;			return(-1);			}		else			{			al=SSL_AD_UNEXPECTED_MESSAGE;			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNEXPECTED_RECORD);			goto f_err;			}		}	/* not reached */f_err:	ssl3_send_alert(s,SSL3_AL_FATAL,al);err:	return(-1);	}