summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoe Orton <notroj@users.noreply.github.com>2008-08-03 19:17:23 +0000
committerJoe Orton <notroj@users.noreply.github.com>2008-08-03 19:17:23 +0000
commitc3f697bc548c8229c8171ab50f5a55c67c74114a (patch)
tree81fa77db3e0ae483c1cdfbc64e21a23d36e3348d /src
parent0263e3fcbf070b99f7428bb276c0a34ec3a77a17 (diff)
downloadneon-git-c3f697bc548c8229c8171ab50f5a55c67c74114a.tar.gz
* src/ne_socket.c (struct iofns): Add swritev member.
(writev_raw, writev_dummy, ne_sock_fullwritev): New functions. * src/ne_socket.h (struct ne_iovec): New structure. (ne_sock_fullwritev): New prototype. * test/socket.c (full_writev, large_writev): New test case. Submitted by: Julien.Reichel@spinetix.com, Joe
Diffstat (limited to 'src')
-rw-r--r--src/ne_socket.c80
-rw-r--r--src/ne_socket.h13
2 files changed, 90 insertions, 3 deletions
diff --git a/src/ne_socket.c b/src/ne_socket.c
index ce23695..020ec1c 100644
--- a/src/ne_socket.c
+++ b/src/ne_socket.c
@@ -188,6 +188,10 @@ struct iofns {
/* Wait up to 'n' seconds for socket to become readable. Returns
* 0 when readable, otherwise NE_SOCK_TIMEOUT or NE_SOCK_ERROR. */
int (*readable)(ne_socket *s, int n);
+ /* Write up to 'count' blocks described by 'vector' to socket.
+ * Return number of bytes written on success, or <0 on error. */
+ ssize_t (*swritev)(ne_socket *s, const struct ne_iovec *vector,
+ int count);
};
static const ne_inet_addr dummy_laddr;
@@ -545,7 +549,49 @@ static ssize_t write_raw(ne_socket *sock, const char *data, size_t length)
return ret;
}
-static const struct iofns iofns_raw = { read_raw, write_raw, readable_raw };
+static ssize_t writev_raw(ne_socket *sock, const struct ne_iovec *vector, int count)
+{
+ ssize_t ret;
+#ifdef WIN32
+ LPWSABUF wasvector = (LPWSABUF)ne_malloc(count * sizeof(WSABUF));
+ DWORD total;
+ int i;
+
+ for (i = 0; i < count; i++){
+ wasvector[i].buf = vector[i].base;
+ wasvector[i].len = vector[i].len;
+ }
+
+ ret = WSASend(sock->fd, wasvector, count, &total, 0, NULL, NULL);
+ if (ret == 0)
+ ret = total;
+
+ ne_free(wasvector);
+#else
+ const struct iovec *vec = (const struct iovec *) vector;
+
+ do {
+ ret = writev(sock->fd, vec, count);
+ } while (ret == -1 && NE_ISINTR(ne_errno));
+#endif
+
+ if (ret < 0) {
+ int errnum = ne_errno;
+ set_strerror(sock, errnum);
+ return MAP_ERR(errnum);
+ }
+
+ return ret;
+}
+
+#ifdef NE_HAVE_SSL
+static ssize_t writev_dummy(ne_socket *sock, const struct ne_iovec *vector, int count)
+{
+ return sock->ops->swrite(sock, vector[0].base, vector[0].len);
+}
+#endif
+
+static const struct iofns iofns_raw = { read_raw, write_raw, readable_raw, writev_raw };
#ifdef HAVE_OPENSSL
/* OpenSSL I/O function implementations. */
@@ -629,7 +675,8 @@ static ssize_t write_ossl(ne_socket *sock, const char *data, size_t len)
static const struct iofns iofns_ssl = {
read_ossl,
write_ossl,
- readable_ossl
+ readable_ossl,
+ writev_dummy
};
#elif defined(HAVE_GNUTLS)
@@ -734,7 +781,8 @@ static ssize_t write_gnutls(ne_socket *sock, const char *data, size_t len)
static const struct iofns iofns_ssl = {
read_gnutls,
write_gnutls,
- readable_gnutls
+ readable_gnutls,
+ writev_dummy
};
#endif
@@ -754,6 +802,32 @@ int ne_sock_fullwrite(ne_socket *sock, const char *data, size_t len)
return ret < 0 ? ret : 0;
}
+int ne_sock_fullwritev(ne_socket *sock, const struct ne_iovec *vector, int count)
+{
+ ssize_t ret;
+
+ do {
+ ret = sock->ops->swritev(sock, vector, count);
+ if (ret > 0) {
+ while (count && (size_t)ret >= vector[0].len) {
+ ret -= vector[0].len;
+ count--;
+ vector++;
+ }
+
+ if (ret && count) {
+ /* Partial buffer sent; send the rest. */
+ ret = ne_sock_fullwrite(sock, (char *)vector[0].base + ret,
+ vector[0].len - ret);
+ count--;
+ vector++;
+ }
+ }
+ } while (count && ret >= 0);
+
+ return ret < 0 ? ret : 0;
+}
+
ssize_t ne_sock_readline(ne_socket *sock, char *buf, size_t buflen)
{
char *lf;
diff --git a/src/ne_socket.h b/src/ne_socket.h
index 8ec3ad5..613f444 100644
--- a/src/ne_socket.h
+++ b/src/ne_socket.h
@@ -177,6 +177,19 @@ int ne_sock_block(ne_socket *sock, int n);
* on error. */
int ne_sock_fullwrite(ne_socket *sock, const char *data, size_t count);
+/* I/O vector. */
+struct ne_iovec {
+ void *base;
+ size_t len;
+};
+
+/* Writes 'count' blocks described by 'vector' to the socket.
+ * Guarantees to either write all the bytes or to fail. Count must be
+ * greater than zero and smaller than the system-defined maximum
+ * vector limit. Returns 0 on success, or NE_SOCK_* on error. */
+int ne_sock_fullwritev(ne_socket *sock, const struct ne_iovec *vector,
+ int count);
+
/* Read an LF-terminated line into 'buffer', and NUL-terminate it.
* At most 'len' bytes are read (including the NUL terminator).
* Returns: