mirror of https://github.com/cy384/ssheven.git
large improvements to error checking and robustness
This commit is contained in:
parent
3c72511444
commit
f183af48f1
|
@ -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
150
ssheven.c
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
30
ssheven.r
30
ssheven.r
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue