static ssize_t mailstream_low_ssl_read(mailstream_low * s, void * buf, size_t count) { struct mailstream_ssl_data * ssl_data; int r; ssl_data = (struct mailstream_ssl_data *) s->data; if (mailstream_cancel_cancelled(ssl_data->cancel)) return -1; while (1) { int ssl_r; r = SSL_read(ssl_data->ssl_conn, buf, count); if (r > 0) return r; ssl_r = SSL_get_error(ssl_data->ssl_conn, r); switch (ssl_r) { case SSL_ERROR_NONE: return r; case SSL_ERROR_ZERO_RETURN: return r; case SSL_ERROR_WANT_READ: r = wait_read(s); if (r < 0) return r; break; default: return -1; } } }
static ssize_t mailstream_low_ssl_read(mailstream_low * s, void * buf, size_t count) { struct mailstream_ssl_data * ssl_data; int r; ssl_data = (struct mailstream_ssl_data *) s->data; if (mailstream_cancel_cancelled(ssl_data->cancel)) return -1; while (1) { r = gnutls_record_recv(ssl_data->session, buf, count); if (r > 0) return r; switch (r) { case 0: /* closed connection */ return -1; case GNUTLS_E_REHANDSHAKE: do { r = gnutls_handshake(ssl_data->session); } while (r == GNUTLS_E_AGAIN || r == GNUTLS_E_INTERRUPTED); break; /* re-receive */ case GNUTLS_E_AGAIN: case GNUTLS_E_INTERRUPTED: r = wait_read(s); if (r < 0) return r; break; default: return -1; } } }
static int wait_write(mailstream_low * s) { fd_set fds_read; fd_set fds_write; struct timeval timeout; int r; int fd; struct mailstream_ssl_data * ssl_data; int max_fd; int cancelled; int write_enabled; #ifdef WIN32 HANDLE event; #endif ssl_data = (struct mailstream_ssl_data *) s->data; if (mailstream_cancel_cancelled(ssl_data->cancel)) return -1; if (s->timeout == 0) { timeout = mailstream_network_delay; } else { timeout.tv_sec = s->timeout; timeout.tv_usec = 0; } FD_ZERO(&fds_read); fd = mailstream_cancel_get_fd(ssl_data->cancel); FD_SET(fd, &fds_read); FD_ZERO(&fds_write); #ifdef WIN32 event = CreateEvent(NULL, TRUE, FALSE, NULL); WSAEventSelect(ssl_data->fd, event, FD_WRITE | FD_CLOSE); FD_SET(event, &fds_read); r = WaitForMultipleObjects(fds_read.fd_count, fds_read.fd_array, FALSE, timeout.tv_sec * 1000 + timeout.tv_usec / 1000); if (r < 0) { WSAEventSelect(ssl_data->fd, event, 0); CloseHandle(event); return -1; } cancelled = (fds_read.fd_array[r - WAIT_OBJECT_0] == fd) /* SEB 20070709 */; write_enabled = (fds_read.fd_array[r - WAIT_OBJECT_0] == event); WSAEventSelect(ssl_data->fd, event, 0); CloseHandle(event); #else FD_SET(ssl_data->fd, &fds_write); max_fd = ssl_data->fd; if (fd > max_fd) max_fd = fd; r = select(max_fd + 1, &fds_read, &fds_write, NULL, &timeout); if (r <= 0) return -1; cancelled = FD_ISSET(fd, &fds_read); write_enabled = FD_ISSET(ssl_data->fd, &fds_write); #endif if (cancelled) { /* cancelled */ mailstream_cancel_ack(ssl_data->cancel); return -1; } if (!write_enabled) return 0; return 1; }
static int wait_write(mailstream_low * s) { struct timeval timeout; int r; int cancellation_fd; struct mailstream_ssl_data * ssl_data; int cancelled; int write_enabled; #if defined(WIN32) fd_set fds_read; fd_set fds_write; HANDLE event; #elif USE_POLL struct pollfd pfd[2]; #else fd_set fds_read; fd_set fds_write; int max_fd; #endif ssl_data = (struct mailstream_ssl_data *) s->data; if (mailstream_cancel_cancelled(ssl_data->cancel)) return -1; if (s->timeout == 0) { timeout = mailstream_network_delay; } else { timeout.tv_sec = s->timeout; timeout.tv_usec = 0; } cancellation_fd = mailstream_cancel_get_fd(ssl_data->cancel); #if defined(WIN32) FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_SET(cancellation_fd, &fds_read); event = CreateEvent(NULL, TRUE, FALSE, NULL); WSAEventSelect(ssl_data->fd, event, FD_WRITE | FD_CLOSE); FD_SET(event, &fds_read); r = WaitForMultipleObjects(fds_read.fd_count, fds_read.fd_array, FALSE, timeout.tv_sec * 1000 + timeout.tv_usec / 1000); if (r < 0) { WSAEventSelect(ssl_data->fd, event, 0); CloseHandle(event); return -1; } cancelled = (fds_read.fd_array[r - WAIT_OBJECT_0] == cancellation_fd) /* SEB 20070709 */; write_enabled = (fds_read.fd_array[r - WAIT_OBJECT_0] == event); WSAEventSelect(ssl_data->fd, event, 0); CloseHandle(event); #elif USE_POLL pfd[0].fd = ssl_data->fd; pfd[0].events = POLLOUT; pfd[0].revents = 0; pfd[1].fd = cancellation_fd; pfd[1].events = POLLIN; pfd[1].revents = 0; r = poll(&pfd[0], 2, timeout.tv_sec * 1000 + timeout.tv_usec / 1000); if (r <= 0) return -1; cancelled = pfd[1].revents & POLLIN; write_enabled = pfd[0].revents & POLLOUT; #else FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_SET(cancellation_fd, &fds_read); FD_SET(ssl_data->fd, &fds_write); max_fd = cancellation_fd > ssl_data->fd ? cancellation_fd : ssl_data->fd; r = select(max_fd + 1, &fds_read, &fds_write, NULL, &timeout); if (r <= 0) return -1; cancelled = FD_ISSET(cancellation_fd, &fds_read); write_enabled = FD_ISSET(ssl_data->fd, &fds_write); #endif if (cancelled) { /* cancelled */ mailstream_cancel_ack(ssl_data->cancel); return -1; } if (!write_enabled) return 0; return 1; }
static ssize_t mailstream_low_socket_read(mailstream_low * s, void * buf, size_t count) { struct mailstream_socket_data * socket_data; socket_data = (struct mailstream_socket_data *) s->data; if (mailstream_cancel_cancelled(socket_data->cancel)) return -1; /* timeout */ { fd_set fds_read; struct timeval timeout; int r; int fd; int cancelled; int got_data; #ifdef WIN32 HANDLE event; #else int max_fd; #endif if (s->timeout == 0) { timeout = mailstream_network_delay; } else { timeout.tv_sec = s->timeout; timeout.tv_usec = 0; } FD_ZERO(&fds_read); fd = mailstream_cancel_get_fd(socket_data->cancel); FD_SET(fd, &fds_read); #ifdef WIN32 event = CreateEvent(NULL, TRUE, FALSE, NULL); WSAEventSelect(socket_data->fd, event, FD_READ | FD_CLOSE); FD_SET(event, &fds_read); r = WaitForMultipleObjects(fds_read.fd_count, fds_read.fd_array, FALSE, timeout.tv_sec * 1000 + timeout.tv_usec / 1000); if (WAIT_TIMEOUT == r) { WSAEventSelect(socket_data->fd, event, 0); CloseHandle(event); return -1; } cancelled = (fds_read.fd_array[r - WAIT_OBJECT_0] == fd); got_data = (fds_read.fd_array[r - WAIT_OBJECT_0] == event); WSAEventSelect(socket_data->fd, event, 0); CloseHandle(event); #else FD_SET(socket_data->fd, &fds_read); max_fd = socket_data->fd; if (fd > max_fd) max_fd = fd; r = select(max_fd + 1, &fds_read, NULL,/* &fds_excp*/ NULL, &timeout); if (r <= 0) return -1; cancelled = FD_ISSET(fd, &fds_read); got_data = FD_ISSET(socket_data->fd, &fds_read); #endif if (cancelled) { /* cancelled */ mailstream_cancel_ack(socket_data->cancel); return -1; } if (!got_data) return 0; } if (socket_data->use_read) { return read(socket_data->fd, buf, count); } else { return recv(socket_data->fd, buf, count, 0); } }