static void client_established_read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { int n; server_ctx *ctx = (server_ctx *)stream->data; if (nread < 0) { // EOF if (buf.len) // If buf is set, we need to free it free(buf.base); LOGCONN(&ctx->client, "Client %s EOF, closing"); HANDLE_CLOSE((uv_handle_t*)stream, client_established_close_cb); // Then close the connection return; } else if (!nread) { free(buf.base); return; } shadow_decrypt((uint8_t *)buf.base, decrypt_table, nread); uv_write_t *req = (uv_write_t *)malloc(sizeof(uv_write_t)); if (!req) { HANDLE_CLOSE((uv_handle_t*)stream, client_established_close_cb); FATAL("malloc() failed!"); } req->data = buf.base; buf.len = nread; n = uv_write(req, (uv_stream_t *)(void *)&ctx->remote, &buf, 1, after_write_cb); if (n) { LOGE("Write to remote failed!"); free(req); HANDLE_CLOSE((uv_handle_t*)stream, client_established_close_cb); return; } // LOGI("Writed to remote"); }
static void connect_to_remote_cb(uv_connect_t* req, int status) { server_ctx *ctx = (server_ctx *)req->data; if (status) { if (uv_last_error(req->handle->loop).code != UV_ECANCELED) { SHOW_UV_ERROR(ctx->client.loop); uv_close((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); free(ctx->handshake_buffer); free(req); } return; } free(req); LOGCONN(&ctx->remote, "Connected to %s"); uv_buf_t buf; buf.base = (char *)ctx->handshake_buffer; buf.len = HANDSHAKE_BUFFER_SIZE; if (!ctx->buffer_len) { free(ctx->handshake_buffer); } else { uv_write_t *wreq = (uv_write_t *)malloc(sizeof(uv_write_t)); if (!wreq) { uv_close((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); FATAL("malloc() failed!"); } wreq->data = buf.base; buf.len = ctx->buffer_len; int n = uv_write(wreq, (uv_stream_t *)(void *)&ctx->remote, &buf, 1, after_write_cb); if (n) { LOGE("Write to remote failed!"); free(wreq); uv_close((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); return; } } ctx->handshake_buffer = NULL; ctx->buffer_len = 0; int n = uv_read_start((uv_stream_t *)(void *)&ctx->client, established_alloc_cb, client_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); uv_close((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); return; } n = uv_read_start((uv_stream_t *)(void *)&ctx->remote, established_alloc_cb, remote_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); uv_close((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); return; } }
static void connect_to_remote_cb(uv_connect_t* req, int status) { server_ctx *ctx = (server_ctx *)req->data; if (status) { if (uv_last_error(req->handle->loop).code != UV_ECANCELED) { SHOW_UV_ERROR(ctx->client.loop); HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); free(ctx->handshake_buffer); free(req); } return; } free(req); LOGCONN(&ctx->remote, "Connected to %s"); uv_buf_t buf; buf.base = (char *)ctx->handshake_buffer; buf.len = HANDSHAKE_BUFFER_SIZE; shadow_encrypt((uint8_t *)buf.base, encrypt_table, ctx->buffer_len); client_established_read_cb((uv_stream_t *)(void *)&ctx->client, ctx->buffer_len, buf); // Deal with ramaining data, only once ctx->handshake_buffer = NULL; ctx->buffer_len = 0; if (uv_is_closing((uv_handle_t *)(void *)&ctx->remote) || uv_is_closing((uv_handle_t *)(void *)&ctx->client)) { LOGE("Connection failed, remote or client already closed"); return; } int n = uv_read_start((uv_stream_t *)(void *)&ctx->client, established_alloc_cb, client_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); return; } n = uv_read_start((uv_stream_t *)(void *)&ctx->remote, established_alloc_cb, remote_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); return; } }
static void connect_cb(uv_stream_t* listener, int status) { int n; if (status) { SHOW_UV_ERROR(listener->loop); return; } server_ctx *ctx = calloc(1, sizeof(server_ctx)); ctx->handshake_buffer = calloc(1, HANDSHAKE_BUFFER_SIZE); if (!ctx || !ctx->handshake_buffer) FATAL("malloc() failed!"); ctx->client.data = ctx; ctx->remote.data = ctx; make_encryptor(&crypto, &ctx->encoder, 0, NULL); n = uv_tcp_init(listener->loop, &ctx->client); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); n = uv_accept(listener, (uv_stream_t *)(void *)&ctx->client); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); n = uv_tcp_nodelay(&ctx->client, 1); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); #ifdef KEEPALIVE_TIMEOUT n = uv_tcp_keepalive(&ctx->client, 1, KEEPALIVE_TIMEOUT); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); #endif /* KEEPALIVE_TIMEOUT */ n = uv_read_start((uv_stream_t *)(void *)&ctx->client, client_handshake_alloc_cb, client_handshake_read_cb); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); LOGCONN(&ctx->client, "Accepted connection from %s"); }
static void remote_established_read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { int n; server_ctx *ctx = (server_ctx *)stream->data; if (nread < 0) { // EOF if (buf.len) // If buf is set, we need to free it free(buf.base); LOGCONN(&ctx->remote, "Remote %s EOF, closing"); HANDLE_CLOSE((uv_handle_t*)stream, remote_established_close_cb); // Then close the connection return; } else if (!nread) { free(buf.base); return; } shadow_encrypt((uint8_t *)buf.base, &ctx->encoder, nread); uv_write_t *req = (uv_write_t *)malloc(sizeof(uv_write_t)); if (!req) { HANDLE_CLOSE((uv_handle_t*)stream, remote_established_close_cb); FATAL("malloc() failed!"); } req->data = buf.base; buf.len = nread; n = uv_write(req, (uv_stream_t *)(void *)&ctx->client, &buf, 1, after_write_cb); if (n) { LOGE("Write to client failed!"); free(req); free(buf.base); HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); return; } if (ctx->buffer_len == MAX_PENDING_PER_CONN - 1) { // buffer_len used as pending write request counter uv_read_stop(stream); } ctx->buffer_len++; }