diff options
author | Joe Orton <notroj@users.noreply.github.com> | 2008-08-03 19:17:23 +0000 |
---|---|---|
committer | Joe Orton <notroj@users.noreply.github.com> | 2008-08-03 19:17:23 +0000 |
commit | c3f697bc548c8229c8171ab50f5a55c67c74114a (patch) | |
tree | 81fa77db3e0ae483c1cdfbc64e21a23d36e3348d /src | |
parent | 0263e3fcbf070b99f7428bb276c0a34ec3a77a17 (diff) | |
download | neon-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.c | 80 | ||||
-rw-r--r-- | src/ne_socket.h | 13 |
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: |