/* Return the number of bytes read. Return -1 on errors and EOF. */ PUBLIC ssize sslRead(Webs *wp, void *buf, ssize len) { Nano *np; WebsSocket *sp; sbyte4 nbytes, count; int rc; np = (Nano*) wp->ssl; assert(np); if (!np->connected && (rc = nanoHandshake(wp)) <= 0) { return rc; } while (1) { /* This will do the actual blocking I/O */ rc = SSL_recv(np->handle, buf, (sbyte4) len, &nbytes, 0); logmsg(5, "NanoSSL: ssl_read %d", rc); if (rc < 0) { if (rc != ERR_TCP_READ_ERROR) { sp = socketPtr(wp->sid); sp->flags |= SOCKET_EOF; } return -1; } break; } SSL_recvPending(np->handle, &count); if (count > 0) { socketReservice(wp->wid); } return nbytes; }
PUBLIC ssize sslRead(Webs *wp, void *buf, ssize len) { WebsSocket *sp; char ebuf[BIT_GOAHEAD_LIMIT_STRING]; ulong serror; int rc, error, retries, i; if (wp->ssl == 0 || len <= 0) { assert(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) { sleep(0); 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) { /* SSL_ERROR_SSL */ 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) { sp->flags |= SOCKET_BUFFERED_READ; socketReservice(wp->sid); } return rc; }
PUBLIC void socketHiddenData(WebsSocket *sp, ssize len, int dir) { if (len > 0) { sp->flags |= (dir == SOCKET_READABLE) ? SOCKET_BUFFERED_READ : SOCKET_BUFFERED_WRITE; if (sp->handler) { socketReservice(sp->sid); } } else { sp->flags &= ~((dir == SOCKET_READABLE) ? SOCKET_BUFFERED_READ : SOCKET_BUFFERED_WRITE); } }
/* Return number of bytes read. Return -1 on errors and EOF. */ PUBLIC ssize sslRead(Webs *wp, void *buf, ssize len) { Ms *ms; ssize bytes; if (len <= 0) { return -1; } bytes = innerRead(wp, buf, len); ms = (Ms*) wp->ssl; if (ms->more) { wp->flags |= SOCKET_BUFFERED_READ; socketReservice(wp->sid); } return bytes; }
/* Write data. Return the number of bytes written or -1 on errors. */ PUBLIC ssize sslWrite(Webs *wp, void *buf, ssize len) { Nano *np; WebsSocket *sp; ssize totalWritten; int rc, count, sent; np = (Nano*) wp->ssl; if (len <= 0) { assert(0); return -1; } if (!np->connected && (rc = nanoHandshake(wp)) <= 0) { return rc; } totalWritten = 0; do { rc = sent = SSL_send(np->handle, (sbyte*) buf, (int) len); logmsg(7, "NanoSSL: written %d, requested len %d", sent, len); if (rc <= 0) { logmsg(0, "NanoSSL: SSL_send failed sent %d", rc); sp = socketPtr(wp->sid); sp->flags |= SOCKET_EOF; return -1; } totalWritten += sent; buf = (void*) ((char*) buf + sent); len -= sent; logmsg(7, "NanoSSL: write: len %d, written %d, total %d", len, sent, totalWritten); } while (len > 0); SSL_sendPending(np->handle, &count); if (count > 0) { socketReservice(wp->sid); } return totalWritten; }