* Version 2.11.0 (unreleased)
+** libgnutls: support scattered write using writev(). This takes
+advantage of the new buffering layer and allows queuing of packets
+and flushing them. This is currently used for handshake messages
+only.
+
** libgnutls: Added gnutls_global_set_mutex() to allow setting
alternative locking procedures. By default the system available
locking is used. In *NIX pthreads are used and in windows the
-critical section API.
+critical section API. This follows a different approach than the
+previous versions that depended on libgcrypt initialization. The
+locks are now set by default in systems that support it.
** libgnutls: Added support for reading DN from EV-certificates.
New DN values:
code contributed by Jonathan Bastien-Filiatrault.
** libgnutls: Internal API for extensions augmented to allow
-safe storing and loading of data on resumption. OPRFI extension
-was removed.
+safe storing and loading of data on resumption. This allows writing
+self-contained extensions (when possible). As a side effect
+the OPRFI extension was removed.
** libgnutls: Added support for DSA-SHA256 and DSA-SHA224
nw="$nw -Wconversion" # Too many warnings for now
nw="$nw -Wsign-conversion" # Too many warnings for now
nw="$nw -Wformat-y2k" # Too many warnings for now
+ nw="$nw -Wvla" # There is no point to avoid C99 variable length arrays
nw="$nw -Wformat-nonliteral" # Incompatible with gettext _()
nw="$nw -Wunsafe-loop-optimizations"
nw="$nw -Wstrict-overflow"
_gnutls_record_log ("REC: Sending Alert[%d|%d] - %s\n", data[0],
data[1], name);
- if ((ret = _gnutls_send_int (session, GNUTLS_ALERT, -1, data, 2)) >= 0)
+ if ((ret = _gnutls_send_int (session, GNUTLS_ALERT, -1, data, 2, MBUFFER_FLUSH)) >= 0)
return 0;
else
return ret;
#include <errno.h>
+#ifndef _WIN32
+# include <sys/uio.h>
+#endif
+
/* We need to disable gnulib's replacement wrappers to get native
Windows interfaces. */
#undef recv
# define EAGAIN EWOULDBLOCK
#endif
+/* this is the maximum number of messages allowed to queue.
+ */
+#define MAX_QUEUE 16
/**
* gnutls_transport_set_errno:
return length;
}
+inline static void reset_errno(gnutls_session_t session)
+{
+ session->internals.errnum = 0;
+}
+
+inline static int get_errno(gnutls_session_t session)
+{
+ if (session->internals.errnum != 0)
+ return session->internals.errnum;
+ else
+ return session->internals.errno_func(session->internals.transport_recv_ptr);
+}
+
/* This function is like read. But it does not return -1 on error.
* It does return gnutls_errno instead.
while (left > 0)
{
- session->internals.errnum = 0;
-
- if (session->internals._gnutls_pull_func == NULL)
- {
- i = recv (GNUTLS_POINTER_TO_INT (fd), &ptr[sizeOfPtr - left],
- left, flags);
-#if HAVE_WINSOCK2_H
- if (i < 0)
- {
- int tmperr = WSAGetLastError ();
- switch (tmperr)
- {
- case WSAEWOULDBLOCK:
- session->internals.errnum = EAGAIN;
- break;
-
- case WSAEINTR:
- session->internals.errnum = EINTR;
- break;
+ reset_errno(session);
- default:
- session->internals.errnum = EIO;
- break;
- }
- WSASetLastError (tmperr);
- }
-#endif
- }
- else
- i = session->internals._gnutls_pull_func (fd,
- &ptr[sizeOfPtr -
- left], left);
+ i = session->internals.pull_func (fd, &ptr[sizeOfPtr - left], left);
if (i < 0)
{
- int err = session->internals.errnum ? session->internals.errnum
- : errno;
+ int err = get_errno(session);
_gnutls_read_log ("READ: %d returned from %p, errno=%d gerrno=%d\n",
(int) i, fd, errno, session->internals.errnum);
return (sizeOfPtr - left);
}
+
+
static ssize_t
-_gnutls_write (gnutls_session_t session, void *iptr,
- size_t sizeOfPtr)
+_gnutls_writev_emu (gnutls_session_t session, const giovec_t * giovec, int giovec_cnt)
{
- int i;
+ int ret, j = 0;
gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
+ void* iptr;
+ size_t sizeOfPtr;
+ size_t total = 0;
- session->internals.errnum = 0;
-
- if (session->internals._gnutls_push_func == NULL)
+ for (j=0;j<giovec_cnt;j++)
{
- i = send (GNUTLS_POINTER_TO_INT (fd), iptr, sizeOfPtr, 0);
-#if HAVE_WINSOCK2_H
- if (i < 0)
- {
- int tmperr = WSAGetLastError ();
- switch (tmperr)
- {
- case WSAEWOULDBLOCK:
- session->internals.errnum = EAGAIN;
- break;
+ sizeOfPtr = giovec[j].iov_len;
+ iptr = giovec[j].iov_base;
+
+ ret = session->internals.push_func (fd, iptr, sizeOfPtr);
- case WSAEINTR:
- session->internals.errnum = EINTR;
- break;
+ if (ret == -1)
+ break;
- default:
- session->internals.errnum = EIO;
- break;
- }
- WSASetLastError (tmperr);
- }
-#endif
+ total += ret;
}
+
+ if (total > 0)
+ return total;
+
+ return ret;
+}
+
+static ssize_t
+_gnutls_writev (gnutls_session_t session, const giovec_t * giovec, int giovec_cnt)
+{
+ int i;
+ gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
+
+ reset_errno(session);
+
+ if (session->internals.push_func != NULL)
+ i = _gnutls_writev_emu(session, giovec, giovec_cnt);
else
- i = session->internals._gnutls_push_func (fd, iptr, sizeOfPtr);
+ i = session->internals.vec_push_func (fd, giovec, giovec_cnt);
if (i == -1)
{
- int err = session->internals.errnum ? session->internals.errnum
- : errno;
-
+ int err = get_errno(session);
+_gnutls_debug_log("errno: %d\n", err);
if (err == EAGAIN)
return GNUTLS_E_AGAIN;
else if (err == EINTR)
}
return i;
}
+
#define RCVLOWAT session->internals.lowat
/* This function is only used with berkeley style sockets.
/* If an external pull function is used, then do not leave
* any data into the kernel buffer.
*/
- if (session->internals._gnutls_pull_func != NULL)
+ if (session->internals.pull_func != NULL)
{
recvlowat = 0;
}
*/
ssize_t
_gnutls_io_write_buffered (gnutls_session_t session,
- mbuffer_st *bufel)
+ mbuffer_st *bufel, unsigned int mflag)
{
mbuffer_head_st * const send_buffer = &session->internals.record_send_buffer;
(int)bufel->msg.size, session->internals.transport_recv_ptr,
(int)send_buffer->byte_length);
- return _gnutls_io_write_flush (session);
+ if (mflag == MBUFFER_FLUSH)
+ return _gnutls_io_write_flush (session);
+ else
+ return bufel->msg.size;
}
+typedef ssize_t (*send_func)(gnutls_session_t, const giovec_t *, int);
+
/* This function writes the data that are left in the
* TLS write buffer (ie. because the previous write was
* interrupted.
ssize_t
_gnutls_io_write_flush (gnutls_session_t session)
{
- mbuffer_head_st * const send_buffer = &session->internals.record_send_buffer;
gnutls_datum_t msg;
+ mbuffer_head_st * send_buffer = &session->internals.record_send_buffer;
int ret;
- ssize_t total = 0;
+ ssize_t sent = 0, tosend = 0;
+ giovec_t iovec[MAX_QUEUE];
+ int i = 0;
+ mbuffer_st* cur;
_gnutls_write_log ("WRITE FLUSH: %d bytes in buffer.\n",
(int)send_buffer->byte_length);
- for (_mbuffer_get_head (send_buffer, &msg);
- msg.data != NULL && msg.size > 0;
- _mbuffer_get_head (send_buffer, &msg))
+ for (cur=_mbuffer_get_first(send_buffer, &msg);
+ cur != NULL;
+ cur = _mbuffer_get_next (cur, &msg))
+ {
+ iovec[i].iov_base = msg.data;
+ iovec[i++].iov_len = msg.size;
+ tosend += msg.size;
+
+ /* we buffer up to MAX_QUEUE messages */
+ if (i>=sizeof(iovec)/sizeof(iovec[0]))
+ {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+ }
+
+ ret = _gnutls_writev (session, iovec, i);
+ if (ret >= 0)
{
- ret = _gnutls_write (session, msg.data, msg.size);
-
- if (ret >= 0)
- {
- _mbuffer_remove_bytes (send_buffer, ret);
-
- _gnutls_write_log ("WRITE: wrote %d bytes, %d bytes left.\n",
+ _mbuffer_remove_bytes (send_buffer, ret);
+ _gnutls_write_log ("WRITE: wrote %d bytes, %d bytes left.\n",
ret, (int)send_buffer->byte_length);
- total += ret;
- }
- else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
- {
- _gnutls_write_log ("WRITE interrupted: %d bytes left.\n",
+ sent += ret;
+ }
+ else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
+ {
+ _gnutls_write_log ("WRITE interrupted: %d bytes left.\n",
(int)send_buffer->byte_length);
return ret;
- }
- else
- {
- _gnutls_write_log ("WRITE error: code %d, %d bytes left.\n",
- ret, (int)send_buffer->byte_length);
+ }
+ else
+ {
+ _gnutls_write_log ("WRITE error: code %d, %d bytes left.\n",
+ ret, (int)send_buffer->byte_length);
- gnutls_assert ();
- return ret;
- }
+ gnutls_assert ();
+ return ret;
+ }
+
+ if (sent < tosend)
+ {
+ gnutls_assert();
+ return GNUTLS_E_AGAIN;
}
- return total;
+ return sent;
}
/* This function writes the data that are left in the
* Handshake write buffer (ie. because the previous write was
* interrupted.
*
- * FIXME: This is practically the same as _gnutls_io_write_flush.
*/
ssize_t
_gnutls_handshake_io_write_flush (gnutls_session_t session)
gnutls_datum_t msg;
int ret;
ssize_t total = 0;
+ mbuffer_st * cur;
_gnutls_write_log ("HWRITE FLUSH: %d bytes in buffer.\n",
(int)send_buffer->byte_length);
- for (_mbuffer_get_head (send_buffer, &msg);
- msg.data != NULL && msg.size > 0;
- _mbuffer_get_head (send_buffer, &msg))
+ for (cur = _mbuffer_get_first (send_buffer, &msg);
+ cur != NULL;
+ cur = _mbuffer_get_first (send_buffer, &msg))
{
ret = _gnutls_send_int (session, GNUTLS_HANDSHAKE,
session->internals.handshake_send_buffer_htype,
- msg.data, msg.size);
+ msg.data, msg.size, 0/* do not flush */);
if (ret >= 0)
{
total += ret;
}
- else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
- {
- _gnutls_write_log ("HWRITE interrupted: %d bytes left.\n",
- (int)send_buffer->byte_length);
- return ret;
- }
else
{
_gnutls_write_log ("HWRITE error: code %d, %d bytes left.\n",
}
}
- return total;
+ return _gnutls_io_write_flush (session);
+
}
/* This is a send function for the gnutls handshake
* protocol. Just makes sure that all data have been sent.
*
- * FIXME: This is practically the same as _gnutls_io_write_buffered.
*/
-ssize_t
-_gnutls_handshake_io_send_int (gnutls_session_t session,
+void
+_gnutls_handshake_io_cache_int (gnutls_session_t session,
gnutls_handshake_description_t htype,
mbuffer_st *bufel)
{
(int)bufel->msg.size,
(int)send_buffer->byte_length);
- return _gnutls_handshake_io_write_flush(session);
+ return;
}
/* This is a receive function for the gnutls handshake
return 0;
}
+
+/**
+ * gnutls_transport_set_pull_function:
+ * @pull_func: a callback function similar to read()
+ * @session: gnutls session
+ *
+ * This is the function where you set a function for gnutls to receive
+ * data. Normally, if you use berkeley style sockets, do not need to
+ * use this function since the default (recv(2)) will probably be ok.
+ *
+ * PULL_FUNC is of the form,
+ * ssize_t (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t);
+ **/
+void
+gnutls_transport_set_pull_function (gnutls_session_t session,
+ gnutls_pull_func pull_func)
+{
+ session->internals.pull_func = pull_func;
+}
+
+/**
+ * gnutls_transport_set_push_function:
+ * @push_func: a callback function similar to write()
+ * @session: gnutls session
+ *
+ * This is the function where you set a push function for gnutls to
+ * use in order to send data. If you are going to use berkeley style
+ * sockets, you do not need to use this function since the default
+ * (send(2)) will probably be ok. Otherwise you should specify this
+ * function for gnutls to be able to send data.
+ *
+ * PUSH_FUNC is of the form,
+ * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
+ **/
+void
+gnutls_transport_set_push_function (gnutls_session_t session,
+ gnutls_push_func push_func)
+{
+ session->internals.push_func = push_func;
+ session->internals.vec_push_func = NULL;
+}
+
+/**
+ * @session: gnutls session
+ * gnutls_transport_set_push_function2:
+ * @vec_func: a callback function similar to writev()
+ *
+ * This is the function where you set a push function for gnutls to
+ * use in order to send data. If you are going to use berkeley style
+ * sockets, you do not need to use this function since the default
+ * (send(2)) will probably be ok. Otherwise you should specify this
+ * function for gnutls to be able to send data.
+ *
+ * PUSH_FUNC is of the form,
+ * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
+ **/
+void
+gnutls_transport_set_push_function2 (gnutls_session_t session,
+ gnutls_vec_push_func vec_func)
+{
+ session->internals.push_func = NULL;
+ session->internals.vec_push_func = vec_func;
+}
+
+/**
+ * @session: gnutls session
+ * gnutls_transport_set_errno_function:
+ * @errno_func: a callback function similar to write()
+ *
+ * This is the function where you set a function to retrieve errno
+ * after a failed push or pull operation.
+ *
+ * errno_func is of the form,
+ * int (*gnutls_errno_func)(gnutls_transport_ptr_t);
+ * and should return the errno.
+ **/
+void
+gnutls_transport_set_errno_function (gnutls_session_t session,
+ gnutls_errno_func errno_func)
+{
+ session->internals.errno_func = errno_func;
+}
* USA
*
*/
+#ifndef GNUTLS_BUFFERS_H
+# define GNUTLS_BUFFERS_H
+
+#define MBUFFER_FLUSH 1
int _gnutls_record_buffer_put (content_type_t type,
gnutls_session_t session, opaque * data,
int _gnutls_io_clear_peeked_data (gnutls_session_t session);
ssize_t _gnutls_io_write_buffered (gnutls_session_t session,
- mbuffer_st *bufel);
+ mbuffer_st *bufel, unsigned int mflag);
int _gnutls_handshake_buffer_get_size (gnutls_session_t session);
int _gnutls_handshake_buffer_put (gnutls_session_t session, opaque * data,
ssize_t _gnutls_handshake_io_recv_int (gnutls_session_t, content_type_t,
gnutls_handshake_description_t, void *,
size_t);
-ssize_t _gnutls_handshake_io_send_int (gnutls_session_t,
+void _gnutls_handshake_io_cache_int (gnutls_session_t,
gnutls_handshake_description_t,
mbuffer_st *bufel);
ssize_t _gnutls_io_write_flush (gnutls_session_t session);
ssize_t _gnutls_handshake_io_write_flush (gnutls_session_t session);
+
+#endif
* historical reasons.
*/
-/**
- * gnutls_transport_set_pull_function:
- * @pull_func: a callback function similar to read()
- * @session: gnutls session
- *
- * This is the function where you set a function for gnutls to receive
- * data. Normally, if you use berkeley style sockets, do not need to
- * use this function since the default (recv(2)) will probably be ok.
- *
- * PULL_FUNC is of the form,
- * ssize_t (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t);
- **/
-void
-gnutls_transport_set_pull_function (gnutls_session_t session,
- gnutls_pull_func pull_func)
-{
- session->internals._gnutls_pull_func = pull_func;
-}
-
-/**
- * gnutls_transport_set_push_function:
- * @push_func: a callback function similar to write()
- * @session: gnutls session
- *
- * This is the function where you set a push function for gnutls to
- * use in order to send data. If you are going to use berkeley style
- * sockets, you do not need to use this function since the default
- * (send(2)) will probably be ok. Otherwise you should specify this
- * function for gnutls to be able to send data.
- *
- * PUSH_FUNC is of the form,
- * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
- **/
-void
-gnutls_transport_set_push_function (gnutls_session_t session,
- gnutls_push_func push_func)
-{
- session->internals._gnutls_push_func = push_func;
-}
/**
* gnutls_check_version:
session->internals.last_handshake_out = type;
- ret = _gnutls_handshake_io_send_int (session, type, bufel);
+ _gnutls_handshake_io_cache_int (session, type, bufel);
+
+ switch (type)
+ {
+ case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: /* this one is followed by ServerHelloDone
+ * or ClientKeyExchange always.
+ */
+ case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE: /* as above */
+ case GNUTLS_HANDSHAKE_SERVER_HELLO: /* as above */
+ case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: /* as above */
+ case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: /* followed by ChangeCipherSpec */
+
+ /* now for client Certificate, ClientKeyExchange and
+ * CertificateVerify are always followed by ChangeCipherSpec
+ */
+ case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
+ case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE:
+ ret = 0;
+ break;
+ default:
+ /* send cached messages */
+ ret = _gnutls_handshake_io_write_flush(session);
+ break;
+ }
return ret;
}
* CertificateVerify*
* [ChangeCipherSpec]
* Finished -------->
+ * NewSessionTicket
* [ChangeCipherSpec]
* <-------- Finished
*
* (*): means optional packet.
*/
+/* Handshake when resumming session:
+ * Client Server
+ *
+ * ClientHello -------->
+ * ServerHello
+ * [ChangeCipherSpec]
+ * <-------- Finished
+ * [ChangeCipherSpec]
+ * Finished -------->
+ *
+ */
+
/**
* gnutls_rehandshake:
* @session: is a #gnutls_session_t structure.
_gnutls_send_handshake_final (gnutls_session_t session, int init)
{
int ret = 0;
+ int oldstate = STATE;
/* Send the CHANGE CIPHER SPEC PACKET */
{
case STATE0:
case STATE20:
- ret = _gnutls_send_change_cipher_spec (session, AGAIN (STATE20));
+
STATE = STATE20;
+
+ ret = _gnutls_handshake_io_write_flush(session);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = _gnutls_send_change_cipher_spec (session, AGAIN2 (oldstate, STATE20));
+
if (ret < 0)
{
ERR ("send ChangeCipherSpec", ret);
/* This returns true if we have got there
* before (and not finished due to an interrupt).
*/
-#define AGAIN(target) STATE==target?1:0
+#define AGAIN(target) (STATE==target?1:0)
+#define AGAIN2(state, target) (state==target?1:0)
/* PUSH & PULL functions.
*/
- gnutls_pull_func _gnutls_pull_func;
- gnutls_push_func _gnutls_push_func;
+ gnutls_pull_func pull_func;
+ gnutls_push_func push_func;
+ gnutls_vec_push_func vec_push_func;
+ gnutls_errno_func errno_func;
/* Holds the first argument of PUSH and PULL
* functions;
*/
buf->tail = &bufel->next;
}
-void
-_mbuffer_get_head (mbuffer_head_st *buf, gnutls_datum_t *msg)
+mbuffer_st* _mbuffer_get_first (mbuffer_head_st *buf, gnutls_datum_t *msg)
{
- mbuffer_st *bufel;
+ mbuffer_st *bufel = buf->head;
+
+ if (bufel)
+ {
+ msg->data = bufel->msg.data + bufel->mark;
+ msg->size = bufel->msg.size - bufel->mark;
+ }
+ else
+ {
+ msg->data = NULL;
+ msg->size = 0;
+ }
+ return bufel;
+}
+
+mbuffer_st* _mbuffer_get_next (mbuffer_st * cur, gnutls_datum_t *msg)
+{
+ mbuffer_st *bufel = cur->next;
- if (buf->head)
+ if (bufel)
{
- bufel = buf->head;
msg->data = bufel->msg.data + bufel->mark;
msg->size = bufel->msg.size - bufel->mark;
}
msg->data = NULL;
msg->size = 0;
}
+ return bufel;
}
static inline void
void _mbuffer_init (mbuffer_head_st *buf);
void _mbuffer_clear (mbuffer_head_st *buf);
void _mbuffer_enqueue (mbuffer_head_st *buf, mbuffer_st *bufel);
-void _mbuffer_get_head (mbuffer_head_st *buf, gnutls_datum_t *msg);
int _mbuffer_remove_bytes (mbuffer_head_st *buf, size_t bytes);
mbuffer_st* _mbuffer_alloc (size_t payload_size, size_t maximum_size);
+mbuffer_st* _mbuffer_get_first (mbuffer_head_st *buf, gnutls_datum_t *msg);
+mbuffer_st* _mbuffer_get_next (mbuffer_st * cur, gnutls_datum_t *msg);
+
/* This is dangerous since it will replace bufel with a new
* one.
*/
ssize_t
_gnutls_send_int (gnutls_session_t session, content_type_t type,
gnutls_handshake_description_t htype, const void *_data,
- size_t sizeofdata)
+ size_t sizeofdata, unsigned int mflags)
{
mbuffer_st *bufel;
size_t cipher_size;
/* Only encrypt if we don't have data to send
* from the previous run. - probably interrupted.
*/
- if (session->internals.record_send_buffer.byte_length > 0)
+ if (mflags != 0 && session->internals.record_send_buffer.byte_length > 0)
{
ret = _gnutls_io_write_flush (session);
if (ret > 0)
}
_mbuffer_set_udata_size(bufel, cipher_size);
- ret = _gnutls_io_write_buffered (session, bufel);
+ ret = _gnutls_io_write_buffered (session, bufel, mflags);
}
if (ret != cipher_size)
_gnutls_handshake_log ("REC[%p]: Sent ChangeCipherSpec\n", session);
if (again == 0)
- return _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, data, 1);
+ return _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, data, 1, MBUFFER_FLUSH);
else
{
return _gnutls_io_write_flush (session);
size_t sizeofdata)
{
return _gnutls_send_int (session, GNUTLS_APPLICATION_DATA, -1, data,
- sizeofdata);
+ sizeofdata, MBUFFER_FLUSH);
}
/**
*
*/
+#ifndef GNUTLS_RECORD_H
+# define GNUTLS_RECORD_H
+
+# include <gnutls/gnutls.h>
+# include <gnutls_buffers.h>
+
ssize_t _gnutls_send_int (gnutls_session_t session, content_type_t type,
gnutls_handshake_description_t htype,
- const void *data, size_t sizeofdata);
+ const void *data, size_t sizeofdata, unsigned int mflags);
ssize_t _gnutls_recv_int (gnutls_session_t session, content_type_t type,
gnutls_handshake_description_t, opaque * data,
size_t sizeofdata);
ssize_t _gnutls_send_change_cipher_spec (gnutls_session_t session, int again);
+
+#endif
#include <gnutls_rsa_export.h>
#include <gnutls_extensions.h>
+#include <errno.h>
+
/* These should really be static, but src/tests.c calls them. Make
them public functions? */
void
}
+/* wrappers for write() and writev()
+ */
+#ifdef _WIN32
+
+static int system_errno(gnutls_transport_ptr)
+{
+ int tmperr = WSAGetLastError ();
+ int ret = 0;
+ switch (tmperr)
+ {
+ case WSAEWOULDBLOCK:
+ ret = EAGAIN;
+ break;
+ case WSAEINTR:
+ ret = EINTR;
+ break;
+ default:
+ ret = EIO;
+ break;
+ }
+ WSASetLastError (tmperr);
+
+ return ret;
+}
+
+static ssize_t system_write(gnutls_transport_ptr ptr, const void* data, size_t data_size)
+{
+ return send( GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0);
+}
+#else /* POSIX */
+static int system_errno(gnutls_transport_ptr ptr)
+{
+ return errno;
+}
+
+static ssize_t system_writev(gnutls_transport_ptr ptr, const giovec_t * iovec, int iovec_cnt)
+{
+ return writev(GNUTLS_POINTER_TO_INT(ptr), (struct iovec*) iovec, iovec_cnt);
+
+}
+#endif
+
+static ssize_t system_read(gnutls_transport_ptr ptr, void* data, size_t data_size)
+{
+ return recv( GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0);
+}
+
#define MIN_DH_BITS 727
/**
* gnutls_init:
*/
(*session)->internals.priorities.sr = SR_PARTIAL;
+#ifdef _WIN32
+ gnutls_transport_set_push_function(*session, system_write);
+#else
+ gnutls_transport_set_push_function2(*session, system_writev);
+#endif
+ gnutls_transport_set_pull_function(*session, system_read);
+ gnutls_transport_set_errno_function(*session, system_errno);
+
return 0;
}
/* Session stuff
*/
+ typedef struct {
+ void *iov_base; /* Starting address */
+ size_t iov_len; /* Number of bytes to transfer */
+ } giovec_t;
+
typedef ssize_t (*gnutls_pull_func) (gnutls_transport_ptr_t, void *,
size_t);
- typedef ssize_t (*gnutls_push_func) (gnutls_transport_ptr_t, const void *,
- size_t);
+ typedef ssize_t (*gnutls_push_func) (gnutls_transport_ptr_t, const void *, size_t);
+
+ typedef ssize_t (*gnutls_vec_push_func) (gnutls_transport_ptr_t, const giovec_t *iov, int iovcnt);
+
+ typedef int (*gnutls_errno_func) (gnutls_transport_ptr_t);
+
void gnutls_transport_set_ptr (gnutls_session_t session,
gnutls_transport_ptr_t ptr);
void gnutls_transport_set_ptr2 (gnutls_session_t session,
void gnutls_transport_set_lowat (gnutls_session_t session, int num);
+ void gnutls_transport_set_push_function2 (gnutls_session_t session,
+ gnutls_vec_push_func vec_func);
void gnutls_transport_set_push_function (gnutls_session_t session,
gnutls_push_func push_func);
void gnutls_transport_set_pull_function (gnutls_session_t session,
gnutls_pull_func pull_func);
+ void gnutls_transport_set_errno_function (gnutls_session_t session,
+ gnutls_errno_func errno_func);
+
void gnutls_transport_set_errno (gnutls_session_t session, int err);
void gnutls_transport_set_global_errno (int err);
gnutls_pubkey_get_preferred_hash_algorithm;
gnutls_x509_crt_get_preferred_hash_algorithm;
gnutls_global_set_mutex;
+ gnutls_transport_set_push_function2;
+ gnutls_transport_set_errno_function;
gnutls_sec_param_to_pk_bits;
gnutls_sec_param_get_name;
memcpy (p + 4, data, sizeofdata);
}
- len = _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1, p, plen);
+ len = _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1, p, plen, MBUFFER_FLUSH);
if (p)
gnutls_free (p);