void
buffer_list_free (struct buffer_list *ol)
{
- buffer_list_reset (ol);
- free (ol);
+ if (ol)
+ {
+ buffer_list_reset (ol);
+ free (ol);
+ }
}
bool
void
buffer_list_push (struct buffer_list *ol, const unsigned char *str)
{
- if (!ol->max_size || ol->size < ol->max_size)
+ if (str)
+ {
+ const size_t len = strlen ((const char *)str);
+ struct buffer_entry *e = buffer_list_push_data (ol, str, len+1);
+ if (e)
+ e->buf.len = len; /* Don't count trailing '\0' as part of length */
+ }
+}
+
+struct buffer_entry *
+buffer_list_push_data (struct buffer_list *ol, const uint8_t *data, size_t size)
+{
+ struct buffer_entry *e = NULL;
+ if (data && (!ol->max_size || ol->size < ol->max_size))
{
- struct buffer_entry *e;
ALLOC_OBJ_CLEAR (e, struct buffer_entry);
++ol->size;
ASSERT (!ol->head);
ol->head = e;
}
- e->buf = string_alloc_buf ((const char *) str, NULL);
+ e->buf = alloc_buf (size);
+ memcpy (e->buf.data, data, size);
+ e->buf.len = (int)size;
ol->tail = e;
}
+ return e;
}
struct buffer *
buffer_list_peek (struct buffer_list *ol)
{
- if (ol->head)
+ if (ol && ol->head)
return &ol->head->buf;
else
return NULL;
}
}
-static void
+void
buffer_list_pop (struct buffer_list *ol)
{
- if (ol->head)
+ if (ol && ol->head)
{
struct buffer_entry *e = ol->head->next;
free_buf (&ol->head->buf);
void buffer_list_reset (struct buffer_list *ol);
void buffer_list_push (struct buffer_list *ol, const unsigned char *str);
+struct buffer_entry *buffer_list_push_data (struct buffer_list *ol, const uint8_t *data, size_t size);
struct buffer *buffer_list_peek (struct buffer_list *ol);
void buffer_list_advance (struct buffer_list *ol, int n);
+void buffer_list_pop (struct buffer_list *ol);
void buffer_list_aggregate (struct buffer_list *bl, const size_t max);
free_buf (&ks->plaintext_read_buf);
free_buf (&ks->plaintext_write_buf);
free_buf (&ks->ack_write_buf);
+ buffer_list_free(ks->paybuf);
if (ks->send_reliable)
{
return 1;
}
+static void
+flush_payload_buffer (struct tls_multi *multi, struct key_state *ks)
+{
+ struct buffer *b;
+ while ((b = buffer_list_peek (ks->paybuf)))
+ {
+ key_state_write_plaintext_const (multi, ks, b->data, b->len);
+ buffer_list_pop (ks->paybuf);
+ }
+}
+
/*
* Macros for key_state_soft_reset & tls_process
*/
/* Set outgoing address for data channel packets */
link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es);
+ /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */
+ flush_payload_buffer (multi, ks);
+
#ifdef MEASURE_TLS_HANDSHAKE_STATS
show_tls_performance_stats();
#endif
if (key_state_write_plaintext_const (multi, ks, data, size) == 1)
ret = true;
}
+ else
+ {
+ if (!ks->paybuf)
+ ks->paybuf = buffer_list_new (0);
+ buffer_list_push_data (ks->paybuf, data, (size_t)size);
+ ret = true;
+ }
ERR_clear_error ();
struct reliable *rec_reliable; /* order incoming ciphertext packets before we pass to TLS */
struct reliable_ack *rec_ack; /* buffers all packet IDs we want to ACK back to sender */
+ struct buffer_list *paybuf;
+
int n_bytes; /* how many bytes sent/recvd since last key exchange */
int n_packets; /* how many packets sent/recvd since last key exchange */
#endif
/*
- * Don't compile the struct buffer_list code unless something needs it
+ * Compile the struct buffer_list code
*/
-#if defined(ENABLE_MANAGEMENT) || defined(ENABLE_PF)
#define ENABLE_BUFFER_LIST
-#endif
/*
* Do we have pthread capability?
dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1.1m])
+define(PRODUCT_VERSION,[2.1.1n])
dnl define the TAP version
define(PRODUCT_TAP_ID,[tap0901])
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])