size_t socket_read(struct client_ctx *cc, char *buf, size_t len) { if (!cc->ssl) return socket_read_plain(cc, buf, len); char *bufp = buf; char packet[PACKET_SIZE]; size_t packetsize = 0; while ((size_t) (bufp - buf) < len && (packetsize = SSL_read(cc->ssl, packet, PACKET_SIZE)) > 0){ memcpy(bufp, packet, packetsize); bufp += packetsize; } return bufp - buf; }
void ListenerIO_AttemptRecv(listener *l, int available) { /* --> failure --> set 'closed' error on socket, don't die */ struct bus *b = l->bus; int read_from = 0; BUS_LOG(b, 3, LOG_LISTENER, "attempting receive", b->udata); for (int i = 0; i < l->tracked_fds; i++) { if (read_from == available) { break; } struct pollfd *fd = &l->fds[i + INCOMING_MSG_PIPE]; connection_info *ci = l->fd_info[i]; BUS_ASSERT(b, b->udata, ci->fd == fd->fd); BUS_LOG_SNPRINTF(b, 1, LOG_LISTENER, b->udata, 64, "poll: l->fds[%d]->revents: 0x%04x", // NOCOMMIT i + INCOMING_MSG_PIPE, fd->revents); /* If a socket is about to be shut down, we want to get a * complete read from it if possible, because it's likely to be * an UNSOLICITEDSTATUS message with a reason for the hangup. * Only do single reads otherwise, though, otherwise the * listener can end up blocking too long handling consecutive * reads on a busy connection and causing the incoming command * queue to get backed up. */ bool is_closing = fd->events & (POLLERR | POLLNVAL | POLLHUP); if (fd->revents & POLLIN) { // Try to read what we can (possibly before hangup) ssize_t cur_read = 0; size_t to_read = ci->to_read_size; do { BUS_LOG_SNPRINTF(b, 3, LOG_LISTENER, b->udata, 64, "reading %zd bytes from socket (buf is %zd)", ci->to_read_size, l->read_buf_size); BUS_ASSERT(b, b->udata, l->read_buf_size >= to_read); switch (ci->type) { case BUS_SOCKET_PLAIN: cur_read = socket_read_plain(b, l, i, ci); break; case BUS_SOCKET_SSL: cur_read = socket_read_ssl(b, l, i, ci); break; default: BUS_ASSERT(b, b->udata, false); } // -1: socket error // 0: no more to read } while (is_closing && cur_read > 0 && ci->to_read_size > 0); read_from++; } if (fd->revents & (POLLERR | POLLNVAL)) { read_from++; BUS_LOG(b, 2, LOG_LISTENER, "pollfd: socket error (POLLERR | POLLNVAL)", b->udata); set_error_for_socket(l, i, ci->fd, RX_ERROR_POLLERR); } else if (fd->revents & POLLHUP) { read_from++; BUS_LOG(b, 3, LOG_LISTENER, "pollfd: socket error POLLHUP", b->udata); set_error_for_socket(l, i, ci->fd, RX_ERROR_POLLHUP); } } if (l->error_occured) { // only conditionally do this to avoid wasting CPU /* This is done outside of the polling loop, to avoid erroneously repeat-polling * or skipping any individual file descriptors. */ move_errored_active_sockets_to_end(l); l->error_occured = false; } }