/* * Created by yuuta on 7/23/22. */ #include "log.h" #include "handler.h" #include "config.h" #include "helpers.h" #include "client.h" #include #include #include #include #include #ifdef _WIN32 #include #else #include #endif static uv_loop_t lop; uv_loop_t *loop = &lop; static int current_req = -1; static bool tty = true; static void on_close(uv_handle_t *handle); static ac_connection_parameters_t params = { .sock = NULL, .version = 0, .port = 25575, .host = NULL, .id = NULL, .token = NULL, .on_send = NULL, }; static void cleanup(void) { LOGD("cleanup()"); /* sock must be closed before cleanup(). */ uv_loop_close(loop); ac_free(); uv_tty_reset_mode(); } static void on_stdin_closed(void) { sock_ext(true); } static void on_sock_closed(void) { uv_stop(loop); } static void prompt(void) { if (tty) { fprintf(stderr, "%s@%s > ", params.id, params.host); } } static int on_input(ac_request_t *req) { if (req->type == AC_REQUEST_CMD && ((ac_request_cmd_t *) req)->cmd[0] == '\0') { prompt(); return 0; } current_req = req->id; stdin_stop(); LOGD("Stdin is paused."); /* The socket will close itself upon errors. So do the input stream. */ return sock_request(req); } static int on_sock_ready(void) { prompt(); return h_stdin(on_input, on_stdin_closed); } static int on_recv(ac_obj_t *obj) { bool p = false; if (AC_IS_RESPONSE(obj->type)) { ac_response_t *resp = (ac_response_t *) obj; if (resp->id == current_req) { if (resp->type == AC_RESPONSE_ERROR || resp->type == AC_RESPONSE_CMD_RESULT) { int r = stdin_start(); if (r) { LOGEV("Cannot resume stdin: %s", uv_strerror(r)); } else { LOGD("Stdin is resumed."); p = true; } } } } const int retval = handle_object(obj); if (p) { prompt(); } return retval; } static void on_resolv(int status, const struct addrinfo *ai, void (*on_connected)(bool)) { if (status) { uv_stop(loop); return; } if (h_socket(¶ms, ai, on_connected, on_sock_ready, on_recv, on_sock_closed)) { /* Mark as true to clean up resources and prevent next retry. */ on_connected(true); uv_stop(loop); } } static void on_int(void) { current_req = -1; int r = stdin_start(); if (r && r != UV_EALREADY) { LOGEV("Cannot resume stdin: %s", uv_strerror(r)); } else { printf("Interrupt\n"); prompt(); } } int main(int argc, const char **argv) { int r; if ((r = config_parse(argc, argv, ¶ms))) return r; atexit(cleanup); if (!isatty(fileno(stdin))) { tty = false; } libac_config_t config = { #ifdef DEBUG .out = NULL, #else .out = NULL, #endif .tok = NULL }; if ((r = ac_init(&config))) { LOGEV("Cannot initialize Acron library: %d", r); return r; } if ((r = uv_loop_init(loop))) goto uviniterr; if ((r = h_signal(on_int, on_stdin_closed))) goto uviniterr; if ((r = a_dns(params.host, params.port, on_resolv))) goto uviniterr; if ((r = uv_run(loop, UV_RUN_DEFAULT))) { if (r == 1) { /* Seems to return 1 if uv_stop is called. */ return 0; } LOGEV("Cannot run: %s", uv_strerror(r)); return -r; } return 0; uviniterr: LOGEV("Cannot initialize: %s", uv_strerror(r)); return -r; }