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); }
void bud_client_read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { int r; bud_client_t* client; bud_client_side_t* side; bud_client_side_t* opposite; bud_client_error_t cerr; client = stream->data; side = bud_client_side_by_tcp(client, (uv_tcp_t*) stream); /* Commit data if there was no error */ r = 0; if (nread >= 0) r = ringbuffer_write_append(&side->input, nread); DBG(side, "after read_cb() => %d", nread); /* Handle EOF */ if (nread == UV_EOF) { side->reading = kBudProgressDone; /* Shutdown opposite side */ opposite = side == &client->frontend ? &client->backend : &client->frontend; cerr = bud_client_shutdown(client, opposite); if (!bud_is_ok(cerr.err)) goto done; } /* Try writing out data anyway */ cerr = bud_client_cycle(client); if (!bud_is_ok(cerr.err)) goto done; if ((r != 0 || nread < 0) && nread != UV_EOF) { if (nread < 0) cerr = bud_client_error(bud_error_num(kBudErrClientReadCb, nread), side); else cerr = bud_client_error(bud_error(kBudErrClientWriteAppend), side); /* Unrecoverable socket error, close */ return bud_client_close(client, cerr); } /* If buffer is full - stop reading */ cerr = bud_client_throttle(client, side, &side->input); done: if (!bud_is_ok(cerr.err) && cerr.err.code != kBudErrClientThrottle) bud_client_close(client, cerr); }
void bud_client_send_cb(uv_write_t* req, int status) { bud_client_t* client; bud_client_error_t cerr; bud_client_side_t* side; bud_client_side_t* opposite; /* Closing, ignore */ if (status == UV_ECANCELED) return; client = req->data; if (req == &client->frontend.write_req) { side = &client->frontend; opposite = &client->backend; } else { side = &client->backend; opposite = &client->frontend; } if (status != 0) { side->write = kBudProgressDone; bud_client_close( client, bud_client_error(bud_error_num(kBudErrClientWriteCb, status), side)); return; } /* Consume written data */ DBG(side, "write_cb => %d", side->write_size); ringbuffer_read_skip(&side->output, side->write_size); /* Skip data in xforward parser */ if (side == &client->backend) bud_client_xforward_skip(client, side->write_size); side->write = kBudProgressNone; side->write_size = 0; if (opposite->reading == kBudProgressNone) { if ((client->retry == kBudProgressRunning || client->connect == kBudProgressRunning) && opposite == &client->backend) { /* Set reading mark on backend to resume it after reconnecting */ opposite->reading = kBudProgressRunning; } else if (opposite->close != kBudProgressDone && side->close != kBudProgressDone && side->shutdown != kBudProgressDone && !ringbuffer_is_full(&side->output)) { DBG_LN(opposite, "read_start"); cerr = bud_client_read_start(client, opposite); if (!bud_is_ok(cerr.err)) return bud_client_close(client, cerr); opposite->reading = kBudProgressRunning; } } /* Cycle again */ cerr = bud_client_cycle(client); if (!bud_is_ok(cerr.err)) return bud_client_close(client, cerr); if (side->close == kBudProgressRunning || side->shutdown == kBudProgressRunning) { if (!ringbuffer_is_empty(&side->output)) return; /* No new data, destroy or shutdown */ if (side->shutdown == kBudProgressRunning) { cerr = bud_client_shutdown(client, side); if (!bud_is_ok(cerr.err)) bud_client_close(client, cerr); return; } bud_client_close(client, bud_client_ok(side)); } }
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); }