From f183af48f1217d8809b0f74ee28ca8c58e371a0e Mon Sep 17 00:00:00 2001 From: cy384 Date: Thu, 23 Jul 2020 19:46:29 -0400 Subject: [PATCH] large improvements to error checking and robustness --- ssheven-constants.r | 15 +++-- ssheven.c | 150 ++++++++++++++++++++++++++++++++++++-------- ssheven.h | 1 + ssheven.r | 30 ++++++++- 4 files changed, 162 insertions(+), 34 deletions(-) diff --git a/ssheven-constants.r b/ssheven-constants.r index 4436939..5d639b8 100644 --- a/ssheven-constants.r +++ b/ssheven-constants.r @@ -1,4 +1,4 @@ -/* used as both a C and resource file include, so keep it simple */ +/* used as both a C and resource file include */ #ifndef __SSHEVEN_CONSTANTS_R__ #define __SSHEVEN_CONSTANTS_R__ @@ -16,14 +16,21 @@ #define SSHEVEN_RELEASE_REGION verUS /* requested number of bytes for RAM, used in SIZE resource */ -#define SSHEVEN_MINIMUM_PARTITION 1024*1024 -#define SSHEVEN_REQUIRED_PARTITION SSHEVEN_MINIMUM_PARTITION +#define SSHEVEN_MINIMUM_PARTITION 1024*1024 +#define SSHEVEN_REQUIRED_PARTITION SSHEVEN_MINIMUM_PARTITION -/* size for recv and send thread buffers */ +/* size in bytes for recv and send thread buffers */ #define SSHEVEN_BUFFER_SIZE 4096 /* terminal type to send over ssh, determines features etc. * "vanilla" supports basically nothing, which is good for us here */ #define SSHEVEN_TERMINAL_TYPE "vanilla" +#define ALRT_OT 128 +#define DITL_OT 129 + +#define DLOG_CONNECT 128 +#define DITL_CONNECT 128 + + #endif diff --git a/ssheven.c b/ssheven.c index 0b84b79..45afdfd 100644 --- a/ssheven.c +++ b/ssheven.c @@ -12,8 +12,8 @@ #include "ssheven-debug.c" // error checking convenience macros -#define OT_CHECK(X) err = (X); if (err != noErr) { print_string("" #X " failed\n"); return; }; -#define SSH_CHECK(X) rc = (X); if (rc != LIBSSH2_ERROR_NONE) { print_string("" #X " failed: "); print_string(libssh2_error_string(rc)); print_string("\n"); return;}; +#define OT_CHECK(X) err = (X); if (err != noErr) { print_string_i("" #X " failed\n"); return 0; }; +#define SSH_CHECK(X) rc = (X); if (rc != LIBSSH2_ERROR_NONE) { print_string("" #X " failed: "); print_string(libssh2_error_string(rc)); print_string("\n"); return 0;}; // sinful globals struct ssheven_console con = { NULL, {0}, 0, 0 }; @@ -76,7 +76,7 @@ void ssh_read(void) InvalRect(&(con.win->portRect)); } -void end_connection(void) +int end_connection(void) { read_thread_state = CLEANUP; @@ -95,7 +95,8 @@ void end_connection(void) if (ssh_con.endpoint != kOTInvalidEndpointRef) { // request to close the TCP connection - OT_CHECK(OTSndOrderlyDisconnect(ssh_con.endpoint)); + //OT_CHECK(OTSndOrderlyDisconnect(ssh_con.endpoint)); + OTSndOrderlyDisconnect(ssh_con.endpoint); // get and discard remaining data so we can finish closing the connection int rc = 1; @@ -274,7 +275,7 @@ void event_loop(void) } while (!exit_event_loop); } -void init_connection(char* hostname) +int init_connection(char* hostname) { int rc; @@ -291,16 +292,19 @@ void init_connection(char* hostname) if (err != noErr || ssh_con.endpoint == kOTInvalidEndpointRef) { - print_string("failed to open OT TCP endpoint\n"); - return; + print_string_i("failed to open OT TCP endpoint\n"); + return 0; } OT_CHECK(OTSetSynchronous(ssh_con.endpoint)); - OT_CHECK(OTSetNonBlocking(ssh_con.endpoint)); + OT_CHECK(OTSetBlocking(ssh_con.endpoint)); OT_CHECK(OTUseSyncIdleEvents(ssh_con.endpoint, false)); + OT_CHECK(OTBind(ssh_con.endpoint, nil, nil)); + OT_CHECK(OTSetNonBlocking(ssh_con.endpoint)); + print_string_i("done.\n"); YieldToAnyThread(); // set up address struct, do the DNS lookup, and connect @@ -325,7 +329,7 @@ void init_connection(char* hostname) if (ssh_con.session == 0) { print_string("failed to initialize SSH library\n"); - return; + return 0; } print_string_i("done.\n"); YieldToAnyThread(); @@ -336,24 +340,28 @@ void init_connection(char* hostname) read_thread_state = OPEN; - return; + return 1; } -void ssh_password_auth(char* username, char* password) +int ssh_password_auth(char* username, char* password) { OSStatus err = noErr; int rc = 1; SSH_CHECK(libssh2_userauth_password(ssh_con.session, username, password)); ssh_con.channel = libssh2_channel_open_session(ssh_con.session); + + return 1; } -void ssh_setup_terminal(void) +int ssh_setup_terminal(void) { int rc = 0; SSH_CHECK(libssh2_channel_request_pty(ssh_con.channel, SSHEVEN_TERMINAL_TYPE)); SSH_CHECK(libssh2_channel_shell(ssh_con.channel)); + + return 1; } int intro_dialog(char* hostname, char* username, char* password) @@ -415,6 +423,8 @@ int intro_dialog(char* hostname, char* username, char* password) // TODO: threads void* read_thread(void* arg) { + int ok = 1; + while (read_thread_command == WAIT) YieldToAnyThread(); if (read_thread_command == EXIT) @@ -423,15 +433,21 @@ void* read_thread(void* arg) } // connect and log in - init_connection(hostname+1); + ok = init_connection(hostname+1); YieldToAnyThread(); - print_string_i("authenticating... "); YieldToAnyThread(); - ssh_password_auth(username+1, password+1); - print_string_i("done.\n"); YieldToAnyThread(); + if (ok) + { + print_string_i("authenticating... "); YieldToAnyThread(); + ok = ssh_password_auth(username+1, password+1); + print_string_i("done.\n"); YieldToAnyThread(); + } - ssh_setup_terminal(); - YieldToAnyThread(); + if (ok) + { + ok = ssh_setup_terminal(); + YieldToAnyThread(); + } // if we failed, exit if (read_thread_state != OPEN) return 0; @@ -449,6 +465,73 @@ void* read_thread(void* arg) return 0; } +int safety_checks(void) +{ + OSStatus err; + long int thread_manager_gestalt = 0; + + // check for thread manager + err = Gestalt(gestaltThreadMgrAttr, &thread_manager_gestalt); + + // bit one is prescence of thread manager + if (err != noErr || (thread_manager_gestalt & (1 << gestaltThreadMgrPresent)) == 0) + { + print_string_i("Thread Manager not available!\n"); + return 0; + } + + // check for Open Transport + + // for some reason, the docs say you shouldn't check for OT via the gestalt + // in an application, and should just try to init, but checking seems more + // user-friendly, so... + + long int open_transport_any_version = 0; + long int open_transport_new_version = 0; + err = Gestalt(gestaltOpenTpt, &open_transport_any_version); + + if (err != noErr) + { + print_string_i("Failed to check for Open Transport!\n"); + return 0; + } + + err = Gestalt(gestaltOpenTptVersions, &open_transport_new_version); + + if (err != noErr) + { + print_string_i("Failed to check for Open Transport!\n"); + return 0; + } + + if (open_transport_any_version == 0 && open_transport_new_version == 0) + { + print_string_i("Open Transport required but not found!\n"); + StopAlert(ALRT_OT, nil); + return 0; + } + + if (open_transport_any_version != 0 && open_transport_new_version == 0) + { + print_string_i("Early version of Open Transport detected!"); + print_string_i(" Attempting to continue anyway.\n"); + } + + NumVersion* ot_version = (NumVersion*) &open_transport_new_version; + + print_string_i("Detected Open Transport version: "); + // "1st part of version number in BCD" + print_int(ot_version->majorRev); + print_char('.'); + // "2nd & 3rd part of version number share a byte" + print_int((ot_version->minorAndBugRev & 0xF0) >> 4); + print_char('.'); + print_int(ot_version->minorAndBugRev & 0x0F); + print_string_i("\n"); + + return 1; +} + int main(int argc, char** argv) { OSStatus err = noErr; @@ -464,8 +547,6 @@ int main(int argc, char** argv) InitWindows(); InitMenus(); - if (!intro_dialog(hostname, username, password)) return 0; - console_setup(); char* logo = " _____ _____ _ _\n" @@ -484,10 +565,17 @@ int main(int argc, char** argv) int ok = 1; - if (InitOpenTransport() != noErr) + if (!safety_checks()) return 0; + + if (!intro_dialog(hostname, username, password)) ok = 0; + + if (ok) { - print_string("failed to initialize OT\n"); - ok = 0; + if (InitOpenTransport() != noErr) + { + print_string_i("failed to initialize OT\n"); + ok = 0; + } } if (ok) @@ -497,7 +585,7 @@ int main(int argc, char** argv) if (ssh_con.recv_buffer == NULL || ssh_con.send_buffer == NULL) { - print_string("failed to allocate network buffers\n"); + print_string_i("failed to allocate network buffers\n"); ok = 0; } } @@ -509,7 +597,7 @@ int main(int argc, char** argv) if (ok) { - err = NewThread(kCooperativeThread, read_thread, NULL, 0, kCreateIfNeeded, NULL, &read_thread_id); + err = NewThread(kCooperativeThread, read_thread, NULL, 100000, kCreateIfNeeded, NULL, &read_thread_id); if (err < 0) { @@ -533,10 +621,18 @@ int main(int argc, char** argv) // err = DisposeThread(read_thread_id, (void*)&read_thread_result, 0); //err = DisposeThread(read_thread_id, NULL, 0); - end_connection(); + if (ok) end_connection(); + + BeginUpdate(con.win); + draw_screen(&(con.win->portRect)); + EndUpdate(con.win); if (ssh_con.recv_buffer != NULL) OTFreeMem(ssh_con.recv_buffer); if (ssh_con.send_buffer != NULL) OTFreeMem(ssh_con.send_buffer); - CloseOpenTransport(); + if (ok) + { + err = OTCancelSynchronousCalls(ssh_con.endpoint, kOTCanceledErr); + CloseOpenTransport(); + } } diff --git a/ssheven.h b/ssheven.h index 9e7cf64..689fc12 100644 --- a/ssheven.h +++ b/ssheven.h @@ -18,6 +18,7 @@ #include #include #include +#include // libssh2 #include diff --git a/ssheven.r b/ssheven.r index e393e7b..40d8fd7 100644 --- a/ssheven.r +++ b/ssheven.r @@ -2,7 +2,7 @@ #include "Dialogs.r" -resource 'DLOG' (128) { +resource 'DLOG' (DLOG_CONNECT) { { 50, 100, 240, 420 }, dBoxProc, visible, @@ -13,7 +13,7 @@ resource 'DLOG' (128) { centerMainScreen }; -resource 'DITL' (128) { +resource 'DITL' (DITL_CONNECT) { { { 190-10-20, 320-10-80, 190-10, 320-10 }, Button { enabled, "Connect" }; @@ -44,6 +44,30 @@ resource 'DITL' (128) { } }; +resource 'DITL' (DITL_OT) { + { + { 50, 260, 70, 340 }, + Button { enabled, "Exit" }; + + { 10, 70, 30, 340 }, + StaticText { enabled, "Open Transport required but not found!" }; + } +}; + +resource 'ALRT' (ALRT_OT, purgeable) { + { 50, 100, 50+80, 100+350 }, + DITL_OT, + + /* OK means draw default border on first button */ + { + OK, visible, silent, + OK, visible, silent, + OK, visible, silent, + OK, visible, silent + }, + alertPositionMainScreen +}; + #include "Processes.r" resource 'SIZE' (-1) { @@ -97,7 +121,7 @@ resource 'SSH7' (0, purgeable) { #include "Finder.r" resource 'FREF' (128, purgeable) { - 'APPL', 0, "" + 'APPL', 0, "" }; resource 'BNDL' (128, purgeable) {