ssize_t fetch_ssl_read_wrapper(SSL *ssl, char *buf, size_t buflen) { #ifdef NO_SANDBOX return (fetch_ssl_read(ssl, buf, buflen)); #else return (fetch_ssl_read_insandbox(buf, buflen)); #endif }
/* Called in sandbox and wraps the actual fetch_ssl_read */ static void sandbox_fetch_ssl_read(struct sandbox_cb *scb, uint32_t opno, uint32_t seqno, char *buffer, size_t len) { struct ssl_req req; struct ssl_rep *rep; struct iovec iov; size_t rep_msg_size; ssize_t rlen; if (len != sizeof(req)) { err(-1, "sandbox_fetch_ssl_read: received msg len %zu", len); return; } /* Demangle data */ memmove(&req, buffer, sizeof(req)); /* Type should be set correctly */ if (req.type != SSL_READ) return; rep_msg_size = sizeof(*rep); if(req.rargs.len) rep_msg_size += req.rargs.len; rep = malloc(rep_msg_size); if(!rep) { DPRINTF("[XXX] malloc() failed"); exit(-1); } rep->type = SSL_READ; rlen = fetch_ssl_read(sconn.ssl, rep->rbuf, req.rargs.len); rep->retval = rep->rbuf_len = rlen; iov.iov_base = rep; iov.iov_len = rep_msg_size; if (sandbox_sendrpc(scb, opno, seqno, &iov, 1) < 0) err(-1, "sandbox_sendrpc"); /* Release resources */ free(rep); }
/* * Read a character from a connection w/ timeout */ ssize_t fetch_read(conn_t *conn, char *buf, size_t len) { struct timeval now, timeout, delta; fd_set readfds; ssize_t rlen, total; int r; char *start; if (fetchTimeout) { FD_ZERO(&readfds); gettimeofday(&timeout, NULL); timeout.tv_sec += fetchTimeout; } total = 0; start = buf; if (conn->cache.len > 0) { /* * The last invocation of fetch_read was interrupted by a * signal after some data had been read from the socket. Copy * the cached data into the supplied buffer before trying to * read from the socket again. */ total = (conn->cache.len < len) ? conn->cache.len : len; memcpy(buf, conn->cache.buf, total); conn->cache.len -= total; conn->cache.pos += total; len -= total; buf += total; } while (len > 0) { /* * The socket is non-blocking. Instead of the canonical * select() -> read(), we do the following: * * 1) call read() or SSL_read(). * 2) if an error occurred, return -1. * 3) if we received data but we still expect more, * update our counters and loop. * 4) if read() or SSL_read() signaled EOF, return. * 5) if we did not receive any data but we're not at EOF, * call select(). * * In the SSL case, this is necessary because if we * receive a close notification, we have to call * SSL_read() one additional time after we've read * everything we received. * * In the non-SSL case, it may improve performance (very * slightly) when reading small amounts of data. */ #ifdef WITH_SSL if (conn->ssl != NULL) rlen = fetch_ssl_read(conn->ssl, buf, len); else #endif rlen = fetch_socket_read(conn->sd, buf, len); if (rlen == 0) { break; } else if (rlen > 0) { len -= rlen; buf += rlen; total += rlen; continue; } else if (rlen == FETCH_READ_ERROR) { if (errno == EINTR) fetch_cache_data(conn, start, total); return (-1); } // assert(rlen == FETCH_READ_WAIT); while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) { FD_SET(conn->sd, &readfds); gettimeofday(&now, NULL); delta.tv_sec = timeout.tv_sec - now.tv_sec; delta.tv_usec = timeout.tv_usec - now.tv_usec; if (delta.tv_usec < 0) { delta.tv_usec += 1000000; delta.tv_sec--; } if (delta.tv_sec < 0) { errno = ETIMEDOUT; fetch_syserr(); return (-1); } errno = 0; r = select(conn->sd + 1, &readfds, NULL, NULL, &delta); if (r == -1) { if (errno == EINTR) { if (fetchRestartCalls) continue; /* Save anything that was read. */ fetch_cache_data(conn, start, total); } fetch_syserr(); return (-1); } } } return (total); }