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__
#define __SSHEVEN_CONSTANTS_R__
@ -19,11 +19,18 @@
#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

138
ssheven.c
View File

@ -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();
if (ok)
{
print_string_i("authenticating... "); YieldToAnyThread();
ssh_password_auth(username+1, password+1);
ok = ssh_password_auth(username+1, password+1);
print_string_i("done.\n"); YieldToAnyThread();
}
ssh_setup_terminal();
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,11 +565,18 @@ int main(int argc, char** argv)
int ok = 1;
if (!safety_checks()) return 0;
if (!intro_dialog(hostname, username, password)) ok = 0;
if (ok)
{
if (InitOpenTransport() != noErr)
{
print_string("failed to initialize OT\n");
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);
if (ok)
{
err = OTCancelSynchronousCalls(ssh_con.endpoint, kOTCanceledErr);
CloseOpenTransport();
}
}

View File

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

View File

@ -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) {