| 29 |
|
|
| 30 |
#include "ttxssh.h" |
#include "ttxssh.h" |
| 31 |
#include "util.h" |
#include "util.h" |
| 32 |
|
#include "resource.h" |
| 33 |
|
|
| 34 |
#include <openssl/bn.h> |
#include <openssl/bn.h> |
| 35 |
#include <openssl/evp.h> |
#include <openssl/evp.h> |
| 52 |
#include <sys/stat.h> |
#include <sys/stat.h> |
| 53 |
#include <assert.h> |
#include <assert.h> |
| 54 |
|
|
| 55 |
|
|
| 56 |
// SSH2 macro |
// SSH2 macro |
| 57 |
#ifdef _DEBUG |
#ifdef _DEBUG |
| 58 |
#define SSH2_DEBUG |
#define SSH2_DEBUG |
| 88 |
char sendfilefull[MAX_PATH]; // sending filename fullpath |
char sendfilefull[MAX_PATH]; // sending filename fullpath |
| 89 |
FILE *sendfp; // file pointer |
FILE *sendfp; // file pointer |
| 90 |
struct _stat filestat; // file status information |
struct _stat filestat; // file status information |
| 91 |
HANDLE thread; // sending thread handle |
HWND progress; |
| 92 |
} scp_t; |
} scp_t; |
| 93 |
|
|
| 94 |
typedef struct channel { |
typedef struct channel { |
| 183 |
c->bufchain = NULL; |
c->bufchain = NULL; |
| 184 |
if (type == TYPE_SCP) { |
if (type == TYPE_SCP) { |
| 185 |
c->scp.state = SCP_INIT; |
c->scp.state = SCP_INIT; |
| 186 |
c->scp.thread = (HANDLE)-1L; |
c->scp.progress = NULL; |
| 187 |
} |
} |
| 188 |
|
|
| 189 |
return (c); |
return (c); |
| 257 |
|
|
| 258 |
if (c->type == TYPE_SCP) { |
if (c->type == TYPE_SCP) { |
| 259 |
c->scp.state = SCP_CLOSING; |
c->scp.state = SCP_CLOSING; |
| 260 |
// SCPスレッドが動いていたら終わるまで待つ |
if (c->scp.progress != NULL) { |
| 261 |
if (c->scp.thread != (HANDLE)-1L) { |
//SendMessage(c->scp.progress, WM_CLOSE, 0, 0); |
| 262 |
WaitForSingleObject(c->scp.thread, INFINITE); |
DestroyWindow(c->scp.progress); |
| 263 |
CloseHandle(c->scp.thread); |
c->scp.progress = NULL; |
|
c->scp.thread = (HANDLE)-1L; |
|
| 264 |
} |
} |
| 265 |
|
fclose(c->scp.sendfp); |
| 266 |
} |
} |
| 267 |
|
|
| 268 |
memset(c, 0, sizeof(Channel_t)); |
memset(c, 0, sizeof(Channel_t)); |
| 334 |
|
|
| 335 |
void ssh_heartbeat_lock(void) |
void ssh_heartbeat_lock(void) |
| 336 |
{ |
{ |
| 337 |
EnterCriticalSection(&g_ssh_heartbeat_lock); |
//EnterCriticalSection(&g_ssh_heartbeat_lock); |
| 338 |
} |
} |
| 339 |
|
|
| 340 |
void ssh_heartbeat_unlock(void) |
void ssh_heartbeat_unlock(void) |
| 341 |
{ |
{ |
| 342 |
LeaveCriticalSection(&g_ssh_heartbeat_lock); |
//LeaveCriticalSection(&g_ssh_heartbeat_lock); |
| 343 |
} |
} |
| 344 |
|
|
| 345 |
static void ssh_blocking_send_lock(void) |
static void ssh_blocking_send_lock(void) |
| 346 |
{ |
{ |
| 347 |
EnterCriticalSection(&g_ssh_blocking_send_lock); |
//EnterCriticalSection(&g_ssh_blocking_send_lock); |
| 348 |
} |
} |
| 349 |
|
|
| 350 |
static void ssh_blocking_send_unlock(void) |
static void ssh_blocking_send_unlock(void) |
| 351 |
{ |
{ |
| 352 |
LeaveCriticalSection(&g_ssh_blocking_send_lock); |
//LeaveCriticalSection(&g_ssh_blocking_send_lock); |
| 353 |
} |
} |
| 354 |
|
|
| 355 |
|
|
| 6414 |
|
|
| 6415 |
static void start_ssh_heartbeat_thread(PTInstVar pvar) |
static void start_ssh_heartbeat_thread(PTInstVar pvar) |
| 6416 |
{ |
{ |
| 6417 |
HANDLE thread; |
HANDLE thread = (HANDLE)-1; |
| 6418 |
unsigned tid; |
//unsigned tid; |
| 6419 |
|
|
| 6420 |
|
// TTSSHは thread-safe ではないのでスレッドは禁止 (yutaka) |
| 6421 |
|
#if 0 |
| 6422 |
thread = (HANDLE)_beginthreadex(NULL, 0, ssh_heartbeat_thread, pvar, 0, &tid); |
thread = (HANDLE)_beginthreadex(NULL, 0, ssh_heartbeat_thread, pvar, 0, &tid); |
| 6423 |
|
#endif |
| 6424 |
if (thread == (HANDLE)-1) { |
if (thread == (HANDLE)-1) { |
| 6425 |
// TODO: |
// TODO: |
| 6426 |
} |
} |
| 7023 |
} |
} |
| 7024 |
|
|
| 7025 |
|
|
| 7026 |
|
void ssh2_channel_remote_close(PTInstVar pvar, Channel_t *c) |
| 7027 |
|
{ |
| 7028 |
|
if (SSHv2(pvar)) { |
| 7029 |
|
buffer_t *msg; |
| 7030 |
|
unsigned char *outmsg; |
| 7031 |
|
int len; |
| 7032 |
|
|
| 7033 |
|
// SSH2 serverにchannel closeを伝える |
| 7034 |
|
msg = buffer_init(); |
| 7035 |
|
if (msg == NULL) { |
| 7036 |
|
// TODO: error check |
| 7037 |
|
return; |
| 7038 |
|
} |
| 7039 |
|
buffer_put_int(msg, c->remote_id); |
| 7040 |
|
|
| 7041 |
|
len = buffer_len(msg); |
| 7042 |
|
outmsg = begin_send_packet(pvar, SSH2_MSG_CHANNEL_CLOSE, len); |
| 7043 |
|
memcpy(outmsg, buffer_ptr(msg), len); |
| 7044 |
|
finish_send_packet(pvar); |
| 7045 |
|
buffer_free(msg); |
| 7046 |
|
} |
| 7047 |
|
} |
| 7048 |
|
|
| 7049 |
|
#define WM_START_SENDING_FILE (WM_USER + 1) |
| 7050 |
|
|
| 7051 |
typedef struct scp_thread_parm { |
typedef struct scp_thread_parm { |
| 7052 |
PTInstVar pvar; |
PTInstVar pvar; |
| 7053 |
Channel_t *c; |
Channel_t *c; |
| 7054 |
} scp_thread_parm_t; |
} scp_thread_parm_t; |
| 7055 |
|
|
| 7056 |
static unsigned __stdcall ssh_scp_thread(void FAR * p) |
static LRESULT CALLBACK ssh_scp_dlg_proc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) |
| 7057 |
{ |
{ |
| 7058 |
scp_thread_parm_t *parm = (scp_thread_parm_t *)p; |
const int RWIN_TIMEOUT = 100; // 100 msec |
| 7059 |
PTInstVar pvar = parm->pvar; |
const int SEND_TIMEOUT = 1; // 1 msec |
| 7060 |
Channel_t *c = parm->c; |
const int IDC_TIMER = 1; |
| 7061 |
|
static int instance = 0; |
| 7062 |
|
static PTInstVar pvar = NULL; |
| 7063 |
|
static Channel_t *c = NULL; |
| 7064 |
|
static long long total_size = 0; |
| 7065 |
char buf[8192]; |
char buf[8192]; |
| 7066 |
size_t ret; |
size_t ret; |
| 7067 |
long long total_size = 0; |
scp_thread_parm_t *parm; |
| 7068 |
|
|
| 7069 |
do { |
switch (msg) { |
| 7070 |
// ファイルから読み込んだデータはかならずサーバへ送信する。 |
case WM_INITDIALOG: |
| 7071 |
ret = fread(buf, 1, sizeof(buf), c->scp.sendfp); |
if (instance > 0) { |
| 7072 |
if (ret == 0) |
EndDialog(hWnd, 0); |
| 7073 |
break; |
} else { |
| 7074 |
|
instance++; |
| 7075 |
|
} |
| 7076 |
|
return FALSE; |
| 7077 |
|
|
| 7078 |
|
case WM_TIMER: |
| 7079 |
|
{ |
| 7080 |
|
char s[80]; |
| 7081 |
|
|
|
do { |
|
| 7082 |
// socket or channelがクローズされたらスレッドを終わる |
// socket or channelがクローズされたらスレッドを終わる |
| 7083 |
if (pvar->socket == INVALID_SOCKET || c->scp.state == SCP_CLOSING || c->used == 0) |
if (pvar->socket == INVALID_SOCKET || c->scp.state == SCP_CLOSING || c->used == 0) |
| 7084 |
goto done; |
goto end; |
| 7085 |
|
|
| 7086 |
// サーバのウィンドウに余裕がない場合は、送信しない。SSH2_send_channel_data()で遅延送信処理が |
if (sizeof(buf) > c->remote_window) { |
| 7087 |
// あるが、SCPスレッドとメインスレッドは別コンテキストであるため、SCPスレッドから遅延送信処理を |
SetTimer(hWnd, 1, RWIN_TIMEOUT, 0); |
| 7088 |
// 行おうとしてもうまく動かない。 |
return TRUE; |
|
if (ret > c->remote_window) { |
|
|
Sleep(100); // yield |
|
| 7089 |
} |
} |
|
} while (ret > c->remote_window); |
|
| 7090 |
|
|
| 7091 |
// 別コンテキストで、SSHのシーケンスへ割り込まないようにロックを取る。 |
// ファイルから読み込んだデータはかならずサーバへ送信する。 |
| 7092 |
ssh_heartbeat_lock(); |
ret = fread(buf, 1, sizeof(buf), c->scp.sendfp); |
| 7093 |
SSH2_send_channel_data(pvar, c, buf, ret); |
if (ret == 0) |
| 7094 |
ssh_heartbeat_unlock(); |
goto eof; |
| 7095 |
|
SSH2_send_channel_data(pvar, c, buf, ret); |
| 7096 |
|
total_size += ret; |
| 7097 |
|
|
| 7098 |
|
_snprintf_s(s, sizeof(s), _TRUNCATE, "%lld / %lld (%d%%)", total_size, (long long)c->scp.filestat.st_size, |
| 7099 |
|
(100 * total_size / c->scp.filestat.st_size)%100 ); |
| 7100 |
|
SendMessage(GetDlgItem(hWnd, IDC_PROGRESS), WM_SETTEXT, 0, (LPARAM)s); |
| 7101 |
|
goto retry; |
| 7102 |
|
|
| 7103 |
|
eof: |
| 7104 |
|
SSH2_send_channel_data(pvar, c, "\0", 1); |
| 7105 |
|
c->scp.state = SCP_DATA; |
| 7106 |
|
assert(total_size == c->scp.filestat.st_size); |
| 7107 |
|
end: |
| 7108 |
|
c->scp.state = SCP_DATA; |
| 7109 |
|
PostMessage(hWnd, WM_CLOSE, 0, 0); |
| 7110 |
|
return TRUE; |
| 7111 |
|
|
| 7112 |
total_size += ret; |
retry: |
| 7113 |
|
SetTimer(hWnd, IDC_TIMER, SEND_TIMEOUT, 0); |
| 7114 |
|
} |
| 7115 |
|
return TRUE; |
| 7116 |
|
break; |
| 7117 |
|
|
| 7118 |
} while (ret >= sizeof(buf)); |
case WM_START_SENDING_FILE: |
| 7119 |
|
{ |
| 7120 |
|
parm = (scp_thread_parm_t *)wp; |
| 7121 |
|
pvar = parm->pvar; |
| 7122 |
|
c = parm->c; |
| 7123 |
|
free(parm); // free! |
| 7124 |
|
total_size = 0; |
| 7125 |
|
|
| 7126 |
// EOF |
SendMessage(GetDlgItem(hWnd, IDC_FILENAME), WM_SETTEXT, 0, (LPARAM)c->scp.sendfile); |
|
SSH2_send_channel_data(pvar, c, "\0", 1); |
|
|
c->scp.state = SCP_DATA; |
|
| 7127 |
|
|
| 7128 |
assert(total_size == c->scp.filestat.st_size); |
SetTimer(hWnd, 1, 100, 0); |
| 7129 |
|
} |
| 7130 |
|
return TRUE; |
| 7131 |
|
break; |
| 7132 |
|
|
| 7133 |
done: |
case WM_COMMAND: |
| 7134 |
free(p); |
switch (wp) { |
| 7135 |
|
} |
| 7136 |
|
|
| 7137 |
return 0; |
switch (LOWORD(wp)) { |
| 7138 |
|
case IDOK: |
| 7139 |
|
{ |
| 7140 |
|
return TRUE; |
| 7141 |
|
} |
| 7142 |
|
|
| 7143 |
|
case IDCANCEL: |
| 7144 |
|
ssh2_channel_remote_close(pvar, c); |
| 7145 |
|
PostMessage(hWnd, WM_CLOSE, 0, 0); |
| 7146 |
|
//EndDialog(hWnd, 0); |
| 7147 |
|
return TRUE; |
| 7148 |
|
default: |
| 7149 |
|
return FALSE; |
| 7150 |
|
} |
| 7151 |
|
break; |
| 7152 |
|
|
| 7153 |
|
case WM_CLOSE: |
| 7154 |
|
KillTimer(hWnd, IDC_TIMER); |
| 7155 |
|
EndDialog(hWnd, 0); |
| 7156 |
|
return TRUE; |
| 7157 |
|
|
| 7158 |
|
case WM_DESTROY: |
| 7159 |
|
instance--; |
| 7160 |
|
return TRUE; |
| 7161 |
|
|
| 7162 |
|
default: |
| 7163 |
|
return FALSE; |
| 7164 |
|
} |
| 7165 |
|
return TRUE; |
| 7166 |
} |
} |
| 7167 |
|
|
| 7168 |
|
|
| 7236 |
SSH2_send_channel_data(pvar, c, buf, strlen(buf)); |
SSH2_send_channel_data(pvar, c, buf, strlen(buf)); |
| 7237 |
|
|
| 7238 |
} else if (c->scp.state == SCP_FILEINFO) { |
} else if (c->scp.state == SCP_FILEINFO) { |
|
HANDLE thread; |
|
|
unsigned tid; |
|
| 7239 |
scp_thread_parm_t *parm = malloc(sizeof(scp_thread_parm_t)); |
scp_thread_parm_t *parm = malloc(sizeof(scp_thread_parm_t)); |
| 7240 |
|
HWND hDlgWnd; |
| 7241 |
|
|
| 7242 |
if (parm == NULL) { |
if (parm == NULL) { |
| 7243 |
// TODO: |
// TODO: |
| 7245 |
parm->pvar = pvar; |
parm->pvar = pvar; |
| 7246 |
parm->c = c; |
parm->c = c; |
| 7247 |
|
|
| 7248 |
thread = (HANDLE)_beginthreadex(NULL, 0, ssh_scp_thread, parm, 0, &tid); |
hDlgWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_SSHSCP_PROGRESS), |
| 7249 |
if (thread == (HANDLE)-1) { |
pvar->cv->HWin, (DLGPROC)ssh_scp_dlg_proc); |
| 7250 |
// TODO: |
if (hDlgWnd != NULL) { |
| 7251 |
|
c->scp.progress = hDlgWnd; |
| 7252 |
|
ShowWindow(hDlgWnd, SW_SHOW); |
| 7253 |
|
SendMessage(hDlgWnd, WM_START_SENDING_FILE, (WPARAM)parm, 0); |
| 7254 |
} |
} |
|
c->scp.thread = thread; |
|
| 7255 |
|
|
| 7256 |
} else if (c->scp.state == SCP_DATA) { |
} else if (c->scp.state == SCP_DATA) { |
| 7257 |
// 送信完了 |
// 送信完了 |
| 7258 |
ssh2_channel_delete(c); // free channel |
ssh2_channel_delete(c); // free channel |
| 7259 |
|
|
| 7260 |
MessageBox(NULL, "SCP sending done.", "TTSSH", MB_OK); |
//MessageBox(NULL, "SCP sending done.", "TTSSH", MB_OK); |
| 7261 |
} |
} |
| 7262 |
|
|
| 7263 |
} else { // error |
} else { // error |
| 7264 |
char msg[2048]; |
char msg[2048]; |
| 7265 |
unsigned int i; |
unsigned int i, max; |
| 7266 |
|
|
| 7267 |
for (i = 0 ; i < str_len ; i++) { |
if (str_len > sizeof(msg)) |
| 7268 |
|
max = sizeof(msg); |
| 7269 |
|
else |
| 7270 |
|
max = str_len; |
| 7271 |
|
for (i = 0 ; i < max ; i++) { |
| 7272 |
msg[i] = data[i]; |
msg[i] = data[i]; |
| 7273 |
} |
} |
| 7274 |
msg[i] = '\0'; |
msg[i] = '\0'; |
| 7275 |
|
|
| 7276 |
|
ssh2_channel_remote_close(pvar, c); |
| 7277 |
ssh2_channel_delete(c); // free channel |
ssh2_channel_delete(c); // free channel |
| 7278 |
|
|
| 7279 |
MessageBox(NULL, msg, "TTSSH: SCP error", MB_OK | MB_ICONEXCLAMATION); |
MessageBox(NULL, msg, "TTSSH: SCP error", MB_OK | MB_ICONEXCLAMATION); |