bud_client_error_t bud_client_backend_out(bud_client_t* client) { int read; int err; size_t avail; char* out; bud_client_error_t cerr; /* If buffer is full - stop reading */ cerr = bud_client_throttle(client, &client->backend, &client->backend.output); if (cerr.err.code == kBudErrClientThrottle) return bud_client_ok(&client->frontend); else if (!bud_is_ok(cerr.err)) return cerr; do { avail = 0; out = ringbuffer_write_ptr(&client->backend.output, &avail); read = SSL_read(client->ssl, out, avail); DBG(&client->frontend, "SSL_read() => %d", read); if (read > 0) { ringbuffer_write_append(&client->backend.output, read); if (client->selected_backend->xforward && !bud_client_xforward_done(client)) { cerr = bud_client_prepend_xforward(client); if (!bud_is_ok(cerr.err)) return cerr; } cerr = bud_client_send(client, &client->backend); if (!bud_is_ok(cerr.err)) return cerr; } /* info_cb() has closed front-end */ if (client->close != kBudProgressNone) return bud_client_ok(&client->frontend); } while (read > 0); if (read > 0) goto success; err = SSL_get_error(client->ssl, read); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) goto success; /* Close-notify, most likely */ if (err == SSL_ERROR_ZERO_RETURN) return bud_client_shutdown(client, &client->backend); return bud_client_error(bud_error_num(kBudErrClientSSLRead, err), &client->frontend); success: return bud_client_ok(&client->backend); }
bud_client_error_t bud_client_shutdown(bud_client_t* client, bud_client_side_t* side) { int r; bud_client_error_t cerr; /* Ignore if already shutdown or destroyed */ if (side->shutdown || client->close == kBudProgressDone) return bud_client_ok(side); /* Do not shutdown not-connected socket */ if (side == &client->backend && client->connect != kBudProgressDone) return bud_client_ok(side); side->shutdown = kBudProgressNone; /* Try cycling data to figure out if there is still something to send */ cerr = bud_client_cycle(client); if (!bud_is_ok(cerr.err)) return cerr; /* Not empty, send everything first */ if (!ringbuffer_is_empty(&side->output)) { side->shutdown = kBudProgressRunning; return bud_client_ok(side); } DBG_LN(side, "shutdown"); if (side == &client->frontend) { if (SSL_shutdown(client->ssl) != 1) SSL_shutdown(client->ssl); /* Try writing close_notify */ cerr = bud_client_send(client, &client->frontend); if (!bud_is_ok(cerr.err)) goto fatal; } side->shutdown_req.data = client; r = uv_shutdown(&side->shutdown_req, (uv_stream_t*) &side->tcp, bud_client_shutdown_cb); if (r != 0) { cerr = bud_client_error(bud_error_num(kBudErrClientShutdown, r), side); } else { cerr = bud_client_ok(side); side->shutdown = kBudProgressRunning; } fatal: side->shutdown = 1; return cerr; }
bud_client_error_t bud_client_cycle(bud_client_t* client) { bud_client_error_t cerr; /* Parsing, must wait */ if (client->hello_parse != kBudProgressDone) { return bud_client_parse_hello(client); } else if (client->cycle == kBudProgressRunning) { /* Recursive call detected, ask cycle loop to run one more time */ client->recycle++; return bud_client_ok(&client->frontend); } else { client->cycle = kBudProgressRunning; cerr = bud_client_ok(&client->frontend); do { client->recycle = 0; cerr = bud_client_backend_in(client); if (!bud_is_ok(cerr.err) || client->close != kBudProgressNone) break; cerr = bud_client_backend_out(client); if (!bud_is_ok(cerr.err) || client->close != kBudProgressNone) break; cerr = bud_client_send(client, &client->frontend); if (!bud_is_ok(cerr.err) || client->close != kBudProgressNone) break; cerr = bud_client_send(client, &client->backend); if (!bud_is_ok(cerr.err) || client->close != kBudProgressNone) break; if (client->recycle) DBG_LN(&client->frontend, "recycle"); } while (client->recycle); client->cycle = kBudProgressNone; if (!bud_is_ok(cerr.err)) bud_client_close(client, cerr); return cerr; } }
bud_client_error_t bud_client_backend_out(bud_client_t* client) { int read; int err; size_t avail; char* out; bud_client_error_t cerr; /* If buffer is full - stop reading */ cerr = bud_client_throttle(client, &client->backend, &client->backend.output); if (cerr.err.code == kBudErrClientThrottle) return bud_client_ok(&client->frontend); else if (!bud_is_ok(cerr.err)) return cerr; do { avail = 0; int init_trigger; init_trigger = SSL_is_init_finished(client->ssl); out = ringbuffer_write_ptr(&client->backend.output, &avail); read = SSL_read(client->ssl, out, avail); init_trigger ^= SSL_is_init_finished(client->ssl); DBG(&client->frontend, "SSL_read() => %d", read); if (read > 0) ringbuffer_write_append(&client->backend.output, read); /* Send proxyline once the handshake will end */ if (init_trigger != 0) { cerr = bud_client_prepend_proxyline(client); if (!bud_is_ok(cerr.err)) return cerr; } /* If there is any new data - try to append x-forwarded-for */ if (read > 0 && client->selected_backend->xforward && !bud_client_xforward_done(client)) { cerr = bud_client_prepend_xforward(client); if (!bud_is_ok(cerr.err)) return cerr; } /* Either proxyline or incoming data - need to send stuff to the client */ if (init_trigger != 0 || read > 0) { cerr = bud_client_send(client, &client->backend); if (!bud_is_ok(cerr.err)) return cerr; } /* info_cb() has closed front-end */ if (client->close != kBudProgressNone) return bud_client_ok(&client->frontend); } while (read > 0); if (read > 0) goto success; err = SSL_get_error(client->ssl, read); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_X509_LOOKUP) { goto success; } /* Close-notify, most likely */ if (err == SSL_ERROR_ZERO_RETURN) return bud_client_shutdown(client, &client->backend); return bud_client_error(bud_error_num(kBudErrClientSSLRead, err), &client->frontend); success: return bud_client_ok(&client->backend); }