[Ttssh2-commit] [7771] ポート転送でSSH通信が遅い場合において、Tera Term(TTSSH)の消費メモリが

Back to archive index
scmno****@osdn***** scmno****@osdn*****
2019年 6月 15日 (土) 15:42:23 JST


Revision: 7771
          https://osdn.net/projects/ttssh2/scm/svn/commits/7771
Author:   yutakapon
Date:     2019-06-15 15:42:23 +0900 (Sat, 15 Jun 2019)
Log Message:
-----------
ポート転送でSSH通信が遅い場合において、Tera Term(TTSSH)の消費メモリが
肥大化して、アプリが落ちる問題を修正した。
チケット #39297

local channelからのパケット読み込み時、SSHサーバへの送信でremote_windowに
空きがない場合は、バッファにパケットを記録するが、フロー制御を追加して際限なく
バッファに溜め込まないようにした。

branches/portfwd_memleak ブランチからのマージ。

Ticket Links:
------------
    https://osdn.net/projects/ttssh2/tracker/detail/39297

Modified Paths:
--------------
    trunk/ttssh2/ttxssh/fwd.c
    trunk/ttssh2/ttxssh/fwd.h
    trunk/ttssh2/ttxssh/ssh.c
    trunk/ttssh2/ttxssh/ssh.h

Property Changed:
----------------
    trunk/

-------------- next part --------------
Index: trunk
===================================================================
--- trunk	2019-06-14 23:40:58 UTC (rev 7770)
+++ trunk	2019-06-15 06:42:23 UTC (rev 7771)

Property changes on: trunk
___________________________________________________________________
Modified: svn:mergeinfo
## -1,4 +1,5 ##
 /branches/drag_and_drop:7130,7139,7141,7143-7147
+/branches/portfwd_memleak:7732,7736-7737,7764
 /branches/ssh_ed25519:5495-5544
 /branches/vs2015_warn:6194-6285
 /tags/teraterm-4_89:6182
\ No newline at end of property
Modified: trunk/ttssh2/ttxssh/fwd.c
===================================================================
--- trunk/ttssh2/ttxssh/fwd.c	2019-06-14 23:40:58 UTC (rev 7770)
+++ trunk/ttssh2/ttxssh/fwd.c	2019-06-15 06:42:23 UTC (rev 7771)
@@ -679,9 +679,21 @@
 
 	while (channel->local_socket != INVALID_SOCKET) {
 		char buf[CHANNEL_READ_BUF_SIZE];
-		int amount = recv(channel->local_socket, buf, sizeof(buf), 0);
+		int amount;
 		int err;
 
+		// recv\x82̈ꎞ\x92\xE2\x8E~\x92\x86\x82Ȃ\xE7\x82΁A\x89\xBD\x82\xE0\x82\xB9\x82\xB8\x82ɖ߂\xE9\x81B
+		if (SSHv2(pvar)) {
+			Channel_t* c = ssh2_local_channel_lookup(channel_num);
+			if (c->bufchain_recv_suspended) {
+				logprintf(LOG_LEVEL_NOTICE, "%s: channel=%d recv was skipped for flow control",
+					__FUNCTION__, channel_num);
+				return;
+			}
+		}
+
+		amount = recv(channel->local_socket, buf, sizeof(buf), 0);
+
 		// X\x83T\x81[\x83o\x82\xA9\x82\xE7\x82̃f\x81[\x83^\x8E\xF3\x90M\x82\xAA\x82\xA0\x82\xEA\x82΁A\x83m\x83\x93\x83u\x83\x8D\x83b\x83L\x83\x93\x83O\x83\x82\x81[\x83h\x82Ń\\x83P\x83b\x83g\x8E\xF3\x90M\x82\xF0\x8Ds\x82\xA2\x81A
 		// SSH\x83T\x81[\x83o\x82\xCCX\x83A\x83v\x83\x8A\x83P\x81[\x83V\x83\x87\x83\x93\x82֑\x97\x90M\x82\xB7\x82\xE9\x81B
 		//OutputDebugPrintf("%s: recv %d\n", __FUNCTION__, amount);
@@ -740,6 +752,63 @@
 	}
 }
 
+// local connection\x82̎\xF3\x90M\x82̒\xE2\x8E~\x82\xA8\x82\xE6\x82эĊJ\x82̔\xBB\x92f\x82\xF0\x8Ds\x82\xA4
+// 
+// notify: TRUE    recv\x82\xF0\x8DĊJ\x82\xB7\x82\xE9
+//         FALSE   recv\x82\xF0\x92\xE2\x8E~\x82\xB7\x82\xE9
+//
+// [\x96ړI]
+// remote_window\x82ɋ󂫂\xAA\x82Ȃ\xA2\x8Fꍇ\x82͒ʒm\x83I\x83t\x82Ƃ\xB5\x81A\x8B󂫂\xAA\x82ł\xAB\x82\xBD\x8Fꍇ\x82\xCD
+// \x92ʒm\x82\xF0\x8DĊJ\x82\xB7\x82\xE9\x81B
+// remote_window\x82ɗ]\x97T\x82\xAA\x82Ȃ\xA2\x8F\xF3\x91ԂŁAlocal connection\x82\xA9\x82\xE7\x82̃p\x83P\x83b\x83g\x82\xF0
+// \x8E\xF3\x90M\x82\xB5\x91\xB1\x82\xAF\x82\xE9\x82ƁA\x8F\xC1\x94\x83\x82\x83\x8A\x82\xAA\x94\xEC\x91剻\x82\xB7\x82\xE9(\x8C\xB5\x96\xA7\x82ɂ̓\x81\x83\x82\x83\x8A\x83\x8A\x81[\x83N\x82ł͂Ȃ\xA2)
+// \x82Ƃ\xA2\x82\xA4\x96\xE2\x91\xE8\x82\xF0\x89\xF1\x94\xF0\x82\xB7\x82\xE9\x81B
+//
+// (2019.6.5 yutaka)
+void FWD_suspend_resume_local_connection(PTInstVar pvar, Channel_t* c, int notify)
+{
+	int channel_num;
+	FWDChannel* channel;
+	int changed = 0;
+
+	channel_num = c->local_num;
+	channel = pvar->fwd_state.channels + channel_num;
+
+	if (notify) {
+		// recv\x82\xF0\x8DĊJ\x82\xB7\x82邩\x94\xBB\x92f\x82\xB7\x82\xE9
+		if (c->bufchain_amount <= FWD_LOW_WATER_MARK) {
+			// \x89\xBA\x8C\xC0\x82\xF0\x89\xBA\x89\xF1\x82\xC1\x82\xBD\x82̂ōĊJ
+			c->bufchain_recv_suspended = FALSE;
+
+			// \x82\xB1\x82\xB1\x82ōĊJ\x82̃\x81\x83b\x83Z\x81[\x83W\x82\xF0\x94\xF2\x82΂\xB7
+			PostMessage(pvar->fwd_state.accept_wnd, WM_SOCK_IO, 
+				(WPARAM)channel->local_socket,
+				MAKEWPARAM(FD_READ, 0)
+				);
+
+			changed = 1;
+		}
+
+	} else {
+		// recv\x82\xF0\x92\xE2\x8E~\x82\xB7\x82邩\x94\xBB\x92f\x82\xB7\x82\xE9
+		if (c->bufchain_amount >= FWD_HIGH_WATER_MARK) {
+			// \x8F\xE3\x8C\xC0\x82𒴂\xA6\x82\xBD\x82̂Œ\xE2\x8E~
+			c->bufchain_recv_suspended = TRUE;
+			changed = 1;
+		}
+	}
+
+	logprintf(LOG_LEVEL_NOTICE, 
+		"%s: Local channel#%d recv has been `%s' for flow control(buffer size %lu, recv %s).",
+		__FUNCTION__, channel_num, 
+		c->bufchain_recv_suspended ? "disabled" : "enabled",
+		c->bufchain_amount,
+		changed ? "changed" : ""
+		);
+
+}
+
+
 static LRESULT CALLBACK accept_wnd_proc(HWND wnd, UINT msg, WPARAM wParam,
                                         LPARAM lParam)
 {

Modified: trunk/ttssh2/ttxssh/fwd.h
===================================================================
--- trunk/ttssh2/ttxssh/fwd.h	2019-06-14 23:40:58 UTC (rev 7770)
+++ trunk/ttssh2/ttxssh/fwd.h	2019-06-15 06:42:23 UTC (rev 7771)
@@ -35,6 +35,11 @@
 #ifndef __FWD_H
 #define __FWD_H
 
+// \x83|\x81[\x83g\x93]\x91\x97\x82ɂ\xA8\x82\xAF\x82\xE9\x83t\x83\x8D\x81[\x90\xA7\x8C\xE4\x82\xCC臒l
+// \x93K\x97p\x90\xE6 Channel_t.bufchain_amount
+#define FWD_HIGH_WATER_MARK (1 * 1024 * 1024)  // 1MB
+#define FWD_LOW_WATER_MARK (0)  // 0MB
+
 #define FWD_REMOTE_CONNECTED  0x01
 #define FWD_LOCAL_CONNECTED   0x02
 #define FWD_BOTH_CONNECTED    (FWD_REMOTE_CONNECTED | FWD_LOCAL_CONNECTED)
@@ -164,5 +169,6 @@
 int FWD_check_local_channel_num(PTInstVar pvar, int local_num);
 int FWD_agent_open(PTInstVar pvar, uint32 remote_channel_num);
 BOOL FWD_agent_forward_confirm(PTInstVar pvar);
+void FWD_suspend_resume_local_connection(PTInstVar pvar, Channel_t* c, int notify);
 
 #endif

Modified: trunk/ttssh2/ttxssh/ssh.c
===================================================================
--- trunk/ttssh2/ttxssh/ssh.c	2019-06-14 23:40:58 UTC (rev 7770)
+++ trunk/ttssh2/ttxssh/ssh.c	2019-06-15 06:42:23 UTC (rev 7771)
@@ -213,6 +213,8 @@
 	c->type = type;
 	c->local_num = local_num;  // alloc_channel()\x82̕Ԓl\x82\xF0\x95ۑ\xB6\x82\xB5\x82Ă\xA8\x82\xAD
 	c->bufchain = NULL;
+	c->bufchain_amount = 0;
+	c->bufchain_recv_suspended = FALSE;
 	if (type == TYPE_SCP) {
 		c->scp.state = SCP_INIT;
 		c->scp.progress_window = NULL;
@@ -231,7 +233,8 @@
 }
 
 // remote_window\x82̋󂫂\xAA\x82Ȃ\xA2\x8Fꍇ\x82ɁA\x91\x97\x82\xEA\x82Ȃ\xA9\x82\xC1\x82\xBD\x83o\x83b\x83t\x83@\x82\xF0\x83\x8A\x83X\x83g\x81i\x93\xFC\x97͏\x87\x81j\x82ւ‚Ȃ\xA2\x82ł\xA8\x82\xAD\x81B
-static void ssh2_channel_add_bufchain(Channel_t *c, unsigned char *buf, unsigned int buflen)
+// \x82\xB1\x82\xB1\x82Ŋm\x95ۂ\xB5\x82\xBD\x83\x81\x83\x82\x83\x8A\x82\xCD ssh2_channel_retry_send_bufchain() \x82ʼn\xF0\x95\xFA\x82\xB7\x82\xE9\x81B
+static void ssh2_channel_add_bufchain(PTInstVar pvar, Channel_t *c, unsigned char *buf, unsigned int buflen)
 {
 	bufchain_t *p, *old;
 
@@ -255,12 +258,22 @@
 			old = old->next;
 		old->next = p;
 	}
+
+	// \x83o\x83b\x83t\x83@\x83T\x83C\x83Y\x82̍\x87\x8Cv\x82\xF0\x8DX\x90V\x82\xB7\x82\xE9(\x8BL\x98^\x97p)
+	c->bufchain_amount += buflen;
+
+	// remote_window\x82̋󂫂\xAA\x82Ȃ\xA2\x82̂ŁAlocal connection\x82\xA9\x82\xE7\x82̃p\x83P\x83b\x83g\x8E\xF3\x90M\x82\xCC
+	// \x92\xE2\x8E~\x8Ew\x8E\xA6\x82\xF0\x8Fo\x82\xB7\x81B\x82\xB7\x82\xAE\x82ɒʒm\x82\xAA\x8E~\x82܂\xE9\x82킯\x82ł͂Ȃ\xA2\x81B
+	FWD_suspend_resume_local_connection(pvar, c, FALSE);
 }
 
+// remote_window\x82̋󂫂\xAA\x82ł\xAB\x82\xBD\x82\xE7\x81A\x83\x8A\x83X\x83g\x82Ɏc\x82\xC1\x82Ă\xA2\x82\xE9\x83f\x81[\x83^\x82\xF0\x8F\x87\x94Ԃɑ\x97\x82\xE9\x81B
+// \x91\x97\x90M\x82\xAA\x82ł\xAB\x82\xBD\x82烁\x83\x82\x83\x8A\x82\xF0\x89\xF0\x95\xFA\x82\xB7\x82\xE9\x81B
 static void ssh2_channel_retry_send_bufchain(PTInstVar pvar, Channel_t *c)
 {
 	bufchain_t *ch;
 	unsigned int size;
+	bufchain_t* ch_origin = c->bufchain;
 
 	while (c->bufchain) {
 		// \x90擪\x82\xA9\x82\xE7\x90\xE6\x82ɑ\x97\x82\xE9
@@ -279,7 +292,16 @@
 
 		buffer_free(ch->msg);
 		free(ch);
+
+		// \x83o\x83b\x83t\x83@\x83T\x83C\x83Y\x82̍\x87\x8Cv\x82\xF0\x8DX\x90V\x82\xB7\x82\xE9(\x8BL\x98^\x97p)
+		c->bufchain_amount -= size;
 	}
+
+	// \x8C\xB3\x81X\x82\xA0\x82\xC1\x82\xBD\x83\x8A\x83X\x83g\x82\xAA\x8B\xF3\x82ɂȂ\xC1\x82\xBD\x82\xE7\x81A
+	// local connection\x82\xA9\x82\xE7\x82̃p\x83P\x83b\x83g\x92ʒm\x82\xF0\x8DĊJ\x82\xB7\x82\xE9\x81B
+	if (ch_origin && c->bufchain == NULL) {
+		FWD_suspend_resume_local_connection(pvar, c, TRUE);
+	}
 }
 
 // channel close\x8E\x9E\x82Ƀ`\x83\x83\x83l\x83\x8B\x8D\\x91\xA2\x91̂\xF0\x83\x8A\x83X\x83g\x82֕ԋp\x82\xB7\x82\xE9
@@ -370,7 +392,7 @@
 // SSH1\x82ŊǗ\x9D\x82\xB5\x82Ă\xA2\x82\xE9channel\x8D\\x91\xA2\x91̂\xA9\x82\xE7\x81ASSH2\x8C\xFC\x82\xAF\x82\xCCChannel_t\x82֕ϊ\xB7\x82\xB7\x82\xE9\x81B
 // TODO: \x8F\xAB\x97\x88\x93I\x82ɂ̓`\x83\x83\x83l\x83\x8B\x8D\\x91\xA2\x91̂\xCD1\x82‚ɓ\x9D\x8D\x87\x82\xB7\x82\xE9\x81B
 // (2005.6.12 yutaka)
-static Channel_t *ssh2_local_channel_lookup(int local_num)
+Channel_t *ssh2_local_channel_lookup(int local_num)
 {
 	int i;
 	Channel_t *c;
@@ -3441,7 +3463,7 @@
 	// \x82\xB1\x82\xEA\x82ɂ\xE6\x82\xE8\x83p\x83P\x83b\x83g\x82\xAA\x89\xF3\x82ꂽ\x82悤\x82Ɍ\xA9\x82\xA6\x82錻\x8Fۂ\xAA\x89\xFC\x91P\x82\xB3\x82\xEA\x82\xE9\x81B
 	// (2012.10.14 yutaka)
 	if (retry == 0 && c->bufchain) {
-		ssh2_channel_add_bufchain(c, buf, buflen);
+		ssh2_channel_add_bufchain(pvar, c, buf, buflen);
 		return;
 	}
 
@@ -3448,7 +3470,7 @@
 	if ((unsigned int)buflen > c->remote_window) {
 		unsigned int offset = 0;
 		// \x91\x97\x82\xEA\x82Ȃ\xA2\x83f\x81[\x83^\x82͂\xA2\x82\xC1\x82\xBD\x82\xF1\x95ۑ\xB6\x82\xB5\x82Ă\xA8\x82\xAD
-		ssh2_channel_add_bufchain(c, buf + offset, buflen - offset);
+		ssh2_channel_add_bufchain(pvar, c, buf + offset, buflen - offset);
 		buflen = offset;
 		return;
 	}

Modified: trunk/ttssh2/ttxssh/ssh.h
===================================================================
--- trunk/ttssh2/ttxssh/ssh.h	2019-06-14 23:40:58 UTC (rev 7770)
+++ trunk/ttssh2/ttxssh/ssh.h	2019-06-15 06:42:23 UTC (rev 7771)
@@ -881,6 +881,8 @@
 	enum channel_type type;
 	int local_num;
 	bufchain_t *bufchain;
+	unsigned long bufchain_amount;
+	BOOL bufchain_recv_suspended;
 	scp_t scp;
 	buffer_t *agent_msg;
 	int agent_request_len;
@@ -892,6 +894,7 @@
 unsigned char *begin_send_packet(PTInstVar pvar, int type, int len);
 void finish_send_packet_special(PTInstVar pvar, int skip_compress);
 void SSH2_send_channel_data(PTInstVar pvar, Channel_t *c, unsigned char *buf, unsigned int buflen, int retry);
+Channel_t* ssh2_local_channel_lookup(int local_num);
 
 #define finish_send_packet(pvar) finish_send_packet_special((pvar), 0)
 #define get_payload_uint32(pvar, offset) get_uint32_MSBfirst((pvar)->ssh_state.payload + (offset))


Ttssh2-commit メーリングリストの案内
Back to archive index