large improvements to error checking and robustness

This commit is contained in:
cy384 2020-07-23 19:46:29 -04:00
parent 3c72511444
commit f183af48f1
4 changed files with 162 additions and 34 deletions

View File

@ -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__ #ifndef __SSHEVEN_CONSTANTS_R__
#define __SSHEVEN_CONSTANTS_R__ #define __SSHEVEN_CONSTANTS_R__
@ -16,14 +16,21 @@
#define SSHEVEN_RELEASE_REGION verUS #define SSHEVEN_RELEASE_REGION verUS
/* requested number of bytes for RAM, used in SIZE resource */ /* requested number of bytes for RAM, used in SIZE resource */
#define SSHEVEN_MINIMUM_PARTITION 1024*1024 #define SSHEVEN_MINIMUM_PARTITION 1024*1024
#define SSHEVEN_REQUIRED_PARTITION SSHEVEN_MINIMUM_PARTITION #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 #define SSHEVEN_BUFFER_SIZE 4096
/* terminal type to send over ssh, determines features etc. /* terminal type to send over ssh, determines features etc.
* "vanilla" supports basically nothing, which is good for us here */ * "vanilla" supports basically nothing, which is good for us here */
#define SSHEVEN_TERMINAL_TYPE "vanilla" #define SSHEVEN_TERMINAL_TYPE "vanilla"
#define ALRT_OT 128
#define DITL_OT 129
#define DLOG_CONNECT 128
#define DITL_CONNECT 128
#endif #endif

150
ssheven.c
View File

@ -12,8 +12,8 @@
#include "ssheven-debug.c" #include "ssheven-debug.c"
// error checking convenience macros // error checking convenience macros
#define OT_CHECK(X) err = (X); if (err != noErr) { print_string("" #X " failed\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;}; #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 // sinful globals
struct ssheven_console con = { NULL, {0}, 0, 0 }; struct ssheven_console con = { NULL, {0}, 0, 0 };
@ -76,7 +76,7 @@ void ssh_read(void)
InvalRect(&(con.win->portRect)); InvalRect(&(con.win->portRect));
} }
void end_connection(void) int end_connection(void)
{ {
read_thread_state = CLEANUP; read_thread_state = CLEANUP;
@ -95,7 +95,8 @@ void end_connection(void)
if (ssh_con.endpoint != kOTInvalidEndpointRef) if (ssh_con.endpoint != kOTInvalidEndpointRef)
{ {
// request to close the TCP connection // 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 // get and discard remaining data so we can finish closing the connection
int rc = 1; int rc = 1;
@ -274,7 +275,7 @@ void event_loop(void)
} while (!exit_event_loop); } while (!exit_event_loop);
} }
void init_connection(char* hostname) int init_connection(char* hostname)
{ {
int rc; int rc;
@ -291,16 +292,19 @@ void init_connection(char* hostname)
if (err != noErr || ssh_con.endpoint == kOTInvalidEndpointRef) if (err != noErr || ssh_con.endpoint == kOTInvalidEndpointRef)
{ {
print_string("failed to open OT TCP endpoint\n"); print_string_i("failed to open OT TCP endpoint\n");
return; return 0;
} }
OT_CHECK(OTSetSynchronous(ssh_con.endpoint)); 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(OTUseSyncIdleEvents(ssh_con.endpoint, false));
OT_CHECK(OTBind(ssh_con.endpoint, nil, nil)); OT_CHECK(OTBind(ssh_con.endpoint, nil, nil));
OT_CHECK(OTSetNonBlocking(ssh_con.endpoint));
print_string_i("done.\n"); YieldToAnyThread(); print_string_i("done.\n"); YieldToAnyThread();
// set up address struct, do the DNS lookup, and connect // set up address struct, do the DNS lookup, and connect
@ -325,7 +329,7 @@ void init_connection(char* hostname)
if (ssh_con.session == 0) if (ssh_con.session == 0)
{ {
print_string("failed to initialize SSH library\n"); print_string("failed to initialize SSH library\n");
return; return 0;
} }
print_string_i("done.\n"); YieldToAnyThread(); print_string_i("done.\n"); YieldToAnyThread();
@ -336,24 +340,28 @@ void init_connection(char* hostname)
read_thread_state = OPEN; 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; OSStatus err = noErr;
int rc = 1; int rc = 1;
SSH_CHECK(libssh2_userauth_password(ssh_con.session, username, password)); SSH_CHECK(libssh2_userauth_password(ssh_con.session, username, password));
ssh_con.channel = libssh2_channel_open_session(ssh_con.session); 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; int rc = 0;
SSH_CHECK(libssh2_channel_request_pty(ssh_con.channel, SSHEVEN_TERMINAL_TYPE)); SSH_CHECK(libssh2_channel_request_pty(ssh_con.channel, SSHEVEN_TERMINAL_TYPE));
SSH_CHECK(libssh2_channel_shell(ssh_con.channel)); SSH_CHECK(libssh2_channel_shell(ssh_con.channel));
return 1;
} }
int intro_dialog(char* hostname, char* username, char* password) int intro_dialog(char* hostname, char* username, char* password)
@ -415,6 +423,8 @@ int intro_dialog(char* hostname, char* username, char* password)
// TODO: threads // TODO: threads
void* read_thread(void* arg) void* read_thread(void* arg)
{ {
int ok = 1;
while (read_thread_command == WAIT) YieldToAnyThread(); while (read_thread_command == WAIT) YieldToAnyThread();
if (read_thread_command == EXIT) if (read_thread_command == EXIT)
@ -423,15 +433,21 @@ void* read_thread(void* arg)
} }
// connect and log in // connect and log in
init_connection(hostname+1); ok = init_connection(hostname+1);
YieldToAnyThread(); YieldToAnyThread();
print_string_i("authenticating... "); YieldToAnyThread(); if (ok)
ssh_password_auth(username+1, password+1); {
print_string_i("done.\n"); YieldToAnyThread(); print_string_i("authenticating... "); YieldToAnyThread();
ok = ssh_password_auth(username+1, password+1);
print_string_i("done.\n"); YieldToAnyThread();
}
ssh_setup_terminal(); if (ok)
YieldToAnyThread(); {
ok = ssh_setup_terminal();
YieldToAnyThread();
}
// if we failed, exit // if we failed, exit
if (read_thread_state != OPEN) return 0; if (read_thread_state != OPEN) return 0;
@ -449,6 +465,73 @@ void* read_thread(void* arg)
return 0; 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) int main(int argc, char** argv)
{ {
OSStatus err = noErr; OSStatus err = noErr;
@ -464,8 +547,6 @@ int main(int argc, char** argv)
InitWindows(); InitWindows();
InitMenus(); InitMenus();
if (!intro_dialog(hostname, username, password)) return 0;
console_setup(); console_setup();
char* logo = " _____ _____ _ _\n" char* logo = " _____ _____ _ _\n"
@ -484,10 +565,17 @@ int main(int argc, char** argv)
int ok = 1; 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"); if (InitOpenTransport() != noErr)
ok = 0; {
print_string_i("failed to initialize OT\n");
ok = 0;
}
} }
if (ok) if (ok)
@ -497,7 +585,7 @@ int main(int argc, char** argv)
if (ssh_con.recv_buffer == NULL || ssh_con.send_buffer == NULL) 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; ok = 0;
} }
} }
@ -509,7 +597,7 @@ int main(int argc, char** argv)
if (ok) 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) 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, (void*)&read_thread_result, 0);
//err = DisposeThread(read_thread_id, NULL, 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.recv_buffer != NULL) OTFreeMem(ssh_con.recv_buffer);
if (ssh_con.send_buffer != NULL) OTFreeMem(ssh_con.send_buffer); if (ssh_con.send_buffer != NULL) OTFreeMem(ssh_con.send_buffer);
CloseOpenTransport(); if (ok)
{
err = OTCancelSynchronousCalls(ssh_con.endpoint, kOTCanceledErr);
CloseOpenTransport();
}
} }

View File

@ -18,6 +18,7 @@
#include <Fonts.h> #include <Fonts.h>
#include <Windows.h> #include <Windows.h>
#include <Sound.h> #include <Sound.h>
#include <Gestalt.h>
// libssh2 // libssh2
#include <libssh2.h> #include <libssh2.h>

View File

@ -2,7 +2,7 @@
#include "Dialogs.r" #include "Dialogs.r"
resource 'DLOG' (128) { resource 'DLOG' (DLOG_CONNECT) {
{ 50, 100, 240, 420 }, { 50, 100, 240, 420 },
dBoxProc, dBoxProc,
visible, visible,
@ -13,7 +13,7 @@ resource 'DLOG' (128) {
centerMainScreen centerMainScreen
}; };
resource 'DITL' (128) { resource 'DITL' (DITL_CONNECT) {
{ {
{ 190-10-20, 320-10-80, 190-10, 320-10 }, { 190-10-20, 320-10-80, 190-10, 320-10 },
Button { enabled, "Connect" }; 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" #include "Processes.r"
resource 'SIZE' (-1) { resource 'SIZE' (-1) {
@ -97,7 +121,7 @@ resource 'SSH7' (0, purgeable) {
#include "Finder.r" #include "Finder.r"
resource 'FREF' (128, purgeable) { resource 'FREF' (128, purgeable) {
'APPL', 0, "" 'APPL', 0, ""
}; };
resource 'BNDL' (128, purgeable) { resource 'BNDL' (128, purgeable) {