Use WSASend() to send several buffer per one sys-call.
Unified send()/recv() support for POSIX/Win32.
Signed-off-by: Evgeny Grin <k2k@narod.ru>
#endif
handshake_internal_state_clear1(*session);
-#ifdef HAVE_WRITEV
#ifdef MSG_NOSIGNAL
if (flags & GNUTLS_NO_SIGNAL)
gnutls_transport_set_vec_push_function(*session, system_writev_nosignal);
else
#endif
gnutls_transport_set_vec_push_function(*session, system_writev);
-#else
- gnutls_transport_set_push_function(*session, system_write);
-#endif
(*session)->internals.pull_timeout_func = gnutls_system_recv_timeout;
(*session)->internals.pull_func = system_read;
(*session)->internals.errno_func = system_errno;
int system_errno(gnutls_transport_ptr_t);
-#ifdef _WIN32
ssize_t system_write(gnutls_transport_ptr_t ptr, const void *data,
size_t data_size);
-#else
#define HAVE_WRITEV
ssize_t system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec,
int iovec_cnt);
int iovec_cnt);
ssize_t system_writev_nosignal_tfo(gnutls_session_t ptr, const giovec_t * iovec,
int iovec_cnt);
-#endif
ssize_t system_read(gnutls_transport_ptr_t ptr, void *data,
size_t data_size);
#ifdef _WIN32
static ssize_t
-tfo_send(gnutls_transport_ptr_t ptr, const void *buf, size_t len)
+tfo_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec, int iovec_cnt)
{
tfo_st *p = ptr;
int fd = p->fd;
if (unlikely(p->connect_addrlen != 0)) {
int ret;
- ret = connect(fd, (struct sockaddr*)&p->connect_addr, p->connect_addrlen);
+ ret = connect(fd, (struct sockaddr*)&p->connect_addr,
+ p->connect_addrlen);
if (ret == -1 && (errno == EINPROGRESS)) {
gnutls_assert();
errno = EAGAIN;
return ret;
}
- return send(fd, buf, len, 0);
+ return system_writev(GNUTLS_INT_TO_POINTER(fd), iovec, iovec_cnt);
}
#else /* sendmsg */
static ssize_t
session->internals.tfo.flags |= MSG_NOSIGNAL;
#endif
-#ifdef _WIN32
- gnutls_transport_set_vec_push_function(session, NULL);
- gnutls_transport_set_push_function(session, tfo_send);
-#else
gnutls_transport_set_vec_push_function(session, tfo_writev);
-#endif
}
{
return send(GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0);
}
+
+ssize_t
+system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec,
+ int iovec_cnt)
+{
+ WSABUF bufs[iovec_cnt];
+ DWORD bytes_sent;
+ int to_send_cnt = 0;
+ size_t to_send_bytes = 0;
+
+ while (to_send_cnt < iovec_cnt && to_send_bytes < SSIZE_MAX) {
+ bufs[to_send_cnt].buf = iovec[to_send_cnt].iov_base;
+
+ if (to_send_bytes + iovec[to_send_cnt].iov_len > SSIZE_MAX) {
+ /* Return value limit: successful result value cannot
+ * exceed SSIZE_MAX */
+ size_t space_left = (size_t)SSIZE_MAX - to_send_bytes;
+ bufs[to_send_cnt].len = (unsigned long)
+ (space_left > ULONG_MAX ?
+ ULONG_MAX : space_left);
+ to_send_cnt++;
+ break;
+ }
+ if (iovec[to_send_cnt].iov_len > ULONG_MAX) {
+ /* WSASend() limitation */
+ bufs[to_send_cnt].len = ULONG_MAX;
+ to_send_cnt++;
+ break;
+ }
+ bufs[to_send_cnt].len =
+ (unsigned long) iovec[to_send_cnt].iov_len;
+ to_send_bytes += iovec[to_send_cnt].iov_len;
+ to_send_cnt++;
+ }
+
+ if (WSASend(GNUTLS_POINTER_TO_INT(ptr), bufs, to_send_cnt, &bytes_sent,
+ 0, NULL, NULL) != 0)
+ return -1;
+
+ return (ssize_t)bytes_sent;
+}
+
#else /* POSIX */
int system_errno(gnutls_transport_ptr_t ptr)
{