- if ( s->init_off == 0 && type == SSL3_RT_HANDSHAKE)
- OPENSSL_assert(s->init_num ==
- (int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH);
-
- frag_off = 0;
- while( s->init_num)
- {
- curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) -
- DTLS1_RT_HEADER_LENGTH;
-
- if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH)
- {
- /* grr.. we could get an error if MTU picked was wrong */
- ret = BIO_flush(SSL_get_wbio(s));
- if ( ret <= 0)
- return ret;
- curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH;
- }
-
- if ( s->init_num > curr_mtu)
- len = curr_mtu;
- else
- len = s->init_num;
-
-
- /* XDTLS: this function is too long. split out the CCS part */
- if ( type == SSL3_RT_HANDSHAKE)
- {
- if ( s->init_off != 0)
- {
- OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH);
- s->init_off -= DTLS1_HM_HEADER_LENGTH;
- s->init_num += DTLS1_HM_HEADER_LENGTH;
-
- /* write atleast DTLS1_HM_HEADER_LENGTH bytes */
- if ( len <= DTLS1_HM_HEADER_LENGTH)
- len += DTLS1_HM_HEADER_LENGTH;
- }
-
- dtls1_fix_message_header(s, frag_off,
- len - DTLS1_HM_HEADER_LENGTH);
-
- dtls1_write_message_header(s, (unsigned char *)&s->init_buf->data[s->init_off]);
-
- OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH);
- }
-
- ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off],
- len);
- if (ret < 0)
- {
- /* might need to update MTU here, but we don't know
- * which previous packet caused the failure -- so can't
- * really retransmit anything. continue as if everything
- * is fine and wait for an alert to handle the
- * retransmit
- */
- if ( BIO_ctrl(SSL_get_wbio(s),
- BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL))
- s->d1->mtu = BIO_ctrl(SSL_get_wbio(s),
- BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
- else
- return(-1);
- }
- else
- {
-
- /* bad if this assert fails, only part of the handshake
- * message got sent. but why would this happen? */
- OPENSSL_assert(len == (unsigned int)ret);
-
- if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting)
- /* should not be done for 'Hello Request's, but in that case
- * we'll ignore the result anyway */
- ssl3_finish_mac(s,
- (unsigned char *)&s->init_buf->data[s->init_off +
- DTLS1_HM_HEADER_LENGTH], ret - DTLS1_HM_HEADER_LENGTH);
-
- if (ret == s->init_num)
- {
- if (s->msg_callback)
- s->msg_callback(1, s->version, type, s->init_buf->data,
- (size_t)(s->init_off + s->init_num), s,
- s->msg_callback_arg);
-
- s->init_off = 0; /* done writing this message */
- s->init_num = 0;
-
- return(1);
- }
- s->init_off+=ret;
- s->init_num-=ret;
- frag_off += (ret -= DTLS1_HM_HEADER_LENGTH);
- }
- }
- return(0);
- }
-
-
-/* Obtain handshake message of message type 'mt' (any if mt == -1),
- * maximum acceptable body length 'max'.
- * Read an entire handshake message. Handshake messages arrive in
- * fragments.
- */
-long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
- {
- int i, al;
-
- /* s3->tmp is used to store messages that are unexpected, caused
- * by the absence of an optional handshake message */
- if (s->s3->tmp.reuse_message)
- {
- s->s3->tmp.reuse_message=0;
- if ((mt >= 0) && (s->s3->tmp.message_type != mt))
- {
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_GET_MESSAGE,SSL_R_UNEXPECTED_MESSAGE);
- goto f_err;
- }
- *ok=1;
- s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
- s->init_num = (int)s->s3->tmp.message_size;
- return s->init_num;
- }
-
- do
- {
- if ( s->d1->r_msg_hdr.frag_off == 0)
- {
- /* s->d1->r_message_header.msg_len = 0; */
- memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st));
- }
-
- i = dtls1_get_message_fragment(s, st1, stn, max, ok);
- if ( i == DTLS1_HM_BAD_FRAGMENT ||
- i == DTLS1_HM_FRAGMENT_RETRY) /* bad fragment received */
- continue;
- else if ( i <= 0 && !*ok)
- return i;
-
- if (s->d1->r_msg_hdr.msg_len == (unsigned int)s->init_num - DTLS1_HM_HEADER_LENGTH)
- {
- memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st));
-
- s->d1->handshake_read_seq++;
- /* we just read a handshake message from the other side:
- * this means that we don't need to retransmit of the
- * buffered messages.
- * XDTLS: may be able clear out this
- * buffer a little sooner (i.e if an out-of-order
- * handshake message/record is received at the record
- * layer.
- * XDTLS: exception is that the server needs to
- * know that change cipher spec and finished messages
- * have been received by the client before clearing this
- * buffer. this can simply be done by waiting for the
- * first data segment, but is there a better way? */
- dtls1_clear_record_buffer(s);
-
- s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
- return s->init_num - DTLS1_HM_HEADER_LENGTH;
- }
- else
- s->d1->r_msg_hdr.frag_off = i;
- } while(1) ;
-
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
- *ok = 0;
- return -1;
- }
-
-
-static int
-dtls1_retrieve_buffered_fragment(SSL *s, unsigned long *copied)
- {
- /* (0) check whether the desired fragment is available
- * if so:
- * (1) copy over the fragment to s->init_buf->data[]
- * (2) update s->init_num
- */
- pitem *item;
- hm_fragment *frag;
- unsigned long overlap;
- unsigned char *p;
-
- item = pqueue_peek(s->d1->buffered_messages);
- if ( item == NULL)
- return 0;
-
- frag = (hm_fragment *)item->data;
-
- if ( s->d1->handshake_read_seq == frag->msg_header.seq &&
- frag->msg_header.frag_off <= (unsigned int)s->init_num - DTLS1_HM_HEADER_LENGTH)
- {
- pqueue_pop(s->d1->buffered_messages);
- overlap = s->init_num - DTLS1_HM_HEADER_LENGTH
- - frag->msg_header.frag_off;
-
- p = frag->fragment;
-
- memcpy(&s->init_buf->data[s->init_num],
- p + DTLS1_HM_HEADER_LENGTH + overlap,
- frag->msg_header.frag_len - overlap);
-
- OPENSSL_free(frag->fragment);
- OPENSSL_free(frag);
- pitem_free(item);
-
- *copied = frag->msg_header.frag_len - overlap;
- return *copied;
- }
- else
- return 0;
- }