Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F169520522
D57906.id180817.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D57906.id180817.diff
View Options
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)
{
struct timeval now, timeout, delta;
struct pollfd pfd;
- ssize_t rlen;
+ ssize_t rlen, total;
int deltams;
if (fetchTimeout > 0) {
@@ -1314,8 +1324,9 @@
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 +1334,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 +1352,24 @@
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 */
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 +1381,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);
}
@@ -1447,17 +1471,64 @@
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;
+ memset(&pfd, 0, sizeof pfd);
+ 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 */
+ fetch_syserr();
+ break;
+ }
+ /* check what's left of our timeout */
+ if (fetchTimeout > 0) {
gettimeofday(&now, NULL);
if (!timercmp(&timeout, &now, >)) {
errno = ETIMEDOUT;
@@ -1467,48 +1538,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
Wed, Sep 2, 7:28 PM (7 m, 59 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34436189
Default Alt Text
D57906.id180817.diff (6 KB)
Attached To
Mode
D57906: libfetch: Overhaul socket read / write
Attached
Detach File
Event Timeline
Log In to Comment