/* Return the number of bytes read. Return -1 on errors and EOF. Distinguish EOF via mprIsSocketEof. If non-blocking, may return zero if no data or still handshaking. */ PUBLIC ssize sslRead(Webs *wp, void *buf, ssize len) { WebsSocket *sp; char ebuf[ME_GOAHEAD_LIMIT_STRING]; ulong serror; int rc, error, retries, i; if (wp->ssl == 0 || len <= 0) { return -1; } /* Limit retries on WANT_READ. If non-blocking and no data, then this can spin forever. */ sp = socketPtr(wp->sid); retries = 5; for (i = 0; i < retries; i++) { rc = SSL_read(wp->ssl, buf, (int) len); if (rc < 0) { error = SSL_get_error(wp->ssl, rc); if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_CONNECT || error == SSL_ERROR_WANT_ACCEPT) { continue; } serror = ERR_get_error(); ERR_error_string_n(serror, ebuf, sizeof(ebuf) - 1); trace(5, "SSL_read %s", ebuf); } break; } if (rc <= 0) { error = SSL_get_error(wp->ssl, rc); if (error == SSL_ERROR_WANT_READ) { rc = 0; } else if (error == SSL_ERROR_WANT_WRITE) { rc = 0; } else if (error == SSL_ERROR_ZERO_RETURN) { sp->flags |= SOCKET_EOF; rc = -1; } else if (error == SSL_ERROR_SYSCALL) { sp->flags |= SOCKET_EOF; rc = -1; } else if (error != SSL_ERROR_ZERO_RETURN) { serror = ERR_get_error(); ERR_error_string_n(serror, ebuf, sizeof(ebuf) - 1); trace(4, "OpenSSL: connection with protocol error: %s", ebuf); rc = -1; sp->flags |= SOCKET_EOF; } } else if (SSL_pending(wp->ssl) > 0) { socketHiddenData(sp, SSL_pending(wp->ssl), SOCKET_READABLE); } return rc; }
/* Return number of bytes read. Return -1 on errors and EOF. */ PUBLIC ssize sslRead(Webs *wp, void *buf, ssize len) { Ms *ms; WebsSocket *sp; ssize bytes; if (len <= 0) { return -1; } bytes = innerRead(wp, buf, len); ms = (Ms*) wp->ssl; if (ms->more) { if ((sp = socketPtr(wp->sid)) != 0) { socketHiddenData(sp, ms->more, SOCKET_READABLE); } } return bytes; }
PUBLIC ssize sslRead(Webs *wp, void *buf, ssize len) { WebsSocket *sp; EstSocket *est; int rc; if (!wp->ssl) { assert(0); return -1; } est = (EstSocket*) wp->ssl; assert(est); sp = socketPtr(wp->sid); if (est->ctx.state != SSL_HANDSHAKE_OVER) { if ((rc = estHandshake(wp)) <= 0) { return rc; } } while (1) { rc = ssl_read(&est->ctx, buf, (int) len); trace(5, "EST: ssl_read %d", rc); if (rc < 0) { if (rc == EST_ERR_NET_TRY_AGAIN) { continue; } else if (rc == EST_ERR_SSL_PEER_CLOSE_NOTIFY) { trace(5, "EST: connection was closed gracefully"); sp->flags |= SOCKET_EOF; return -1; } else if (rc == EST_ERR_NET_CONN_RESET) { trace(5, "EST: connection reset"); sp->flags |= SOCKET_EOF; return -1; } else { trace(4, "EST: read error -0x%", -rc); sp->flags |= SOCKET_EOF; return -1; } } break; } socketHiddenData(sp, est->ctx.in_left, SOCKET_READABLE); return rc; }
PUBLIC ssize sslWrite(Webs *wp, void *buf, ssize len) { EstSocket *est; ssize totalWritten; int rc; if (wp->ssl == 0 || len <= 0) { assert(0); return -1; } est = (EstSocket*) wp->ssl; if (est->ctx.state != SSL_HANDSHAKE_OVER) { if ((rc = estHandshake(wp)) <= 0) { return rc; } } totalWritten = 0; do { rc = ssl_write(&est->ctx, (uchar*) buf, (int) len); trace(7, "EST: written %d, requested len %d", rc, len); if (rc <= 0) { if (rc == EST_ERR_NET_TRY_AGAIN) { break; } if (rc == EST_ERR_NET_CONN_RESET) { trace(4, "ssl_write peer closed"); return -1; } else { trace(4, "ssl_write failed rc %d", rc); return -1; } } else { totalWritten += rc; buf = (void*) ((char*) buf + rc); len -= rc; trace(7, "EST: write: len %d, written %d, total %d", len, rc, totalWritten); } } while (len > 0); socketHiddenData(socketPtr(wp->sid), est->ctx.in_left, SOCKET_WRITABLE); return totalWritten; }