Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F161557841
D57906.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D57906.diff
View Options
diff --git a/lib/libfetch/common.h b/lib/libfetch/common.h
--- a/lib/libfetch/common.h
+++ b/lib/libfetch/common.h
@@ -119,9 +119,9 @@
int fetch_ssl_cb_verify_crt(int, X509_STORE_CTX*);
#endif
int fetch_ssl(conn_t *, const struct url *, int);
-ssize_t fetch_read(conn_t *, char *, size_t);
+ssize_t fetch_read(conn_t *, void *, size_t);
int fetch_getln(conn_t *);
-ssize_t fetch_write(conn_t *, const char *, size_t);
+ssize_t fetch_write(conn_t *, const void *, size_t);
ssize_t fetch_writev(conn_t *, struct iovec *, int);
int fetch_putln(conn_t *, const char *, size_t);
int fetch_close(conn_t *);
diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c
--- a/lib/libfetch/common.c
+++ b/lib/libfetch/common.c
@@ -1253,13 +1253,9 @@
#endif
}
-#define FETCH_READ_WAIT -2
-#define FETCH_READ_ERROR -1
-#define FETCH_READ_DONE 0
-
#ifdef WITH_SSL
static ssize_t
-fetch_ssl_read(SSL *ssl, char *buf, size_t len)
+fetch_ssl_read(SSL *ssl, void *buf, size_t len)
{
ssize_t rlen;
int ssl_err;
@@ -1267,43 +1263,57 @@
rlen = SSL_read(ssl, buf, len);
if (rlen < 0) {
ssl_err = SSL_get_error(ssl, rlen);
- if (ssl_err == SSL_ERROR_WANT_READ ||
- ssl_err == SSL_ERROR_WANT_WRITE) {
- return (FETCH_READ_WAIT);
- } else {
- ERR_print_errors_fp(stderr);
- return (FETCH_READ_ERROR);
+ switch (ssl_err) {
+ case SSL_ERROR_ZERO_RETURN:
+ return (0);
+ case SSL_ERROR_WANT_READ:
+ errno = EAGAIN;
+ return (-1);
+ case SSL_ERROR_SYSCALL:
+ return (-1);
+ default:
+ errno = EPROTO;
+ return (-1);
}
}
return (rlen);
}
-#endif
static ssize_t
-fetch_socket_read(int sd, char *buf, size_t len)
+fetch_ssl_write(SSL *ssl, void *buf, size_t len)
{
- ssize_t rlen;
+ ssize_t wlen;
+ int ssl_err;
- rlen = read(sd, buf, len);
- if (rlen < 0) {
- if (errno == EAGAIN || (errno == EINTR && fetchRestartCalls)) {
- return (FETCH_READ_WAIT);
- } else {
- return (FETCH_READ_ERROR);
+ wlen = SSL_write(ssl, buf, len);
+ if (wlen < 0) {
+ ssl_err = SSL_get_error(ssl, wlen);
+ switch (ssl_err) {
+ case SSL_ERROR_ZERO_RETURN:
+ return (0);
+ case SSL_ERROR_WANT_WRITE:
+ errno = EAGAIN;
+ return (-1);
+ case SSL_ERROR_SYSCALL:
+ return (-1);
+ default:
+ errno = EPROTO;
+ return (-1);
}
}
- return (rlen);
+ return (wlen);
}
+#endif
/*
- * Read a character from a connection w/ timeout
+ * Read from a connection w/ timeout
*/
ssize_t
-fetch_read(conn_t *conn, char *buf, size_t len)
+fetch_read(conn_t *conn, void *buf, size_t len)
{
struct timeval now, timeout, delta;
struct pollfd pfd;
- ssize_t rlen;
+ ssize_t rlen, total;
int deltams;
if (fetchTimeout > 0) {
@@ -1312,10 +1322,10 @@
}
deltams = INFTIM;
- memset(&pfd, 0, sizeof pfd);
pfd.fd = conn->sd;
- pfd.events = POLLIN | POLLERR;
+ pfd.events = POLLIN;
+ total = 0;
for (;;) {
/*
* The socket is non-blocking. Instead of the canonical
@@ -1323,8 +1333,8 @@
*
* 1) call read() or SSL_read().
* 2) if we received some data, return it.
- * 3) if an error occurred, return -1.
- * 4) if read() or SSL_read() signaled EOF, return.
+ * 3) if read() or SSL_read() signaled EOF, return.
+ * 4) if an error occurred, return -1.
* 5) if we did not receive any data but we're not at EOF,
* call poll().
*
@@ -1341,14 +1351,26 @@
rlen = fetch_ssl_read(conn->ssl, buf, len);
else
#endif
- rlen = fetch_socket_read(conn->sd, buf, len);
- if (rlen >= 0) {
+ rlen = read(conn->sd, buf, len);
+ if (rlen > 0) {
+ /* something was read */
+ total += rlen;
+ len -= rlen;
+ if (len == 0)
+ break;
+ /* a partial read is success */
+ break;
+ } else if (rlen == 0) {
+ /* connection closed */
break;
- } else if (rlen == FETCH_READ_ERROR) {
+ } else if (errno != EAGAIN) {
+ /* error */
+ if (errno == EINTR && fetchRestartCalls)
+ continue;
fetch_syserr();
- return (-1);
+ break;
}
- // assert(rlen == FETCH_READ_WAIT);
+ /* check what's left of our timeout */
if (fetchTimeout > 0) {
gettimeofday(&now, NULL);
if (!timercmp(&timeout, &now, >)) {
@@ -1360,16 +1382,19 @@
deltams = delta.tv_sec * 1000 +
delta.tv_usec / 1000;
}
- errno = 0;
- pfd.revents = 0;
+ /* wait for the socket to become readable */
if (poll(&pfd, 1, deltams) < 0) {
+ if (errno == EAGAIN)
+ continue;
if (errno == EINTR && fetchRestartCalls)
continue;
- fetch_syserr();
- return (-1);
+ break;
}
}
- return (rlen);
+ /* a partial read is success */
+ if (rlen < 0 && total == 0)
+ return (-1);
+ return (total);
}
@@ -1426,7 +1451,7 @@
* Write to a connection w/ timeout
*/
ssize_t
-fetch_write(conn_t *conn, const char *buf, size_t len)
+fetch_write(conn_t *conn, const void *buf, size_t len)
{
struct iovec iov;
@@ -1447,17 +1472,65 @@
ssize_t wlen, total;
int deltams;
- memset(&pfd, 0, sizeof pfd);
- if (fetchTimeout) {
- pfd.fd = conn->sd;
- pfd.events = POLLOUT | POLLERR;
+ if (fetchTimeout > 0) {
gettimeofday(&timeout, NULL);
timeout.tv_sec += fetchTimeout;
}
+ deltams = INFTIM;
+ pfd.fd = conn->sd;
+ pfd.events = POLLOUT;
+
total = 0;
- while (iovcnt > 0) {
- while (fetchTimeout && pfd.revents == 0) {
+ for (;;) {
+ /*
+ * The socket is non-blocking. Instead of the canonical
+ * poll() -> write(), we do the following:
+ *
+ * 1) call write() or SSL_write().
+ * 2) if we wrote everything, return success.
+ * 3) if write() or SSL_write() signaled EOF before we
+ * wrote everything, return -1.
+ * 4) if an error occurred, return -1.
+ * 5) if we did not write everything but we're not at EOF,
+ * call poll().
+ */
+#ifdef WITH_SSL
+ if (conn->ssl != NULL) {
+ wlen = fetch_ssl_write(conn->ssl,
+ iov->iov_base, iov->iov_len);
+ } else
+#endif
+ wlen = writev(conn->sd, iov, iovcnt);
+ if (wlen > 0) {
+ /* something was written */
+ total += wlen;
+ /* skip iovs which were completely written */
+ while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
+ wlen -= iov->iov_len;
+ iov++;
+ iovcnt--;
+ }
+ /* are we done? */
+ if (iovcnt == 0)
+ break;
+ /* skip written portion of current iov */
+ iov->iov_len -= wlen;
+ iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
+ /* a partial write is incomplete */
+ continue;
+ } else if (wlen == 0) {
+ /* connection closed */
+ break;
+ } else if (errno != EAGAIN) {
+ /* error */
+ if (errno == EINTR && fetchRestartCalls)
+ continue;
+ fetch_syserr();
+ break;
+ }
+ /* check what's left of our timeout */
+ if (fetchTimeout > 0) {
gettimeofday(&now, NULL);
if (!timercmp(&timeout, &now, >)) {
errno = ETIMEDOUT;
@@ -1467,48 +1540,19 @@
timersub(&timeout, &now, &delta);
deltams = delta.tv_sec * 1000 +
delta.tv_usec / 1000;
- errno = 0;
- pfd.revents = 0;
- if (poll(&pfd, 1, deltams) < 0) {
- /* POSIX compliance */
- if (errno == EAGAIN)
- continue;
- if (errno == EINTR && fetchRestartCalls)
- continue;
- return (-1);
- }
}
- errno = 0;
-#ifdef WITH_SSL
- if (conn->ssl != NULL)
- wlen = SSL_write(conn->ssl,
- iov->iov_base, iov->iov_len);
- else
-#endif
- wlen = writev(conn->sd, iov, iovcnt);
- if (wlen == 0) {
- /* we consider a short write a failure */
- /* XXX perhaps we shouldn't in the SSL case */
- errno = EPIPE;
- fetch_syserr();
- return (-1);
- }
- if (wlen < 0) {
+ /* wait for the socket to become writeable */
+ if (poll(&pfd, 1, deltams) < 0) {
+ if (errno == EAGAIN)
+ continue;
if (errno == EINTR && fetchRestartCalls)
continue;
return (-1);
}
- total += wlen;
- while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
- wlen -= iov->iov_len;
- iov++;
- iovcnt--;
- }
- if (iovcnt > 0) {
- iov->iov_len -= wlen;
- iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
- }
}
+ /* a partial write is failure */
+ if (iovcnt > 0)
+ return (-1);
return (total);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jul 5, 8:46 PM (8 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34506209
Default Alt Text
D57906.diff (7 KB)
Attached To
Mode
D57906: libfetch: Overhaul socket read / write
Attached
Detach File
Event Timeline
Log In to Comment