• R/O
  • SSH
  • HTTPS

ttssh2: コミット


コミットメタ情報

リビジョン6027 (tree)
日時2015-09-20 01:51:28
作者(del#24082)

ログメッセージ

全角スペースをASCIIに変換した。

変更サマリ

差分

--- trunk/doc/en/html/reference/sourcecode.html (revision 6026)
+++ trunk/doc/en/html/reference/sourcecode.html (revision 6027)
@@ -63,41 +63,41 @@
6363
6464 <!--
6565 <h2><a name="module">モジュール構成</a></h2>
66- Tera Termパッケージに含まれる実行モジュール(.exeと.dll)の関連図を以下に示します。実行ファイルの拡張子は".exe"になっており、必要に応じてDLLが動的リンクされます。いずれも32ビットプログラム(x86)であるために、x86-64やIA-64といった64ビット環境ではそのまま動作するかどうかは評価されていません。
67- 
66+ Tera Termパッケージに含まれる実行モジュール(.exeと.dll)の関連図を以下に示します。実行ファイルの拡張子は".exe"になっており、必要に応じてDLLが動的リンクされます。いずれも32ビットプログラム(x86)であるために、x86-64やIA-64といった64ビット環境ではそのまま動作するかどうかは評価されていません。
67+
6868 <div align="center">
6969 <img src="image/module_relation.png" width=720 height=540>
7070 </div>
7171
72- 通常、ユーザがデスクトップやスタートメニューからアプリケーションを起動するときに、呼び出される実行ファイルは"ttermpro.exe"になります。実行ファイルはさらに5つのDLLとダイナミックリンクしています。静的リンクを行い、単一のEXEファイルにしていないのは、1つのプロセスのメモリ占有率を抑えるためです。Tera Termでは多数の起動が行われることが想定されるため、初期設計段階からDLLに分割されています。一度読み込まれたDLLは、複数のプロセス間で共有することができます。<br>
73- <br>
74- 
75- マクロスクリプトを実行する際は、"ttpmacro.exe"というまったく別のプロセスが呼び出されます。"ttermpro.exe"とプロセス単位で分けられているのは、マクロを単体で実行できるようにするためです。両プロセス間で、データのやりとりを行うためには、プロセス間通信が必要です。Tera Termでは、DDE(Dynamic Data Exchange)と呼ばれる現在ではレガシーとなってしまったしくみが採用されています。将来のWindowsではDDEがサポートされなくなる可能性があり、その場合Tera Term上でマクロを実行することは一切できなくなります。<br>
76- <br>
77- 
78- TTSSHやTTProxy、TTXKanjiMenuといったプラグイン形式のDLLは、Tera Termの起動時に明示的に LoadLibrary() を使ってダイナミックロードされます。ロード対象となるDLLのファイル名は、TTXInit()#ttplug.c において、"TTX*.DLL"というパターンにマッチしたものとなります。<br>
79- <br>
80- 
81- "keycode.exe"と"ttpmenu.exe"、"LogMeTT.exe"は単体アプリケーションです。<br>
82- <br>
83- 
84- Cygwin接続のしくみについては、別の節で説明します。
72+ 通常、ユーザがデスクトップやスタートメニューからアプリケーションを起動するときに、呼び出される実行ファイルは"ttermpro.exe"になります。実行ファイルはさらに5つのDLLとダイナミックリンクしています。静的リンクを行い、単一のEXEファイルにしていないのは、1つのプロセスのメモリ占有率を抑えるためです。Tera Termでは多数の起動が行われることが想定されるため、初期設計段階からDLLに分割されています。一度読み込まれたDLLは、複数のプロセス間で共有することができます。<br>
73+ <br>
74+
75+ マクロスクリプトを実行する際は、"ttpmacro.exe"というまったく別のプロセスが呼び出されます。"ttermpro.exe"とプロセス単位で分けられているのは、マクロを単体で実行できるようにするためです。両プロセス間で、データのやりとりを行うためには、プロセス間通信が必要です。Tera Termでは、DDE(Dynamic Data Exchange)と呼ばれる現在ではレガシーとなってしまったしくみが採用されています。将来のWindowsではDDEがサポートされなくなる可能性があり、その場合Tera Term上でマクロを実行することは一切できなくなります。<br>
76+ <br>
77+
78+ TTSSHやTTProxy、TTXKanjiMenuといったプラグイン形式のDLLは、Tera Termの起動時に明示的に LoadLibrary() を使ってダイナミックロードされます。ロード対象となるDLLのファイル名は、TTXInit()#ttplug.c において、"TTX*.DLL"というパターンにマッチしたものとなります。<br>
79+ <br>
80+
81+ "keycode.exe"と"ttpmenu.exe"、"LogMeTT.exe"は単体アプリケーションです。<br>
82+ <br>
83+
84+ Cygwin接続のしくみについては、別の節で説明します。
8585
8686 <hr>
8787
8888
8989 <h2><a name="library">ライブラリ構成</a></h2>
90- 高度な機能を実現するために、フルスクラッチで実装することは効率がいいとは言えません。Tera Termでは開発効率化を図るために、オープンソースのライブラリを積極的に利用しています。ただし、オープンソース製品のライセンスによる競合には注意を払う必要があります(特にGPL)。<br>
91- 下図に、オープンソースのライブラリをリンクしているモジュールと、そのリンク状況を示します。Tera Termマクロプログラムにおいて、"waitregex"や"sprintf"コマンドにおいて正規表現を利用するために、Onigurumaと呼ばれる正規表現ライブラリをリンクしています。Tera Term本体では、バージョンダイアログにOnigurumaのバージョンを表示するためだけにリンクをしています。
92- 
90+ 高度な機能を実現するために、フルスクラッチで実装することは効率がいいとは言えません。Tera Termでは開発効率化を図るために、オープンソースのライブラリを積極的に利用しています。ただし、オープンソース製品のライセンスによる競合には注意を払う必要があります(特にGPL)。<br>
91+ 下図に、オープンソースのライブラリをリンクしているモジュールと、そのリンク状況を示します。Tera Termマクロプログラムにおいて、"waitregex"や"sprintf"コマンドにおいて正規表現を利用するために、Onigurumaと呼ばれる正規表現ライブラリをリンクしています。Tera Term本体では、バージョンダイアログにOnigurumaのバージョンを表示するためだけにリンクをしています。
92+
9393 <p>
94- SSHモジュールである"TTSSH"は、暗号処理を行うためにOpenSSLを利用しています。"OpenSSL"というネーミングからWebアクセスに使われるSSL(Secure Socket Layer)プロトコル専用のライブラリかと思われがちですが、基本的な暗号アルゴリズムをサポートしていることから、TTSSHではOpenSSLに含まれる低レイヤのルーチンを利用するだけに留まっています。このことは、すなわちOpenSSLライブラリにセキュリティホールが発見されたとしても、TTSSHへの影響は極めて低いということです。<br>
95- zlibライブラリは、SSHパケットの圧縮を行うために利用しています。ただし、ダイヤルアップ回線などの低速度なネットワークにおいては、パケット圧縮は有効ですが、昨今の高速回線ではむしろ速度低下を招く足かせとなります。ゆえに、デフォルトではパケット圧縮機能は無効化されています。
96- PuTTYは世界標準であるフリーのターミナルエミュレータです。PuTTYに含まれるPageantと呼ばれるSSH認証エージェントがあるのですが、TTSSHでPageantによる公開鍵認証をサポートするために、PuTTYのソースコードを利用しています。
94+ SSHモジュールである"TTSSH"は、暗号処理を行うためにOpenSSLを利用しています。"OpenSSL"というネーミングからWebアクセスに使われるSSL(Secure Socket Layer)プロトコル専用のライブラリかと思われがちですが、基本的な暗号アルゴリズムをサポートしていることから、TTSSHではOpenSSLに含まれる低レイヤのルーチンを利用するだけに留まっています。このことは、すなわちOpenSSLライブラリにセキュリティホールが発見されたとしても、TTSSHへの影響は極めて低いということです。<br>
95+ zlibライブラリは、SSHパケットの圧縮を行うために利用しています。ただし、ダイヤルアップ回線などの低速度なネットワークにおいては、パケット圧縮は有効ですが、昨今の高速回線ではむしろ速度低下を招く足かせとなります。ゆえに、デフォルトではパケット圧縮機能は無効化されています。
96+ PuTTYは世界標準であるフリーのターミナルエミュレータです。PuTTYに含まれるPageantと呼ばれるSSH認証エージェントがあるのですが、TTSSHでPageantによる公開鍵認証をサポートするために、PuTTYのソースコードを利用しています。
9797 </p>
98- 
99- なお、いずれのライブラリも静的リンク(static link)としています。ライブラリのコンパイルオプションには"/MT"を付加しています。動的リンク(dynamic link)を行うと、一部のユーザ環境でTera Termが起動できないという現象が発生したために、現在では動的リンクは行っていません。
100- 
98+
99+ なお、いずれのライブラリも静的リンク(static link)としています。ライブラリのコンパイルオプションには"/MT"を付加しています。動的リンク(dynamic link)を行うと、一部のユーザ環境でTera Termが起動できないという現象が発生したために、現在では動的リンクは行っていません。
100+
101101
102102 <div align="center">
103103 <img src="image/library_relation.png" width=720 height=540>
@@ -176,7 +176,7 @@
176176
177177 Basically, the export function of the plug-in module should be designed not to interfere other plug-in modules. Also, when the plug-in module is called by Tera Term body, the module needs to check the request for own module. <br>
178178 Every export function of plug-in module are as follows:
179- 
179+
180180 <p>
181181 <table border=1 align=center>
182182 <tr>
@@ -265,8 +265,8 @@
265265
266266 </table>
267267 </p>
268- 
269268
269+
270270 <hr>
271271
272272
@@ -273,12 +273,12 @@
273273 <!--
274274
275275 <h2><a name="configuration">設定ファイルの読み書き</a></h2>
276- Windowsではアプリケーションのデータ保存のために、レジストリが伝統的に利用されていますが、Tera Termではその誕生がWindows 3.1までに遡るために、.iniファイルによるローカルディレクトリへの保存方法が標準となっています。<br>
277- パッケージに同梱されるCollectorやLogMeTT、CygTermに関してもローカルディレクトリへデータが保存されます。<br>
278- 例外として、TeraTerm Menuはデフォルトでレジストリへ保存をします。カレントディレクトリに"ttpmenu.ini"(0バイトで可)を設置することで、レジストリの代わりに.iniファイルを使うようにすることもできます。ただし、レジストリから.iniファイルへの移行は自動で行いませんので、手動で再登録してください。<br>
279- <br>
280- 
281- teraterm.iniファイルにエントリを追加した場合は、ReadIniFile()#ttset.cに設定を読み込みするようにします。
276+ Windowsではアプリケーションのデータ保存のために、レジストリが伝統的に利用されていますが、Tera Termではその誕生がWindows 3.1までに遡るために、.iniファイルによるローカルディレクトリへの保存方法が標準となっています。<br>
277+ パッケージに同梱されるCollectorやLogMeTT、CygTermに関してもローカルディレクトリへデータが保存されます。<br>
278+ 例外として、TeraTerm Menuはデフォルトでレジストリへ保存をします。カレントディレクトリに"ttpmenu.ini"(0バイトで可)を設置することで、レジストリの代わりに.iniファイルを使うようにすることもできます。ただし、レジストリから.iniファイルへの移行は自動で行いませんので、手動で再登録してください。<br>
279+ <br>
280+
281+ teraterm.iniファイルにエントリを追加した場合は、ReadIniFile()#ttset.cに設定を読み込みするようにします。
282282
283283 <pre class=code>
284284 ts->ConfirmChangePaste =
@@ -285,7 +285,7 @@
285285 GetOnOff(Section, "ConfirmChangePaste", FName, TRUE);
286286 </pre>
287287
288- WriteIniFile()#ttset.c に設定を書き込みするようにします。
288+ WriteIniFile()#ttset.c に設定を書き込みするようにします。
289289
290290 <pre class=code>
291291 WriteOnOff(Section, "ConfirmChangePaste", FName,
@@ -292,7 +292,7 @@
292292 ts->ConfirmChangePaste);
293293 </pre>
294294
295- エントリに文字列を設定する場合は、Win32APIのGetPrivateProfileString()とWritePrivateProfileString()を使います。数値を扱いたい場合は、GetPrivateProfileInt()とWriteInt()を使います。
295+ エントリに文字列を設定する場合は、Win32APIのGetPrivateProfileString()とWritePrivateProfileString()を使います。数値を扱いたい場合は、GetPrivateProfileInt()とWriteInt()を使います。
296296
297297 <hr>
298298
@@ -301,9 +301,9 @@
301301 <h2><a name="secure">セキュアプログラミング</a></h2>
302302
303303 <h3>文字列操作</h3>
304- WindowsのデフォルトアカウントはAdministrator権限を保持するために(ただし、Windows Vistaには当てはまらない)、アプリケーションにバッファオーバーフローの不具合があると、管理者権限を第三者に奪取されてしまう危険性があります。<br>
305- 従来、C言語の文字列処理は開発者のミスにより、バッファオーバーフローが発生しやすいという状況にありました。そこで、MicrosoftはVisual Studio 2005から文字列処理関数のセキュリティ強化バージョンを提供するようになりました。<br>
306- <br>
304+ WindowsのデフォルトアカウントはAdministrator権限を保持するために(ただし、Windows Vistaには当てはまらない)、アプリケーションにバッファオーバーフローの不具合があると、管理者権限を第三者に奪取されてしまう危険性があります。<br>
305+ 従来、C言語の文字列処理は開発者のミスにより、バッファオーバーフローが発生しやすいという状況にありました。そこで、MicrosoftはVisual Studio 2005から文字列処理関数のセキュリティ強化バージョンを提供するようになりました。<br>
306+ <br>
307307
308308 <ul>
309309 <li><a href="http://msdn2.microsoft.com/ja-jp/library/8ef0s5kh(VS.80).aspx">CRT のセキュリティ強化(MSDNライブラリ)</a></li>
@@ -310,8 +310,8 @@
310310 </ul>
311311 <br>
312312
313- Tera Termではセキュリティ強化を図るため、文字列操作のほとんどをセキュリティ強化バージョンに置き換えています。以下に代替関数を示します。<br>
314- <br>
313+ Tera Termではセキュリティ強化を図るため、文字列操作のほとんどをセキュリティ強化バージョンに置き換えています。以下に代替関数を示します。<br>
314+ <br>
315315
316316 <table border=1 align=center>
317317 <tr>
@@ -334,15 +334,15 @@
334334 <td>strncpy_s()</td>
335335 </tr>
336336 </table>
337- <br>
338- 
339- デフォルトのロケールが適用されると、期待する動作とならないケースにおいては、_snprintf_s_l()を使用しています。<br>
340- いずれの関数においても、_s("secure")という接尾辞が付くため、見た目に区別が付きやすくなっています。当然のことながら、これらの関数はANSI C非互換です。<br>
341- <br>
342- なお、これらの関数を利用する際、Count引数(格納する最大文字数)には"_TRUNCATE"マクロを指定しており、バッファオーバーフローが発生する場合は、強制的にバッファの切り詰めを行っています。
337+ <br>
338+
339+ デフォルトのロケールが適用されると、期待する動作とならないケースにおいては、_snprintf_s_l()を使用しています。<br>
340+ いずれの関数においても、_s("secure")という接尾辞が付くため、見た目に区別が付きやすくなっています。当然のことながら、これらの関数はANSI C非互換です。<br>
341+ <br>
342+ なお、これらの関数を利用する際、Count引数(格納する最大文字数)には"_TRUNCATE"マクロを指定しており、バッファオーバーフローが発生する場合は、強制的にバッファの切り詰めを行っています。
343343 <p>
344344
345- 以下に、strncpy_s()の使用例を示します。strncpy_s()の第2引数(numberOfElements)には、<b>ナル文字(\0)も含めた</b>バッファサイズを指定します。書き込み先のバッファは3バイトしかないので、第3引数(strSource)で指定した5バイトのデータは、2バイトに切り詰められ、buf[]には"he\0"が格納されます。
345+ 以下に、strncpy_s()の使用例を示します。strncpy_s()の第2引数(numberOfElements)には、<b>ナル文字(\0)も含めた</b>バッファサイズを指定します。書き込み先のバッファは3バイトしかないので、第3引数(strSource)で指定した5バイトのデータは、2バイトに切り詰められ、buf[]には"he\0"が格納されます。
346346
347347 <pre class=code>
348348 char buf[3];
@@ -349,8 +349,8 @@
349349 strncpy_s(buf, sizeof(buf), "hello", _TRUNCATE);
350350 </pre>
351351
352- 次に、strncat_s()の使用例を示します。当該関数は、すでに存在する文字列に、さらに文字列を連結するものであるため、第1引数(strDest)は<b>かならずnull-terminateしている</b>必要性があります。strncpy_s()の第2引数(numberOfElements)には、ナル文字(\0)も含めたバッファサイズを指定します。以下の例では、最初の関数を実行すると、5バイト(4文字+ナル文字)が格納されます。2つめの関数を実行する際、残り2バイトしかないので、2文字だけがコピーされ、最終的に"TeraTe"(4文字+2文字+ナル文字)となります。
353- 
352+ 次に、strncat_s()の使用例を示します。当該関数は、すでに存在する文字列に、さらに文字列を連結するものであるため、第1引数(strDest)は<b>かならずnull-terminateしている</b>必要性があります。strncpy_s()の第2引数(numberOfElements)には、ナル文字(\0)も含めたバッファサイズを指定します。以下の例では、最初の関数を実行すると、5バイト(4文字+ナル文字)が格納されます。2つめの関数を実行する際、残り2バイトしかないので、2文字だけがコピーされ、最終的に"TeraTe"(4文字+2文字+ナル文字)となります。
353+
354354 <pre class=code>
355355 char str[7];
356356 str[0] = '\0';
@@ -358,7 +358,7 @@
358358 strncat_s(str, sizeof(str), "Term", _TRUNCATE);
359359 </pre>
360360
361- 最後に、_snprintf_s()です。紛らわしいのが _snprintf() という関数であり、この関数は<b>null-terminateされない</b>ケースがあるため、使用禁止です。以下に、_snprintf_s()の使用例を示します。以下の例では、buf[]には"ab\0"が格納されます。
361+ 最後に、_snprintf_s()です。紛らわしいのが _snprintf() という関数であり、この関数は<b>null-terminateされない</b>ケースがあるため、使用禁止です。以下に、_snprintf_s()の使用例を示します。以下の例では、buf[]には"ab\0"が格納されます。
362362
363363 <pre class=code>
364364 char buf[3];
@@ -374,8 +374,8 @@
374374
375375 <h3>ダイナミックローディング</h3>
376376
377- Windowsのアプリケーションプログラムは、単一のバイナリファイルを変更することなく、新旧のバージョンのWindows上で起動できるようにするためには、アプリケーションプログラム側での工夫が必要です。<br>
378- たとえば、Windows2000で導入された SetLayeredWindowAttributes() APIを直接呼び出すと、WindowsNT4.0や98などではアプリケーションの起動に失敗するようになります。そのため、新しいAPIを呼び出すときは、LoadLibrary()を使って動的ロードするようにします。<br>
377+ Windowsのアプリケーションプログラムは、単一のバイナリファイルを変更することなく、新旧のバージョンのWindows上で起動できるようにするためには、アプリケーションプログラム側での工夫が必要です。<br>
378+ たとえば、Windows2000で導入された SetLayeredWindowAttributes() APIを直接呼び出すと、WindowsNT4.0や98などではアプリケーションの起動に失敗するようになります。そのため、新しいAPIを呼び出すときは、LoadLibrary()を使って動的ロードするようにします。<br>
379379
380380 <pre class=code>
381381 static BOOL MySetLayeredWindowAttributes(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags)
@@ -401,7 +401,7 @@
401401 }
402402 </pre>
403403
404- いちいち、手で関数プロトタイプを書いていくのは面倒である場合は、「DLLの遅延読み込み」というしくみを利用すると、上記のような手順は不要です。いきなり、関数を呼び出すことができます。ダイレクトに呼び出したい関数がある場合、それが古いWindowsではサポートされていないものであるならば、Visual Studioのプロジェクト設定で、「DLLの遅延読み込み」に該当するDLLを指定しておきます。
404+ いちいち、手で関数プロトタイプを書いていくのは面倒である場合は、「DLLの遅延読み込み」というしくみを利用すると、上記のような手順は不要です。いきなり、関数を呼び出すことができます。ダイレクトに呼び出したい関数がある場合、それが古いWindowsではサポートされていないものであるならば、Visual Studioのプロジェクト設定で、「DLLの遅延読み込み」に該当するDLLを指定しておきます。
405405
406406
407407 <h3>Windows 95</h3>
@@ -421,10 +421,10 @@
421421
422422 <h2><a name="debug">デバッグ手法</a></h2>
423423 <h3>debug printf</h3>
424- Windowsアプリケーションでは printf() が使えません。標準出力がどこにも割り当てられていないからです。AllocConsole()とfreopen()を使えば、Windowsアプリケーションにおいても printf() を利用することができます。<br>
425- OutputDebugString()というAPIがあります。これは Visual Studio のデバッグコンソールにメッセージ出力することができる関数です。当該APIは、"Debug build"および"Release build"に関係なく、デバッガが存在すれば、メッセージを送信します。ゆえに、 Visual Studioがなくとも、<a href="http://www.vector.co.jp/soft/win95/prog/se046776.html">DBCon</a>のようなツールを使えば、アプリケーションの単体起動においても、OutputDebugString()によるメッセージを拾うことができます。<br>
426- Tera Termでは、可変長引数を扱えるようにラッパー関数を用意しています。
427- 
424+ Windowsアプリケーションでは printf() が使えません。標準出力がどこにも割り当てられていないからです。AllocConsole()とfreopen()を使えば、Windowsアプリケーションにおいても printf() を利用することができます。<br>
425+ OutputDebugString()というAPIがあります。これは Visual Studio のデバッグコンソールにメッセージ出力することができる関数です。当該APIは、"Debug build"および"Release build"に関係なく、デバッガが存在すれば、メッセージを送信します。ゆえに、 Visual Studioがなくとも、<a href="http://www.vector.co.jp/soft/win95/prog/se046776.html">DBCon</a>のようなツールを使えば、アプリケーションの単体起動においても、OutputDebugString()によるメッセージを拾うことができます。<br>
426+ Tera Termでは、可変長引数を扱えるようにラッパー関数を用意しています。
427+
428428 <pre class=code>
429429 void OutputDebugPrintf(char *fmt, ...) {
430430 char tmp[1024];
@@ -436,7 +436,7 @@
436436 </pre>
437437
438438 <h3>memory leak</h3>
439- malloc()等による確保したヒープメモリの解放し忘れによる「メモリリーク」を、自動で検出するしくみが Visual Studio には用意されています。プログラムの起動時に、以下のコードを挿入するだけです。プログラムの終了時に、解放していないヒープメモリがあれば、 Visual Studio の「出力」ウィンドウにリストアップされます。
439+ malloc()等による確保したヒープメモリの解放し忘れによる「メモリリーク」を、自動で検出するしくみが Visual Studio には用意されています。プログラムの起動時に、以下のコードを挿入するだけです。プログラムの終了時に、解放していないヒープメモリがあれば、 Visual Studio の「出力」ウィンドウにリストアップされます。
440440
441441 <pre class=code>
442442 #ifdef _DEBUG
@@ -444,14 +444,14 @@
444444 #endif
445445 </pre>
446446
447- なお、Windowsのように仮想記憶で動くアプリケーションプログラムに関しては、プログラムの終了時に解放されていないメモリが存在した場合、OSが面倒を見て、メモリが解放されるようになっています。
447+ なお、Windowsのように仮想記憶で動くアプリケーションプログラムに関しては、プログラムの終了時に解放されていないメモリが存在した場合、OSが面倒を見て、メモリが解放されるようになっています。
448448
449449 <hr>
450450
451451
452452 <h2><a name="thread">マルチスレッド</a></h2>
453- Windowsのアプリケーションはマルチスレッドで設計されることがほとんどですが、Windows 3.1から95の時代ではあまり一般的ではありませんでした。そのため、元々Tera Termはマルチスレッド化されていません。ソースコードを見ると分かるように、グローバル変数が多用されているため、ほとんどの処理がスレッドセーフではありません。<br>
454- ただし、一部の処理においては _beginthreadex() API を使ってスレッドが生成されています。以下にスレッド生成箇所を示します。
453+ Windowsのアプリケーションはマルチスレッドで設計されることがほとんどですが、Windows 3.1から95の時代ではあまり一般的ではありませんでした。そのため、元々Tera Termはマルチスレッド化されていません。ソースコードを見ると分かるように、グローバル変数が多用されているため、ほとんどの処理がスレッドセーフではありません。<br>
454+ ただし、一部の処理においては _beginthreadex() API を使ってスレッドが生成されています。以下にスレッド生成箇所を示します。
455455
456456 <p>
457457 <div align=center><b>Tera Term</b></div>
@@ -503,9 +503,9 @@
503503 </table>
504504 </p>
505505
506- すでに説明したとおり、Tera Term(TTSSH含む)の内部処理はスレッドセーフではないため、シンプルにスレッドを生成し、スレッド内から送受信処理等を行おうとすると、不具合が発生してしまいます。<br>
507- TELNETやSSHのキープアライブ(ハートビート)処理を実現するためには、定期的にパケットの送信処理を行う必要があります。また、SCPによるファイル送受信を行う際においても、ファイルの送信処理中に、ユーザの端末操作のレスポンスを落とさないために、スレッドの使用が不可欠です。<br>
508- そこで、マルチスレッドを使う場合は、モードレスダイアログを非表示で作成したあとに、_beginthreadex() APIでスレッドを生成し、実際の処理はモードレスダイアログに行わせるという手段を使用しています。このしくみにより、マルチスレッドを使いながら、スレッドセーフを保つことができます。以下に、コード例を示します。<br>
506+ すでに説明したとおり、Tera Term(TTSSH含む)の内部処理はスレッドセーフではないため、シンプルにスレッドを生成し、スレッド内から送受信処理等を行おうとすると、不具合が発生してしまいます。<br>
507+ TELNETやSSHのキープアライブ(ハートビート)処理を実現するためには、定期的にパケットの送信処理を行う必要があります。また、SCPによるファイル送受信を行う際においても、ファイルの送信処理中に、ユーザの端末操作のレスポンスを落とさないために、スレッドの使用が不可欠です。<br>
508+ そこで、マルチスレッドを使う場合は、モードレスダイアログを非表示で作成したあとに、_beginthreadex() APIでスレッドを生成し、実際の処理はモードレスダイアログに行わせるという手段を使用しています。このしくみにより、マルチスレッドを使いながら、スレッドセーフを保つことができます。以下に、コード例を示します。<br>
509509
510510 <pre class=code>
511511 #define WM_SEND_HEARTBEAT (WM_USER + 1)
@@ -579,9 +579,9 @@
579579
580580 <h2><a name="dde">DDEによるプロセス間通信</a></h2>
581581 <h3>概要</h3>
582- DDE(Dynamic Data Exchange)の誕生は、1987年のWindows 2.0までに遡ります。DDEはプロセス間通信を行うためのしくみですが、現在ではレガシーな方式であり、ほとんどのアプリケーションでは利用されていません。Windowsにおけるプロセス間通信といえば、メールスロットや名前付きパイプ、OLEなどが定番です。<br>
583- かつては、DDEによるプロセス間の通信データをキャプチャすることができる「DDEスパイ」(DDESPY.EXE)というツールがVisual Studioに付属していましたが、現在のVisual Studioにはもはや含まれていません。<br>
584- DDEに関するリファレンスはMSDNライブラリから参照することができます。<br>
582+ DDE(Dynamic Data Exchange)の誕生は、1987年のWindows 2.0までに遡ります。DDEはプロセス間通信を行うためのしくみですが、現在ではレガシーな方式であり、ほとんどのアプリケーションでは利用されていません。Windowsにおけるプロセス間通信といえば、メールスロットや名前付きパイプ、OLEなどが定番です。<br>
583+ かつては、DDEによるプロセス間の通信データをキャプチャすることができる「DDEスパイ」(DDESPY.EXE)というツールがVisual Studioに付属していましたが、現在のVisual Studioにはもはや含まれていません。<br>
584+ DDEに関するリファレンスはMSDNライブラリから参照することができます。<br>
585585
586586 <p>
587587 <ul>
@@ -590,15 +590,15 @@
590590 </ul>
591591 </p>
592592
593- DDEは、TCPによるネットワーク通信と似ており、サーバとクライアント間を一対一で接続し、通信を行います。アプリケーションがDDEによる通信を行うために、DDEML(Dynamic Data Exchange Management Library)と呼ばれるライブラリをWin32 APIとして提供されています。<br>
594- DDE通信を行うために、一方がサーバとなり、他方がクライアントになる必要があります。また、通信のセッションをシステム全体でユニークとするために、識別情報が必要です。TCP通信ではIPアドレスとポート番号が使われますが、DDE通信では「サービス名」と「トピック名」の組み合わせが使われます。Tera Termではサービス名は"TERATERM"という文字列が使われ、トピック名はTera Term本体のウィンドウハンドル(HVTWin)の16進数値を文字列化したものが使われています。<br>
595- このようなしくみになっているために、マクロスクリプトからまったく別のTera Termへコマンドを送ることはできません。<br>
593+ DDEは、TCPによるネットワーク通信と似ており、サーバとクライアント間を一対一で接続し、通信を行います。アプリケーションがDDEによる通信を行うために、DDEML(Dynamic Data Exchange Management Library)と呼ばれるライブラリをWin32 APIとして提供されています。<br>
594+ DDE通信を行うために、一方がサーバとなり、他方がクライアントになる必要があります。また、通信のセッションをシステム全体でユニークとするために、識別情報が必要です。TCP通信ではIPアドレスとポート番号が使われますが、DDE通信では「サービス名」と「トピック名」の組み合わせが使われます。Tera Termではサービス名は"TERATERM"という文字列が使われ、トピック名はTera Term本体のウィンドウハンドル(HVTWin)の16進数値を文字列化したものが使われています。<br>
595+ このようなしくみになっているために、マクロスクリプトからまったく別のTera Termへコマンドを送ることはできません。<br>
596596
597597 <div align="center">
598598 <img src="image/dde.png" width=720 height=540>
599599 </div>
600600
601- 上図に示すように、Tera Term本体("ttermpro.exe")がDDEサーバとなり、マクロプログラム("ttpmacro.exe")がDDEクライアントとなります。DDEでは、やりとりするデータの塊のことを「トランザクション」と呼びます。トランザクションには以下に示すような何種類かがあります。タイプは"ddeml.h"でマクロ定義されています。<br>
601+ 上図に示すように、Tera Term本体("ttermpro.exe")がDDEサーバとなり、マクロプログラム("ttpmacro.exe")がDDEクライアントとなります。DDEでは、やりとりするデータの塊のことを「トランザクション」と呼びます。トランザクションには以下に示すような何種類かがあります。タイプは"ddeml.h"でマクロ定義されています。<br>
602602
603603 <p>
604604 <table border=1 align=center>
@@ -635,12 +635,12 @@
635635 </table>
636636 </p>
637637
638- DDE通信の特徴として、アドバイズループ(advise loop)という概念があります。DDEサーバがアドバイズループに入ると、クライアントはサーバから定期的にデータを受け取り続けることができます。Tera Termでは、リモートホストからの受信データを、マクロプログラムへ渡すために、アドバイズループが使われています。<br>
638+ DDE通信の特徴として、アドバイズループ(advise loop)という概念があります。DDEサーバがアドバイズループに入ると、クライアントはサーバから定期的にデータを受け取り続けることができます。Tera Termでは、リモートホストからの受信データを、マクロプログラムへ渡すために、アドバイズループが使われています。<br>
639639
640640 <h3>ライブラリ</h3>
641- Tera Termで使われているDDEMLについて、以下に示します。
642- 
643- 
641+ Tera Termで使われているDDEMLについて、以下に示します。
642+
643+
644644 <p>
645645 <table border=1 align=center>
646646 <tr>
@@ -704,10 +704,10 @@
704704
705705
706706 <h3>実装</h3>
707- DDEサーバ側の実装について見ていきます。Tera Term本体("ttermpro.exe")がDDEサーバとなり、かならずDDEサーバから起動されます。マクロプログラム("ttpmacro.exe")から直接マクロスクリプトが実行されるケースにおいても、"connect"マクロによりDDE接続をしないと、通信が開始できません。<br>
708- Tera TermのControlメニューからMacroを呼び出した場合、RunMacro()#ttdde.c がコールされます。<br>
709- HVTWinウィンドウハンドルからトピック名(8バイト)を作成し、DDEの初期化とサーバの登録を行います。また、このタイミングでDDEバッファ(1KB)を作成しています。その後、"ttpmacro.exe"を /D= オプションでトピック名を渡しつつ、起動をします。<br>
710- 
707+ DDEサーバ側の実装について見ていきます。Tera Term本体("ttermpro.exe")がDDEサーバとなり、かならずDDEサーバから起動されます。マクロプログラム("ttpmacro.exe")から直接マクロスクリプトが実行されるケースにおいても、"connect"マクロによりDDE接続をしないと、通信が開始できません。<br>
708+ Tera TermのControlメニューからMacroを呼び出した場合、RunMacro()#ttdde.c がコールされます。<br>
709+ HVTWinウィンドウハンドルからトピック名(8バイト)を作成し、DDEの初期化とサーバの登録を行います。また、このタイミングでDDEバッファ(1KB)を作成しています。その後、"ttpmacro.exe"を /D= オプションでトピック名を渡しつつ、起動をします。<br>
710+
711711 <pre class=code>
712712 SetTopic();
713713 if (! InitDDE()) return;
@@ -715,10 +715,10 @@
715715 strncat_s(Cmnd,sizeof(Cmnd),TopicName,_TRUNCATE);
716716 </pre>
717717
718- DDEサーバに、DDEクライアントからトランザクションが送られてきたときは、DdeCallbackProcコールバック関数が呼び出されます。コールバック関数は、DdeInitialize()でDDEの初期化を行うときに登録されます。<br><br>
719- 
720- 次に、DDEクライアントについて見てみましょう。マクロプログラムの起動時、InitDDE()#ttmdde.c が呼び出され、DDEクライアントとして初期化が行われます。DDEの初期化は、DdeInitialize()で行われ、同時にDdeCallbackProcコールバック関数が登録されます。DDEサーバから届いたトランザクションは、コールバック関数で処理されます。<br>
721- DDE通信を始めるためには、DdeConnect()を呼び出し、サーバと接続する必要があります。次に、"ttpmacro.exe"のウィンドウハンドル(HWin)をサーバへ通知するために、XTYP_EXECUTEトランザクションで送ります。最後に、XTYP_ADVSTARTトランザクションをサーバへ送り、アドバイズループを開始します。<br>
718+ DDEサーバに、DDEクライアントからトランザクションが送られてきたときは、DdeCallbackProcコールバック関数が呼び出されます。コールバック関数は、DdeInitialize()でDDEの初期化を行うときに登録されます。<br><br>
719+
720+ 次に、DDEクライアントについて見てみましょう。マクロプログラムの起動時、InitDDE()#ttmdde.c が呼び出され、DDEクライアントとして初期化が行われます。DDEの初期化は、DdeInitialize()で行われ、同時にDdeCallbackProcコールバック関数が登録されます。DDEサーバから届いたトランザクションは、コールバック関数で処理されます。<br>
721+ DDE通信を始めるためには、DdeConnect()を呼び出し、サーバと接続する必要があります。次に、"ttpmacro.exe"のウィンドウハンドル(HWin)をサーバへ通知するために、XTYP_EXECUTEトランザクションで送ります。最後に、XTYP_ADVSTARTトランザクションをサーバへ送り、アドバイズループを開始します。<br>
722722
723723 <pre class=code>
724724 ConvH = DdeConnect(Inst, Service, Topic, NULL);
@@ -740,38 +740,38 @@
740740
741741
742742 <h3>バッファの管理</h3>
743- マクロプログラムでは"wait"コマンド等で、リモートホストから送られてきたデータを監視するための機能が用意されています。この機能を実現するためには、Tera Term本体とマクロプログラムのそれぞれにおいて、バッファを用意する必要があり、プロセス間通信(DDEトランザクション)により、Tera Term本体からマクロプログラムへリモートホストからの受信データを送らなければなりません。<br>
743+ マクロプログラムでは"wait"コマンド等で、リモートホストから送られてきたデータを監視するための機能が用意されています。この機能を実現するためには、Tera Term本体とマクロプログラムのそれぞれにおいて、バッファを用意する必要があり、プロセス間通信(DDEトランザクション)により、Tera Term本体からマクロプログラムへリモートホストからの受信データを送らなければなりません。<br>
744744
745745 <div align="center">
746746 <img src="image/dde_flowcontrol.png" width=720 height=540>
747747 </div>
748748
749- まず、Tera Term本体におけるリモートホストからのTCPパケット受信は、アイドルループ OnIdle()#teraterm.cpp にて行われます。OnIdle()から呼び出される CommReceive()#commlib.c において、TCPパケットデータをバッファ(cv->InBuff[])に格納します。このバッファは 1KB の大きさを持ちます。また、リングバッファではないため、バッファフルになった場合は、TCPパケットの受信をしません。ただし、バッファフル状態が長く続くと、Windowsカーネル内にTCPパケットが溜まっていき、いずれはリモートホストからのパケットを受信できなくなる可能性があります。<br>
750- エスケープシーケンスの解析処理を行う過程で、「ログ採取」か「マクロ実行」を行っている場合は、LogPut1()が呼び出され、DDEバッファ(cv.LogBuf[])へ受信データが格納されます。すなわち、ログ採取とマクロ実行におけるバッファは共通です。このバッファは1KBの大きさを持つリングバッファであり、バッファフルになった場合は、最古のデータから上書きされてゆきます。<br>
751- なお、バイナリモードでログ採取においては、cv.BinBuf[] という別のバッファへデータが格納されますので、DDEバッファとは別物です。言い換えると、バイナリモードにおけるデータをDDE通信させることはできないということです。単純な"wait"コマンドでは、バイナリデータ(制御コードなど)を待つことはできません。<br>
752- Tera Term本体のDDEバッファのデータは、エスケープシーケンスの解析処理が完了後、DDEAdv()#ttdde.c がすぐに呼び出され、自分自身(DDEサーバ)へ XTYP_ADVREQ トランザクションを送ります。XTYP_ADVREQを受け取ったら、DDEコールバック関数 DdeCallbackProc() が呼び出され、マクロプログラムへのデータ送信を行います。ここでアドバイズループが使われています。<br>
749+ まず、Tera Term本体におけるリモートホストからのTCPパケット受信は、アイドルループ OnIdle()#teraterm.cpp にて行われます。OnIdle()から呼び出される CommReceive()#commlib.c において、TCPパケットデータをバッファ(cv->InBuff[])に格納します。このバッファは 1KB の大きさを持ちます。また、リングバッファではないため、バッファフルになった場合は、TCPパケットの受信をしません。ただし、バッファフル状態が長く続くと、Windowsカーネル内にTCPパケットが溜まっていき、いずれはリモートホストからのパケットを受信できなくなる可能性があります。<br>
750+ エスケープシーケンスの解析処理を行う過程で、「ログ採取」か「マクロ実行」を行っている場合は、LogPut1()が呼び出され、DDEバッファ(cv.LogBuf[])へ受信データが格納されます。すなわち、ログ採取とマクロ実行におけるバッファは共通です。このバッファは1KBの大きさを持つリングバッファであり、バッファフルになった場合は、最古のデータから上書きされてゆきます。<br>
751+ なお、バイナリモードでログ採取においては、cv.BinBuf[] という別のバッファへデータが格納されますので、DDEバッファとは別物です。言い換えると、バイナリモードにおけるデータをDDE通信させることはできないということです。単純な"wait"コマンドでは、バイナリデータ(制御コードなど)を待つことはできません。<br>
752+ Tera Term本体のDDEバッファのデータは、エスケープシーケンスの解析処理が完了後、DDEAdv()#ttdde.c がすぐに呼び出され、自分自身(DDEサーバ)へ XTYP_ADVREQ トランザクションを送ります。XTYP_ADVREQを受け取ったら、DDEコールバック関数 DdeCallbackProc() が呼び出され、マクロプログラムへのデータ送信を行います。ここでアドバイズループが使われています。<br>
753753
754754 <div align="center">
755755 <img src="image/dde_buffer.png" width=720 height=540>
756756 </div>
757757
758- アドバイズループによりDDEサーバよりデータが送られてくると、DDEクライアントであるマクロプログラムにおいては、XTYP_ADVDATAトランザクションがDDEコールバック関数 DdeCallbackProc()#ttmdde.c により処理されます。<br>
759- 
760- なお、Tera Term本体において、DDE通信用のバッファと、ログ採取用のバッファは cv.LogBuf[] で共有されています。バッファの先頭とデータサイズを表すインデックスは、DDE通信の場合は"DStart"と"Dcount"、ログ採取の場合は"LStart"と"Lcount"と区別されています。実際には、1つのバッファを共有しているわけなので、それぞれのインデックスが食い違うと、誤動作する原因となるため、常に同期を取っておくことになります。<br>
758+ アドバイズループによりDDEサーバよりデータが送られてくると、DDEクライアントであるマクロプログラムにおいては、XTYP_ADVDATAトランザクションがDDEコールバック関数 DdeCallbackProc()#ttmdde.c により処理されます。<br>
759+
760+ なお、Tera Term本体において、DDE通信用のバッファと、ログ採取用のバッファは cv.LogBuf[] で共有されています。バッファの先頭とデータサイズを表すインデックスは、DDE通信の場合は"DStart"と"Dcount"、ログ採取の場合は"LStart"と"Lcount"と区別されています。実際には、1つのバッファを共有しているわけなので、それぞれのインデックスが食い違うと、誤動作する原因となるため、常に同期を取っておくことになります。<br>
761761 <hr>
762762
763763
764764 <h2><a name="ttssh">TTSSHによるSSHの設計と実装</a></h2>
765765 <h3>概要</h3>
766- オリジナルのTTSSHは<a href="http://www.cs.cmu.edu/People/roc/">Robert O'Callahan</a>氏(現在は<a href="http://weblogs.mozillazine.org/roc/">Mozilla hacker</a>として活躍)により開発されたプラグインです。SSH1へ対応しており、ポートフォワーディングやzlibによるパケット圧縮もサポートしていました。TTSSHは、Tera Termをセキュア通信に対応させるためのプラグインであったために、SCPやSFTP等には未対応でした。オリジナルTera Termが1998年に開発凍結後も、2001年ごろまでメンテナンスが続けられていました。<br>
767- TTSSHのSSH2対応を実現するために、TeraTerm Projectにより2004年から設計と実装が始められました。3年の歳月をかけて、ほぼSSH2プロトコルのフルサポートを実現しました。現在ではSCPへも対応しています。将来的にはSFTPへも対応されるかもしれません。<br>
768- 原則、TTSSHの実装は<a href="http://www.openssh.com/">OpenSSH</a>を参考にしています。一部、コードをそのまま流用しているところもあります。ただし、OpenSSHはUNIXのコマンドライン向けに設計されているため、Tera TermのようなWindowsアプリケーションにはそのまま適合しない箇所も多く、フレームワークとしてはOpenSSHと大きく異なったものとなっています。<br>
766+ オリジナルのTTSSHは<a href="http://www.cs.cmu.edu/People/roc/">Robert O'Callahan</a>氏(現在は<a href="http://weblogs.mozillazine.org/roc/">Mozilla hacker</a>として活躍)により開発されたプラグインです。SSH1へ対応しており、ポートフォワーディングやzlibによるパケット圧縮もサポートしていました。TTSSHは、Tera Termをセキュア通信に対応させるためのプラグインであったために、SCPやSFTP等には未対応でした。オリジナルTera Termが1998年に開発凍結後も、2001年ごろまでメンテナンスが続けられていました。<br>
767+ TTSSHのSSH2対応を実現するために、TeraTerm Projectにより2004年から設計と実装が始められました。3年の歳月をかけて、ほぼSSH2プロトコルのフルサポートを実現しました。現在ではSCPへも対応しています。将来的にはSFTPへも対応されるかもしれません。<br>
768+ 原則、TTSSHの実装は<a href="http://www.openssh.com/">OpenSSH</a>を参考にしています。一部、コードをそのまま流用しているところもあります。ただし、OpenSSHはUNIXのコマンドライン向けに設計されているため、Tera TermのようなWindowsアプリケーションにはそのまま適合しない箇所も多く、フレームワークとしてはOpenSSHと大きく異なったものとなっています。<br>
769769
770770
771771 <h3>SSHプロトコル</h3>
772- SSH(Secure Shell)は、バージョン1(厳密には1.5)とバージョン2が存在し、略して"SSH1"および"SSH2"と呼ばれます。それらのバージョン間にはプロトコル仕様としての互換性はありません。SSH1にはセキュリティ上の問題があるために、現在はほとんど利用されません。<br>
773- SSH2プロトコルの仕様に関しては、RFC化されています。
774- 
772+ SSH(Secure Shell)は、バージョン1(厳密には1.5)とバージョン2が存在し、略して"SSH1"および"SSH2"と呼ばれます。それらのバージョン間にはプロトコル仕様としての互換性はありません。SSH1にはセキュリティ上の問題があるために、現在はほとんど利用されません。<br>
773+ SSH2プロトコルの仕様に関しては、RFC化されています。
774+
775775 <p>
776776 <ul>
777777 <li><a href="http://www.ietf.org/rfc/rfc4250.txt">RFC4250: The Secure Shell (SSH) Protocol Assigned Numbers</a></li>
@@ -788,7 +788,7 @@
788788
789789
790790 <h3>接続処理</h3>
791- TTSSHは、Tera Termの一部のコードでもあるため、ネットワーク接続処理はTera TermとTTSSHの間を行き来することになり、処理の流れが複雑になっています。また、SSHプロトコルそのもののフローを熟知していないと、TTSSHのシーケンスを追っていくのが難しくなっています。以下に、リモートホストへの接続を行うまでのフローを示します。<br>
791+ TTSSHは、Tera Termの一部のコードでもあるため、ネットワーク接続処理はTera TermとTTSSHの間を行き来することになり、処理の流れが複雑になっています。また、SSHプロトコルそのもののフローを熟知していないと、TTSSHのシーケンスを追っていくのが難しくなっています。以下に、リモートホストへの接続を行うまでのフローを示します。<br>
792792
793793 <div align="center">
794794 <img src="image/ssh.png" width=720 height=540>
@@ -820,18 +820,18 @@
820820 }
821821 </pre>
822822
823- SSH通信に載せられて、実際にパケットが送出されるのは、finish_send_packet()から呼び出される finish_send_packet_special() です。パケットを送信するときのフォーマットについて、以下に示します。共通鍵暗号でパケットデータを暗号化する前に、ヘッダとフッタを付ける必要があります。<br>
824- パケットサイズはHMACを除く長さです。パケットサイズそのものはビッグエンディアン形式で、4バイト分格納しますが、その"4"バイトは含まれません。ペイロードの直後にパディングを埋めるのは、共通鍵暗号で暗号化するときに「ブロックサイズ単位」になっていなければ、アルゴリズム的に暗号化できないからです。ブロックサイズは暗号アルゴリズムにより異なり、たとえば3DES-CBCならば24バイト、AES128ならば16バイトです。<br>
825- HMAC(Keyed-Hashing for Message Authentication)は、暗号化本文に対するハッシュです。ハッシュのアルゴリズムは選択可能であり、"MD5"や"SHA-1"がよく使われています。HMACを付加することにより、「第三者によるデータの改ざん」を検出することができます。HMACは、暗号化対象となる本文を秘密鍵とシーケンス番号を加え、ハッシュ値を計算します。秘密鍵とシーケンス番号を加えることにより、第三者がデータをまるごと差し替えたとしても、送信者が生成したハッシュ値を復元することは理論上できません。<br>
826- 
823+ SSH通信に載せられて、実際にパケットが送出されるのは、finish_send_packet()から呼び出される finish_send_packet_special() です。パケットを送信するときのフォーマットについて、以下に示します。共通鍵暗号でパケットデータを暗号化する前に、ヘッダとフッタを付ける必要があります。<br>
824+ パケットサイズはHMACを除く長さです。パケットサイズそのものはビッグエンディアン形式で、4バイト分格納しますが、その"4"バイトは含まれません。ペイロードの直後にパディングを埋めるのは、共通鍵暗号で暗号化するときに「ブロックサイズ単位」になっていなければ、アルゴリズム的に暗号化できないからです。ブロックサイズは暗号アルゴリズムにより異なり、たとえば3DES-CBCならば24バイト、AES128ならば16バイトです。<br>
825+ HMAC(Keyed-Hashing for Message Authentication)は、暗号化本文に対するハッシュです。ハッシュのアルゴリズムは選択可能であり、"MD5"や"SHA-1"がよく使われています。HMACを付加することにより、「第三者によるデータの改ざん」を検出することができます。HMACは、暗号化対象となる本文を秘密鍵とシーケンス番号を加え、ハッシュ値を計算します。秘密鍵とシーケンス番号を加えることにより、第三者がデータをまるごと差し替えたとしても、送信者が生成したハッシュ値を復元することは理論上できません。<br>
826+
827827
828828 <div align="center">
829829 <img src="image/ssh_packet_format1.png" width=720 height=540>
830830 </div>
831831
832- zlibによるパケット圧縮を行う場合における、パケットを送信するときのフォーマットについて、以下に示します。パケット圧縮を行うのは、「ペイロード」の部分のみで、残りは通常の送信パケットとフォーマットは同じです。なお、パケットを圧縮したとしても、かならずしも元のサイズよりも小さくなるとは限らないので、そのことを考慮したバッファ管理が必要です。<br>
833- パケット圧縮送信で難しいのは、圧縮を開始するタイミングです。ローカルホストからリモートホストへのSSH接続を開始すると、実にたくさんのネゴシエーションが行われますが、パケットを圧縮してよいのは決められたタイミングであり、このタイミングを間違えると、サーバとまったく通信ができなくなります。<br>
834- 通常のパケット圧縮の場合は、"SSH2_MSG_KEXINIT"を受信したタイミングです。遅延パケット圧縮の場合は、ユーザ認証が成功したタイミング("SSH2_MSG_USERAUTH_SUCCESS"を受信した時)です。遅延パケット圧縮というのは、それまで"SSH2_MSG_KEXINIT"を受信したタイミングで圧縮を開始していたのを、ユーザ認証が完了するまで延長する方式です。遅延パケット圧縮は、zlibライブラリのセキュリティホールにより、不正なSSHサーバへ接続しただけで、クライアント側に影響が出るのを回避するためのしくみです。
832+ zlibによるパケット圧縮を行う場合における、パケットを送信するときのフォーマットについて、以下に示します。パケット圧縮を行うのは、「ペイロード」の部分のみで、残りは通常の送信パケットとフォーマットは同じです。なお、パケットを圧縮したとしても、かならずしも元のサイズよりも小さくなるとは限らないので、そのことを考慮したバッファ管理が必要です。<br>
833+ パケット圧縮送信で難しいのは、圧縮を開始するタイミングです。ローカルホストからリモートホストへのSSH接続を開始すると、実にたくさんのネゴシエーションが行われますが、パケットを圧縮してよいのは決められたタイミングであり、このタイミングを間違えると、サーバとまったく通信ができなくなります。<br>
834+ 通常のパケット圧縮の場合は、"SSH2_MSG_KEXINIT"を受信したタイミングです。遅延パケット圧縮の場合は、ユーザ認証が成功したタイミング("SSH2_MSG_USERAUTH_SUCCESS"を受信した時)です。遅延パケット圧縮というのは、それまで"SSH2_MSG_KEXINIT"を受信したタイミングで圧縮を開始していたのを、ユーザ認証が完了するまで延長する方式です。遅延パケット圧縮は、zlibライブラリのセキュリティホールにより、不正なSSHサーバへ接続しただけで、クライアント側に影響が出るのを回避するためのしくみです。
835835
836836
837837 <div align="center">
@@ -840,16 +840,16 @@
840840
841841
842842 <h3>受信パケット処理</h3>
843- パケットの受信は、TeraTerm本体側からは recv ソケット関数を呼び出した場合に、それがTELNETなのかSSHなのかを意識させないような設計になっていることと、 recv ソケット関数の呼び出しでは、かならずしも十分なバッファサイズが指定されてくるとは限らないため、少々実装が複雑になっています。<br>
843+ パケットの受信は、TeraTerm本体側からは recv ソケット関数を呼び出した場合に、それがTELNETなのかSSHなのかを意識させないような設計になっていることと、 recv ソケット関数の呼び出しでは、かならずしも十分なバッファサイズが指定されてくるとは限らないため、少々実装が複雑になっています。<br>
844844
845845 <div align="center">
846846 <img src="image/ssh_recv_packet.png" width=720 height=540>
847847 </div>
848848
849- TeraTerm本体側は OnIdle()#teraterm.cpp というアイドルループにおいて、常時パケットの受信がないかをポーリングしています。それが CommReceive() で、recv()を呼び出します。recv()はTTSSHによりフックされているので、ソケット関数ではなく、TTXrecv()#ttxssh.c が呼び出されます。<br>
850- CommReceive()は recv() を呼び出す際に、バッファ(cv->InBuff[])の空きポインタとサイズを引数に渡します。バッファサイズは 1KB です。つまり、TTXrecv()のサイズには、1~1024 までの数値が渡される可能性があるということです。<br>
851- TTXrecv()から呼び出される PKT_recv() は、少々複雑なループ処理となっています。SSH接続を初めて行うときのシーケンスを以下に示します。
852- 
849+ TeraTerm本体側は OnIdle()#teraterm.cpp というアイドルループにおいて、常時パケットの受信がないかをポーリングしています。それが CommReceive() で、recv()を呼び出します。recv()はTTSSHによりフックされているので、ソケット関数ではなく、TTXrecv()#ttxssh.c が呼び出されます。<br>
850+ CommReceive()は recv() を呼び出す際に、バッファ(cv->InBuff[])の空きポインタとサイズを引数に渡します。バッファサイズは 1KB です。つまり、TTXrecv()のサイズには、1~1024 までの数値が渡される可能性があるということです。<br>
851+ TTXrecv()から呼び出される PKT_recv() は、少々複雑なループ処理となっています。SSH接続を初めて行うときのシーケンスを以下に示します。
852+
853853 <ol>
854854 <li>recv_data() で本当の recv() を呼び出し、サーバからの受信パケットをカーネルから受け取る。pvar->pkt_state.datalenが更新される。 </li>
855855 <li>SSH_handle_server_ID() でSSHサーバのバージョンチェックが行われる。pvar->pkt_state.datastart と pvar->pkt_state.datalen を更新する。</li>
@@ -857,7 +857,7 @@
857857 <li>TeraTermの recv() は"0"で返ってくる。すなわち、受信データなし。</li>
858858 </ol>
859859
860- 次に、SSH通信のための共通鍵生成までのシーケンスを以下に示します。
860+ 次に、SSH通信のための共通鍵生成までのシーケンスを以下に示します。
861861
862862 <ol>
863863 <li>recv_data() で本当の recv() を呼び出し、サーバからの受信パケットをカーネルから受け取る。pvar->pkt_state.datalenが更新される。 </li>
@@ -869,7 +869,7 @@
869869 <li>TeraTermの recv() は"0"で返ってくる。すなわち、受信データなし。</li>
870870 </ol>
871871
872- 次に、端末データ通信のシーケンスを以下に示します。
872+ 次に、端末データ通信のシーケンスを以下に示します。
873873
874874 <ol>
875875 <li>recv_data() で本当の recv() を呼び出し、サーバからの受信パケットをカーネルから受け取る。pvar->pkt_state.datalenが更新される。 </li>
@@ -885,10 +885,10 @@
885885
886886
887887 <h3>シーケンス制御</h3>
888- SSH2接続を行うことで、通信経路を暗号化することができるのが特徴ですが、パケットの暗号化を行うためには、「鍵」が必要です。通信経路の暗号化には、共通鍵による共通鍵暗号が利用されます。公開鍵暗号のほうがセキュリティ強度は高いのですが、暗号処理に多大な時間がかかるため、SSHのような通信性能が要求されるしくみでは採用されません。SSH2では、共通鍵暗号アルゴリズムとして、AES(Advanced Encryption Standard:Rijndaelアルゴリズム)や3DES(Triple DES)などが利用されます。<br>
889- 共通鍵は通信を行う二者間でのみに共有される情報であり、第三者に知られてはなりません。SSH2では、クライアントがリモートホスト(SSHサーバ)へTCP接続した時に、"Diffie-Hellman"アルゴリズムをベースとした独自の方式により、クライアントとサーバでしか知り得ないDH(Diffie-Hellman)鍵を生成します。DH鍵生成までの過程は、ネットワーク上をパケットが平文で流れるため、第三者によるパケットキャプチャが可能となっていますが、パケットを覗かれても、DH鍵は理論上第三者には分からないようになっています。<br>
890- 共通鍵が生成できたあとは、その鍵を使ってパケットを暗号化します。SSH2では、送受信されるパケットは種類があるため、それぞれに「メッセージ番号」を割り振っています。RFC4250にメッセージ番号の一覧があります。メッセージ名は"SSH2_MSG_xxxx"というネーミングになっており、TTSSH内部でも同じ名前でマクロ定義しています。<br>
891- 以下に、クライアントからサーバへTCP接続(ポート22番)してから、パスワード認証でユーザ認証されるまでの流れを示します。<br>
888+ SSH2接続を行うことで、通信経路を暗号化することができるのが特徴ですが、パケットの暗号化を行うためには、「鍵」が必要です。通信経路の暗号化には、共通鍵による共通鍵暗号が利用されます。公開鍵暗号のほうがセキュリティ強度は高いのですが、暗号処理に多大な時間がかかるため、SSHのような通信性能が要求されるしくみでは採用されません。SSH2では、共通鍵暗号アルゴリズムとして、AES(Advanced Encryption Standard:Rijndaelアルゴリズム)や3DES(Triple DES)などが利用されます。<br>
889+ 共通鍵は通信を行う二者間でのみに共有される情報であり、第三者に知られてはなりません。SSH2では、クライアントがリモートホスト(SSHサーバ)へTCP接続した時に、"Diffie-Hellman"アルゴリズムをベースとした独自の方式により、クライアントとサーバでしか知り得ないDH(Diffie-Hellman)鍵を生成します。DH鍵生成までの過程は、ネットワーク上をパケットが平文で流れるため、第三者によるパケットキャプチャが可能となっていますが、パケットを覗かれても、DH鍵は理論上第三者には分からないようになっています。<br>
890+ 共通鍵が生成できたあとは、その鍵を使ってパケットを暗号化します。SSH2では、送受信されるパケットは種類があるため、それぞれに「メッセージ番号」を割り振っています。RFC4250にメッセージ番号の一覧があります。メッセージ名は"SSH2_MSG_xxxx"というネーミングになっており、TTSSH内部でも同じ名前でマクロ定義しています。<br>
891+ 以下に、クライアントからサーバへTCP接続(ポート22番)してから、パスワード認証でユーザ認証されるまでの流れを示します。<br>
892892
893893
894894 <div align="center">
@@ -899,13 +899,13 @@
899899 <img src="image/ssh2_sequence2.png" width=720 height=540>
900900 </div>
901901
902- 以下は、リモートホストのシェル上で"exit"や"logout"として、クライアントから明示的にシェルをクローズするときの、パケットの流れを示しています。<br>
902+ 以下は、リモートホストのシェル上で"exit"や"logout"として、クライアントから明示的にシェルをクローズするときの、パケットの流れを示しています。<br>
903903
904904 <div align="center">
905905 <img src="image/ssh2_sequence3.png" width=720 height=540>
906906 </div>
907907
908- TTSSHは、SSH2でパスワード認証のほかにkeyboard-interactive認証、publickey認証、Pageantを利用したpublickey認証をサポートしています。それぞれの認証方式でどのようなシーケンスで認証が行われるのか、以下に示します。
908+ TTSSHは、SSH2でパスワード認証のほかにkeyboard-interactive認証、publickey認証、Pageantを利用したpublickey認証をサポートしています。それぞれの認証方式でどのようなシーケンスで認証が行われるのか、以下に示します。
909909
910910 <div align="center">
911911 <img src="image/ssh2_auth1.png" width=720 height=540>
@@ -917,83 +917,83 @@
917917
918918
919919 <h3>疑似端末のしくみ</h3>
920- SSH2では、新しく「フロー制御」という概念が取り込まれています。TCPのウィンドウと同じ考え方で、「ウィンドウサイズ」というしくみを導入しています。この機能により、クライアント(Tera Term)とサーバ(SSHデーモン)間において、フロー制御が働くため、原則データが溢れることはありません。<br>
921- ところで、SSH2におけるフロー制御があるにも関わらず、大量のクリップボードをTeraTermの端末へペーストすると、サーバ側での「データの取りこぼし」が発生することがあります。この現象を理解するためには、UNIXにおける疑似端末(PTY: pseudo-terminal)の動作原理を知る必要があります。
920+ SSH2では、新しく「フロー制御」という概念が取り込まれています。TCPのウィンドウと同じ考え方で、「ウィンドウサイズ」というしくみを導入しています。この機能により、クライアント(Tera Term)とサーバ(SSHデーモン)間において、フロー制御が働くため、原則データが溢れることはありません。<br>
921+ ところで、SSH2におけるフロー制御があるにも関わらず、大量のクリップボードをTeraTermの端末へペーストすると、サーバ側での「データの取りこぼし」が発生することがあります。この現象を理解するためには、UNIXにおける疑似端末(PTY: pseudo-terminal)の動作原理を知る必要があります。
922922
923923 <div align="center">
924924 <img src="image/pty.png" width=720 height=540>
925925 </div>
926926
927- SSHデーモン(sshd)はクライアントに対して、あたかもサーバ側のシェルが直接接続されているかのように見せる必要があります。逆に、シェル上で動くプログラムは、文字を送りたいときは printf(3) を、文字を受け取りたい場合は scanf(3) といったCライブラリ関数を呼び出すだけでよく、その先がシリアルコンソールなのか、VGAコンソールなのか、SSH接続されているのかは、一切気にしなくてよいようになっています。<br>
928- sshdは、クライアントからの接続要求があったタイミングで、openpty(3)を使って、疑似端末の初期化を行います。疑似端末では、カーネル空間でクライアントとサーバをつなぐために、「マスターデバイスドライバ」と「スレーブデバイスドライバ」が用意されます。マスターデバイスドライバが担当するデバイスファイルは"/dev/ptyXX"、スレーブデバイスドライバでは"/dev/ttyXX"です。つまり、sshdはマスターデバイスドライバへアクセスすることで、シェルとお話をすることができます。シェルは、sshdからforkされて子プロセスとなり、親プロセス(sshd)が初期化済みのスレーブデバイスドライバとお話をすることになります。この疑似端末のしくみにより、sshdとシェルが接続されます。<br>
929- なお、端末ラインディシプリン(line discipline: 回線規約)というのは、たとえばプログラムが getchar() を呼び出したときに、Enterキーを押下するまで、プログラムに制御が渡りません。端末ラインディシプリンは、プログラム実行中での「行内編集」を可能とするためのモジュールです。Linuxでは、端末ラインディシプリンは /proc/tty/ldiscs で確認できます(N_TTYが標準的に利用される)。
927+ SSHデーモン(sshd)はクライアントに対して、あたかもサーバ側のシェルが直接接続されているかのように見せる必要があります。逆に、シェル上で動くプログラムは、文字を送りたいときは printf(3) を、文字を受け取りたい場合は scanf(3) といったCライブラリ関数を呼び出すだけでよく、その先がシリアルコンソールなのか、VGAコンソールなのか、SSH接続されているのかは、一切気にしなくてよいようになっています。<br>
928+ sshdは、クライアントからの接続要求があったタイミングで、openpty(3)を使って、疑似端末の初期化を行います。疑似端末では、カーネル空間でクライアントとサーバをつなぐために、「マスターデバイスドライバ」と「スレーブデバイスドライバ」が用意されます。マスターデバイスドライバが担当するデバイスファイルは"/dev/ptyXX"、スレーブデバイスドライバでは"/dev/ttyXX"です。つまり、sshdはマスターデバイスドライバへアクセスすることで、シェルとお話をすることができます。シェルは、sshdからforkされて子プロセスとなり、親プロセス(sshd)が初期化済みのスレーブデバイスドライバとお話をすることになります。この疑似端末のしくみにより、sshdとシェルが接続されます。<br>
929+ なお、端末ラインディシプリン(line discipline: 回線規約)というのは、たとえばプログラムが getchar() を呼び出したときに、Enterキーを押下するまで、プログラムに制御が渡りません。端末ラインディシプリンは、プログラム実行中での「行内編集」を可能とするためのモジュールです。Linuxでは、端末ラインディシプリンは /proc/tty/ldiscs で確認できます(N_TTYが標準的に利用される)。
930930
931931
932932 <h3>SCP(Secure Copy)</h3>
933- SCPは OpenSSH パッケージに含まれるプログラムの1つであり、SSHセッションを使ってファイルの送受信を行うことができます。SCPを利用するためには、リモートサーバに"sshd"だけではなく、"scp"コマンドも導入されている必要があります。OpenSSHのSCPは、sshd デーモンから"scp"コマンドが子プロセスとして起動されることで実現されています。なお、SCPとSFTP(Secure File Transfer Program)はまったく別のプロトコルで、互換性はなく、SCPは純粋にファイルの「送信」と「受信」しかできません。<br>
934- SSHセッション上でファイル転送を行うには、クライアントからサーバへ接続が成功したあとに、シェルオープン(pty-req)の代わりに、「外部コマンドの実行」(exec)という形式で、SCPが利用できるようになります。
935- 
936- <p><font size=3>・SSH2の場合</font></p>
937- SSH2_MSG_CHANNEL_REQUEST をサーバへ送るときに、"pty-req"の代わりに"exec"をサービス名として指定すると、外部コマンドを実行することができます。
933+ SCPは OpenSSH パッケージに含まれるプログラムの1つであり、SSHセッションを使ってファイルの送受信を行うことができます。SCPを利用するためには、リモートサーバに"sshd"だけではなく、"scp"コマンドも導入されている必要があります。OpenSSHのSCPは、sshd デーモンから"scp"コマンドが子プロセスとして起動されることで実現されています。なお、SCPとSFTP(Secure File Transfer Program)はまったく別のプロトコルで、互換性はなく、SCPは純粋にファイルの「送信」と「受信」しかできません。<br>
934+ SSHセッション上でファイル転送を行うには、クライアントからサーバへ接続が成功したあとに、シェルオープン(pty-req)の代わりに、「外部コマンドの実行」(exec)という形式で、SCPが利用できるようになります。
935+
936+ <p><font size=3>・SSH2の場合</font></p>
937+ SSH2_MSG_CHANNEL_REQUEST をサーバへ送るときに、"pty-req"の代わりに"exec"をサービス名として指定すると、外部コマンドを実行することができます。
938938 <pre>
939-  ユーザ認証成功後
940-   ----&gt; SSH2_MSG_CHANNEL_OPEN(90)
941-   &lt;---- SSH2_MSG_CHANNEL_OPEN_CONFIRMATION(91)
942-   ----&gt; SSH2_MSG_CHANNEL_REQUEST(98) サービス名&quot;exec&quot;で外部コマンド送信(&quot;scp -f&quot;)
943-   &lt;---- SSH2_MSG_CHANNEL_WINDOW_ADJUST (remote_window+=131072バイト)
944-   &lt;---- SSH2_MSG_CHANNEL_EXTENDED_DATA (local_window-=36バイト)
945-   &lt;---- SSH2_MSG_CHANNEL_DATA(94)
939+ ユーザ認証成功後
940+ ----&gt; SSH2_MSG_CHANNEL_OPEN(90)
941+ &lt;---- SSH2_MSG_CHANNEL_OPEN_CONFIRMATION(91)
942+ ----&gt; SSH2_MSG_CHANNEL_REQUEST(98) サービス名&quot;exec&quot;で外部コマンド送信(&quot;scp -f&quot;)
943+ &lt;---- SSH2_MSG_CHANNEL_WINDOW_ADJUST (remote_window+=131072バイト)
944+ &lt;---- SSH2_MSG_CHANNEL_EXTENDED_DATA (local_window-=36バイト)
945+ &lt;---- SSH2_MSG_CHANNEL_DATA(94)
946946 </pre>
947947
948- <p><font size=3>・SSH1の場合</font></p>
949-  セッションを開くときに、SSH_CMSG_EXEC_CMD をサーバへ送ると、外部コマンドを実行することができます。
950- 
951- <p><font size=3>・外部コマンドの書式</font></p>
948+ <p><font size=3>・SSH1の場合</font></p>
949+ セッションを開くときに、SSH_CMSG_EXEC_CMD をサーバへ送ると、外部コマンドを実行することができます。
950+
951+ <p><font size=3>・外部コマンドの書式</font></p>
952952 <pre>
953- * "scp [-v] [-r] [-p] [-d] -t ファイル名" ローカルからリモートへのコピー
954- * "scp [-v] [-r] [-p] [-d] -f ファイル名" リモートからローカルへのコピー
955-  -v verbose
956-  -r リカーシブ
957-  -p タイムスタンプ保持
958-  -d ディレクトリ
959-  -t Local-to-Remoteへコピー
960-  -f Remote-to-Localへコピー
953+ * "scp [-v] [-r] [-p] [-d] -t ファイル名" ローカルからリモートへのコピー
954+ * "scp [-v] [-r] [-p] [-d] -f ファイル名" リモートからローカルへのコピー
955+ -v verbose
956+ -r リカーシブ
957+ -p タイムスタンプ保持
958+ -d ディレクトリ
959+ -t Local-to-Remoteへコピー
960+ -f Remote-to-Localへコピー
961961 </pre>
962962
963- <p><font size=3>・データ転送</font></p>
964-  外部コマンドの送信が完了したあとに、ファイルの内容を送信および受信することができます。
963+ <p><font size=3>・データ転送</font></p>
964+ 外部コマンドの送信が完了したあとに、ファイルの内容を送信および受信することができます。
965965 <pre>
966-  1.送信の流れ
967-   ・"Tタイムスタンプ 0 タイムスタンプ 0"を送信(オプション)
968-   ・"C0666 サイズ ファイル名"を送信
969-   ・ファイルの内容を送信
970-   ・セッションクローズ
966+ 1.送信の流れ
967+ ・"Tタイムスタンプ 0 タイムスタンプ 0"を送信(オプション)
968+ ・"C0666 サイズ ファイル名"を送信
969+ ・ファイルの内容を送信
970+ ・セッションクローズ
971971
972-  2.受信の流れ
973-   ・"Tタイムスタンプ 0 タイムスタンプ 0"を受信(オプション)
974-   ・0を送信
975-   ・"C0666 サイズ ファイル名"を受信
976-   ・0を送信
977-   ・ファイルの内容を受信
978-   ・ファイルのタイムスタンプを設定(オプション)
979-   ・0を送信
980-   ・セッションクローズ
972+ 2.受信の流れ
973+ ・"Tタイムスタンプ 0 タイムスタンプ 0"を受信(オプション)
974+ ・0を送信
975+ ・"C0666 サイズ ファイル名"を受信
976+ ・0を送信
977+ ・ファイルの内容を受信
978+ ・ファイルのタイムスタンプを設定(オプション)
979+ ・0を送信
980+ ・セッションクローズ
981981 </pre>
982982
983- <p><font size=3>・注意事項</font></p>
984-  ファイル名にディレクトリが含まれるときは、パスの区切りは「/」となります。「\」は受け付けないので、変換が必要です。
983+ <p><font size=3>・注意事項</font></p>
984+ ファイル名にディレクトリが含まれるときは、パスの区切りは「/」となります。「\」は受け付けないので、変換が必要です。
985985
986986
987987
988988 <h3>X11転送</h3>
989- X11転送(X11 port forwarding)は、SSHサーバ上でXウィンドウアプリケーションを起動し、アプリケーションのGUI画面をTera Termが動作しているコンソールPCに飛ばすしくみです。このしくみを使うと、SSHセッション上で"xeyes"や"firefox"、"xemacs"などのソフトウェアを動かすことができるようになります。なお、コンソールPC上には、Xming(http://sourceforge.net/projects/xming/)などのXサーバをあらかじめ用意しておく必要があります。<br>
990- 下図にX11転送のフローを示します。図を見ると分かるように、Tera Term(TTSSH)はXアプリケーションとXサーバをつなぐ橋渡しの役目を持ちます。このようなTera Termのことを"Redirector"や"Port forwarder"、"TCP proxy"と呼びます。
989+ X11転送(X11 port forwarding)は、SSHサーバ上でXウィンドウアプリケーションを起動し、アプリケーションのGUI画面をTera Termが動作しているコンソールPCに飛ばすしくみです。このしくみを使うと、SSHセッション上で"xeyes"や"firefox"、"xemacs"などのソフトウェアを動かすことができるようになります。なお、コンソールPC上には、Xming(http://sourceforge.net/projects/xming/)などのXサーバをあらかじめ用意しておく必要があります。<br>
990+ 下図にX11転送のフローを示します。図を見ると分かるように、Tera Term(TTSSH)はXアプリケーションとXサーバをつなぐ橋渡しの役目を持ちます。このようなTera Termのことを"Redirector"や"Port forwarder"、"TCP proxy"と呼びます。
991991
992992 <div align="center">
993993 <img src="image/x11forward.png" width=720 height=540>
994994 </div>
995995
996- X11転送を利用するためには、Tera TermおよびSSHサーバの双方に事前設定が必要です。まず、Tera Termのほうはteraterm.iniに下記の設定が必要です。
996+ X11転送を利用するためには、Tera TermおよびSSHサーバの双方に事前設定が必要です。まず、Tera Termのほうはteraterm.iniに下記の設定が必要です。
997997
998998 <pre class=code>
999999 [TTSSH]
@@ -1000,13 +1000,13 @@
10001000 DefaultForwarding=X
10011001 </pre>
10021002
1003- SSHサーバのほうは、OpenSSHを例に挙げると、"sshd_config"に下記の設定が必要です。デフォルトは"no"になっているため、通常はデフォルトではX11転送が使えません。
1003+ SSHサーバのほうは、OpenSSHを例に挙げると、"sshd_config"に下記の設定が必要です。デフォルトは"no"になっているため、通常はデフォルトではX11転送が使えません。
10041004
10051005 <pre class=code>
10061006 X11Forwarding=yes
10071007 </pre>
10081008
1009- Tera TermはX11転送が有効であると、spec.typeに"FWD_REMOTE_X11_TO_LOCAL"を設定します。これはSSHサーバ側からTera Term側に向かって、X11転送を行うことを意味します。Tera Termは、リモートホストにSSH接続する際、セッションオープン後の"SSH2_MSG_CHANNEL_OPEN_CONFIRMATION"において、X11転送の初期化を行います。
1009+ Tera TermはX11転送が有効であると、spec.typeに"FWD_REMOTE_X11_TO_LOCAL"を設定します。これはSSHサーバ側からTera Term側に向かって、X11転送を行うことを意味します。Tera Termは、リモートホストにSSH接続する際、セッションオープン後の"SSH2_MSG_CHANNEL_OPEN_CONFIRMATION"において、X11転送の初期化を行います。
10101010
10111011 <pre class=code>
10121012 if (c->type == TYPE_SHELL) {
@@ -1017,7 +1017,7 @@
10171017 }
10181018 </pre>
10191019
1020- FWD_prep_forwarding()では、"x11-req"サービス名と"MIT-MAGIC-COOKIE-1"をSSHサーバに送信し、SSHサーバ側のX11転送の初期化を促します。SSH接続時にX11の初期化が完了すると、SSHサーバ側に環境変数"DISPLAY"が自動的に設定されます。
1020+ FWD_prep_forwarding()では、"x11-req"サービス名と"MIT-MAGIC-COOKIE-1"をSSHサーバに送信し、SSHサーバ側のX11転送の初期化を促します。SSH接続時にX11の初期化が完了すると、SSHサーバ側に環境変数"DISPLAY"が自動的に設定されます。
10211021
10221022 <pre class=code>
10231023 # echo $DISPLAY
@@ -1024,8 +1024,8 @@
10241024 DISPLAY=localhost:10.0
10251025 </pre>
10261026
1027- ここまで準備が整うと、SSHサーバ上でXアプリケーションを起動させることができます。XアプリケーションからXサーバ、すなわちSSHサーバからTera Termへ送られてくるデータは、SSH2_MSG_CHANNEL_DATA メッセージ形式となります。当該メッセージは FWD_received_data() で処理され、Xサーバ(TCP/6000)へ送られます。Xサーバのソケットは channel->local_socket で、ノンブロッキングモードで扱われます。そのため、一度でパケットを全部送れない場合があるため、送れなかったデータは内部バッファに溜めておく必要があります。また、channel->local_socket にパケットをsendすることにより、FD_WRITE メッセージが発生し、write_local_connection_buffer() が呼び出されます。ここでは、前回送れなかったデータがあれば、内部バッファから取り出し、再度Xサーバへの送信を試みます。<br>
1028- 反対に、Xサーバ、すなわちX11の画面上で何らかの操作が行われた場合、Tera TermからSSHサーバにデータを送信する必要があります。このとき、Tera Termへは FD_READ メッセージが発生し、read_local_connection() が呼び出されます。ここでは、Xサーバから送られてきたデータを SSH2_MSG_CHANNEL_DATA メッセージ形式に載せて、SSHサーバへ送ります。
1027+ ここまで準備が整うと、SSHサーバ上でXアプリケーションを起動させることができます。XアプリケーションからXサーバ、すなわちSSHサーバからTera Termへ送られてくるデータは、SSH2_MSG_CHANNEL_DATA メッセージ形式となります。当該メッセージは FWD_received_data() で処理され、Xサーバ(TCP/6000)へ送られます。Xサーバのソケットは channel->local_socket で、ノンブロッキングモードで扱われます。そのため、一度でパケットを全部送れない場合があるため、送れなかったデータは内部バッファに溜めておく必要があります。また、channel->local_socket にパケットをsendすることにより、FD_WRITE メッセージが発生し、write_local_connection_buffer() が呼び出されます。ここでは、前回送れなかったデータがあれば、内部バッファから取り出し、再度Xサーバへの送信を試みます。<br>
1028+ 反対に、Xサーバ、すなわちX11の画面上で何らかの操作が行われた場合、Tera TermからSSHサーバにデータを送信する必要があります。このとき、Tera Termへは FD_READ メッセージが発生し、read_local_connection() が呼び出されます。ここでは、Xサーバから送られてきたデータを SSH2_MSG_CHANNEL_DATA メッセージ形式に載せて、SSHサーバへ送ります。
10291029
10301030 <hr>
10311031
@@ -1032,17 +1032,17 @@
10321032
10331033 <h2><a name="macro">マクロ言語の設計と実装</a></h2>
10341034 <h3>概要</h3>
1035- Tera Termのマクロスクリプトは、BASIC風の言語仕様となっています。BisonやFlexといったしくみは利用しておらず、力業的な独自の構文解析(再帰的下降法)により実装されています。そのため、本格的なスクリプト言語としての記述はできない側面があります。<br>
1036- 
1035+ Tera Termのマクロスクリプトは、BASIC風の言語仕様となっています。BisonやFlexといったしくみは利用しておらず、力業的な独自の構文解析(再帰的下降法)により実装されています。そのため、本格的なスクリプト言語としての記述はできない側面があります。<br>
1036+
10371037 <h3>ファイルの読み込み</h3>
1038- ttpmacro.exeの起動時に、マクロファイル(.ttl)が一括してバッファへ読み込まれます。
1039- 
1038+ ttpmacro.exeの起動時に、マクロファイル(.ttl)が一括してバッファへ読み込まれます。
1039+
10401040 <p><ul>
10411041 <li>OnInitDialog()#ttmmain.cpp -> InitTTL() -> InitBuff() -> LoadMacroFile()</li>
10421042 </ul></p>
10431043
1044- 初めて読み込まれるマクロファイルの全内容は Buff[0] # ttmbuff.c に格納されます。この時点で、ファイルの内容は一括して読み込まれるため、マクロ実行中はファイルを削除してしまっても問題はありません。ただし、"include"で別のファイルを読み込む場合は、includeを実行する時点で、include対象となるファイルの読み込みが発生します。
1045- 
1044+ 初めて読み込まれるマクロファイルの全内容は Buff[0] # ttmbuff.c に格納されます。この時点で、ファイルの内容は一括して読み込まれるため、マクロ実行中はファイルを削除してしまっても問題はありません。ただし、"include"で別のファイルを読み込む場合は、includeを実行する時点で、include対象となるファイルの読み込みが発生します。
1045+
10461046 <pre class=code>
10471047 #define MAXNESTLEVEL 10 /* 扱えるファイル数(includeは9つまで)*/
10481048
@@ -1055,7 +1055,7 @@
10551055
10561056
10571057 <h3>マクロエンジン</h3>
1058- マクロ処理はアイドルループ OnIdle()#ttmmain.cpp で行われます。アイドルループでは TTLStatus 変数により、マクロエンジンの動作を変えています。通常の実行状態は IdTTLRun がセットされています。以下に、動作一覧を示します。
1058+ マクロ処理はアイドルループ OnIdle()#ttmmain.cpp で行われます。アイドルループでは TTLStatus 変数により、マクロエンジンの動作を変えています。通常の実行状態は IdTTLRun がセットされています。以下に、動作一覧を示します。
10591059
10601060 <p>
10611061 <table border=1 align=center>
@@ -1104,7 +1104,7 @@
11041104
11051105
11061106 <h3>インタープリタ処理</h3>
1107- アイドルループから Exec()#ttl.c が定期的に呼び出される度に、マクロファイルが一行ずつ処理されてゆきます。GetNewLine() では、バッファから一行分を取り出し、LineBuff[]#ttmparse.c へ格納します。行の終わりかどうかは、「ASCIIコードが0x20未満で、かつタブ(0x09)以外」のコードが出現したタイミングで判定しています。先頭の空白やタブは無視されます。セミコロン(;)が出現すると、以降の処理をスキップするため、コメントは行の途中でも付けられることになります。<br>
1107+ アイドルループから Exec()#ttl.c が定期的に呼び出される度に、マクロファイルが一行ずつ処理されてゆきます。GetNewLine() では、バッファから一行分を取り出し、LineBuff[]#ttmparse.c へ格納します。行の終わりかどうかは、「ASCIIコードが0x20未満で、かつタブ(0x09)以外」のコードが出現したタイミングで判定しています。先頭の空白やタブは無視されます。セミコロン(;)が出現すると、以降の処理をスキップするため、コメントは行の途中でも付けられることになります。<br>
11081108
11091109 <pre class=code>
11101110 char LineBuff[MaxLineLen]; /* 1つの行は500バイトまで格納可能 */
@@ -1112,7 +1112,7 @@
11121112 WORD LineLen; /* バッファサイズ */
11131113 </pre>
11141114
1115- Exec()から呼ばれる ExecCmnd() で、字句解析を行います。字句解析は単純な文字列検索であり、LineBuff[]を1バイトずつ参照していきます。大まかな処理の流れは以下のとおりです。
1115+ Exec()から呼ばれる ExecCmnd() で、字句解析を行います。字句解析は単純な文字列検索であり、LineBuff[]を1バイトずつ参照していきます。大まかな処理の流れは以下のとおりです。
11161116
11171117 <p><ol>
11181118 <li>endwhileの判定</li>
@@ -1124,19 +1124,19 @@
11241124 <li>文法エラー(上記のいずれでもない場合)</li>
11251125 </ol></p>
11261126
1127- マクロコマンドかどうかは、GetReservedWord()で判別しています。_stricmp()で比較しているので、アルファベットの大文字・小文字は区別されません(case-insensitive)。マクロコマンドの場合は、TTLxxx() の関数を呼び出します。<br>
1128- 識別子の判定は、GetIdentifier() で行います。アルファベット(a-z, A-Z)および数値(0-9)、アンダースコア(_)から構成されるトークンを切り出します。トークンは32文字までです。トークンは「変数」として扱われます。左辺値に変数が来る場合は、「変数への代入」しかありえないので、その直後に「イコール(=)」があるかどうかを調べます。<br>
1129- イコール以降の判定処理は、以下の順番となります。
1130- 
1127+ マクロコマンドかどうかは、GetReservedWord()で判別しています。_stricmp()で比較しているので、アルファベットの大文字・小文字は区別されません(case-insensitive)。マクロコマンドの場合は、TTLxxx() の関数を呼び出します。<br>
1128+ 識別子の判定は、GetIdentifier() で行います。アルファベット(a-z, A-Z)および数値(0-9)、アンダースコア(_)から構成されるトークンを切り出します。トークンは32文字までです。トークンは「変数」として扱われます。左辺値に変数が来る場合は、「変数への代入」しかありえないので、その直後に「イコール(=)」があるかどうかを調べます。<br>
1129+ イコール以降の判定処理は、以下の順番となります。
1130+
11311131 <p><ol>
11321132 <li>文字列の判定</li>
11331133 <li>計算式の判定</li>
11341134 </ol></p>
11351135
1136- 文字列かどうかは GetString() で判定します。文字列は’か”でクォートされているため、取り出すのは容易です。<br>
1137- 計算式の判定は、GetExpression() で行います。ここでは再帰的下降法により、構文解析されます。<br>
1138- 左辺値が定義済みの変数かどうかは CheckVar() でチェックし、数値もしくは文字列をセットします。そうではない場合は NewStrVar() で、新しい変数として登録します。
1139- 
1136+ 文字列かどうかは GetString() で判定します。文字列は’か”でクォートされているため、取り出すのは容易です。<br>
1137+ 計算式の判定は、GetExpression() で行います。ここでは再帰的下降法により、構文解析されます。<br>
1138+ 左辺値が定義済みの変数かどうかは CheckVar() でチェックし、数値もしくは文字列をセットします。そうではない場合は NewStrVar() で、新しい変数として登録します。
1139+
11401140
11411141 <hr>
11421142
@@ -1144,11 +1144,11 @@
11441144
11451145 <h2><a name="caret">キャレット制御</a></h2>
11461146 <h3>概要</h3>
1147- ユーザが端末上でキーボード入力を行うと、カーソルが移動しますが、サーバからのエスケープシーケンスにより、キーボード入力なしにカーソルを移動させる必要があります。また、ウィンドウが非アクティブ状態の場合においても、カーソルを表示させることにより、ブロードキャストモードにおいて、複数端末の同時操作性を向上させています。
1147+ ユーザが端末上でキーボード入力を行うと、カーソルが移動しますが、サーバからのエスケープシーケンスにより、キーボード入力なしにカーソルを移動させる必要があります。また、ウィンドウが非アクティブ状態の場合においても、カーソルを表示させることにより、ブロードキャストモードにおいて、複数端末の同時操作性を向上させています。
11481148 <br>
11491149
11501150 <h3>システムキャレット</h3>
1151- Tera Termにおけるカーソル描画には、システムキャレットを利用しています。Tera Termで使用されているシステムキャレットを制御するAPIを以下に示します。
1151+ Tera Termにおけるカーソル描画には、システムキャレットを利用しています。Tera Termで使用されているシステムキャレットを制御するAPIを以下に示します。
11521152
11531153 <p><ul>
11541154 <li>CreateCaret</li>
@@ -1160,7 +1160,7 @@
11601160 <li>ShowCaret</li>
11611161 </ul></p>
11621162
1163- <a href="http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpwinui/html/_win32_createcaret.asp">CreateCaretのドキュメント</a>によると、
1163+ <a href="http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpwinui/html/_win32_createcaret.asp">CreateCaretのドキュメント</a>によると、
11641164
11651165 <pre>
11661166 システムは 1 つのキューにつき 1 つのキャレットを提供します。ウィンドウが
@@ -1170,16 +1170,16 @@
11701170 </pre>
11711171
11721172 とあるため、ウィンドウがアクティブになったタイミングで CreateCaret() を呼び出し、フォーカスが外れ、非アクティブになるタイミングで DestroyCaret() を呼び出す必要があることを意味しています。<br>
1173- キャレットの表示は CaretOn()#vtdisp.c で、消去は CaretOff()#vtdisp.c で実装されています。CaretOn()やCaretOff()が呼び出されるタイミングは、エスケープシーケンス処理 VTParse() の箇所以外にも、マウスボタンを押したときやウィンドウのリサイズを行っているときなどがあります。<br>
1173+ キャレットの表示は CaretOn()#vtdisp.c で、消去は CaretOff()#vtdisp.c で実装されています。CaretOn()やCaretOff()が呼び出されるタイミングは、エスケープシーケンス処理 VTParse() の箇所以外にも、マウスボタンを押したときやウィンドウのリサイズを行っているときなどがあります。<br>
11741174
11751175
11761176
11771177 <h3>非アクティブ時のカーソル表示</h3>
1178- ウィンドウが非アクティブの場合は、カーソルが消滅します。Windowsの上ではユーザが操作できうるウィンドウは1つであるため、システムキャレットも1つのみ用意されています。通常のオペレーションにおいては、この動作で問題がありません。<br>
1179- しかし、ブロードキャストモードを利用する場合、非アクティブのTera Termウィンドウに対して、コマンドを投入することになります。特に、viなどで複数の端末を同時操作するときは、カーソルが消えていると不都合があります。<br>
1180- そこで、ウィンドウが非アクティブの場合においても、カーソルを描画するようにしています。ただし、システムキャレットは使えないので、自前でカーソルを描画する必要があります。Tera Termのウィンドウが非アクティブの場合においても、リモートホストから送られてくるエスケープシーケンスを処理するためにメインエンジンは動いており、常にカーソル位置は更新されています。現在のカーソル位置は、CursorXとCursorYに設定されています。<br>
1181- 非アクティブ時のカーソル表示は CaretKillFocus() で行っています。このときに表示されるカーソルを「ポリゴンカーソル」と呼んでいます。ts.VTColor[0] は Text color です。非アクティブ状態でカーソル位置が更新されるときは、以前に描いたカーソルを消す必要があるので、そのときは ts.VTColor[1] で表される Background color で再描画することで、以前のカーソルを消去しています。<br>
1182- Background colorでポリゴンカーソルを描画すると、ちょうどそのとき背景にあった文字の一部が欠けることがあります。そのため、その文字の再描画を行う必要があり、UpdateCaretKillFocus() で実現しています。当該関数では InvalidateRect() で WM_PAINT を送ることにより、文字の再描画を促しています。<br>
1178+ ウィンドウが非アクティブの場合は、カーソルが消滅します。Windowsの上ではユーザが操作できうるウィンドウは1つであるため、システムキャレットも1つのみ用意されています。通常のオペレーションにおいては、この動作で問題がありません。<br>
1179+ しかし、ブロードキャストモードを利用する場合、非アクティブのTera Termウィンドウに対して、コマンドを投入することになります。特に、viなどで複数の端末を同時操作するときは、カーソルが消えていると不都合があります。<br>
1180+ そこで、ウィンドウが非アクティブの場合においても、カーソルを描画するようにしています。ただし、システムキャレットは使えないので、自前でカーソルを描画する必要があります。Tera Termのウィンドウが非アクティブの場合においても、リモートホストから送られてくるエスケープシーケンスを処理するためにメインエンジンは動いており、常にカーソル位置は更新されています。現在のカーソル位置は、CursorXとCursorYに設定されています。<br>
1181+ 非アクティブ時のカーソル表示は CaretKillFocus() で行っています。このときに表示されるカーソルを「ポリゴンカーソル」と呼んでいます。ts.VTColor[0] は Text color です。非アクティブ状態でカーソル位置が更新されるときは、以前に描いたカーソルを消す必要があるので、そのときは ts.VTColor[1] で表される Background color で再描画することで、以前のカーソルを消去しています。<br>
1182+ Background colorでポリゴンカーソルを描画すると、ちょうどそのとき背景にあった文字の一部が欠けることがあります。そのため、その文字の再描画を行う必要があり、UpdateCaretKillFocus() で実現しています。当該関数では InvalidateRect() で WM_PAINT を送ることにより、文字の再描画を促しています。<br>
11831183
11841184 <pre class=code>
11851185 void CaretKillFocus(BOOL show)
@@ -1227,7 +1227,7 @@
12271227
12281228
12291229 <h3>非アクティブ時のカーソル表示タイミング</h3>
1230- 非アクティブ時のカーソル表示のタイミングは、いくつかのパターンがあるため、漏れなく対処しておく必要があります。表示タイミングとしては以下のとおりです。
1230+ 非アクティブ時のカーソル表示のタイミングは、いくつかのパターンがあるため、漏れなく対処しておく必要があります。表示タイミングとしては以下のとおりです。
12311231
12321232 <p>
12331233 <ul>
@@ -1249,11 +1249,11 @@
12491249
12501250 <h2><a name="serial">シリアルポート</a></h2>
12511251 <h3>概要</h3>
1252- Tera TermはUART(16550A)互換のシリアルポートに対応しているため、シリアルコンソールが使用できます。シリアルポートのことを、COM(Communication Port)ポートと呼ぶこともあります。OSが検出したCOMポートは、順に"COM1"、"COM2"といった名前が付けられ、アプリケーションから利用することができます。Microsoft Windows XPでは、最大256個のCOMポート(COM1~COM256)までが利用可能です。<br>
1253- パソコンに搭載されるCOMポートは、せいぜい1つ、多くても2つであり、最近ではまったくCOMポートがないパソコンも存在します。そのため、USB接続によるシリアルポートを実現する「USBシリアル変換ケーブル」が発売されています。こういった製品の特徴として、OSに認識させるCOMポートの番号を、ユーザが自由に設定できるようになっています。すなわち、Tera Term見えには、2つのCOMポートがあった場合、それぞれ"COM1"、"COM2"として認識できるとは限らず、"COM1"、"COM7"といったふうに認識できるようになる必要があります。<br>
1254- 
1252+ Tera TermはUART(16550A)互換のシリアルポートに対応しているため、シリアルコンソールが使用できます。シリアルポートのことを、COM(Communication Port)ポートと呼ぶこともあります。OSが検出したCOMポートは、順に"COM1"、"COM2"といった名前が付けられ、アプリケーションから利用することができます。Microsoft Windows XPでは、最大256個のCOMポート(COM1~COM256)までが利用可能です。<br>
1253+ パソコンに搭載されるCOMポートは、せいぜい1つ、多くても2つであり、最近ではまったくCOMポートがないパソコンも存在します。そのため、USB接続によるシリアルポートを実現する「USBシリアル変換ケーブル」が発売されています。こういった製品の特徴として、OSに認識させるCOMポートの番号を、ユーザが自由に設定できるようになっています。すなわち、Tera Term見えには、2つのCOMポートがあった場合、それぞれ"COM1"、"COM2"として認識できるとは限らず、"COM1"、"COM7"といったふうに認識できるようになる必要があります。<br>
1254+
12551255 <h3>COMポートのリストアップ</h3>
1256- かつてのTera Termでは、"COM1"から"COM256"までのすべてのCOMポートを、接続ダイアログにリストアップしていましたが、使い勝手がよくありませんでした。そこで、接続ダイアログを呼び出したタイミングにおいて(Tera Term起動時のみでは不十分)、OSが認識しているCOMポートを検出するようにして、必要なCOMポートのみを表示させるようにしました。その検出ロジックが、DetectComPorts()#ttcmn.c です。QueryDosDevice() APIを使用し、MS-DOSデバイス名から"COM"を探します。<br>
1256+ かつてのTera Termでは、"COM1"から"COM256"までのすべてのCOMポートを、接続ダイアログにリストアップしていましたが、使い勝手がよくありませんでした。そこで、接続ダイアログを呼び出したタイミングにおいて(Tera Term起動時のみでは不十分)、OSが認識しているCOMポートを検出するようにして、必要なCOMポートのみを表示させるようにしました。その検出ロジックが、DetectComPorts()#ttcmn.c です。QueryDosDevice() APIを使用し、MS-DOSデバイス名から"COM"を探します。<br>
12571257
12581258 <pre class=code>
12591259 if (((h = GetModuleHandle("kernel32.dll")) != NULL) &&
@@ -1272,8 +1272,8 @@
12721272
12731273 <h3>COMポートのフルネーム取得</h3>
12741274
1275- 上記の処理だけでもユーザビリティは向上するのですが、さらなる欲求として、各COMポートに付けられる「フルネーム」を同時に表示したくなります。COMポートの番号とともに、フルネームも付加表示できると、さらに使い勝手がよくなることが期待されます。この課題を解決するのが、ListupSerialPort()#ttcmn.c です。<br>
1276- 
1275+ 上記の処理だけでもユーザビリティは向上するのですが、さらなる欲求として、各COMポートに付けられる「フルネーム」を同時に表示したくなります。COMポートの番号とともに、フルネームも付加表示できると、さらに使い勝手がよくなることが期待されます。この課題を解決するのが、ListupSerialPort()#ttcmn.c です。<br>
1276+
12771277 <pre class=code>
12781278 static void ListupSerialPort(LPWORD ComPortTable, int comports, char **ComPortDesc, int ComPortMax)
12791279 {
@@ -1466,8 +1466,8 @@
14661466 </table>
14671467
14681468 <h3>テスト手法</h3>
1469- バイナリ転送プロトコルはシリアル回線で利用されることが多いのですが、最近のPCは、シリアルポートが搭載されていないため、シリアル接続でのテストを行うことが難しくなっています。そこで、<a href="http://com0com.sourceforge.net/">com0comというNull-modem emulator</a>を利用すると、1つのPC内で仮想的に2つのCOMポートを生成し、Tera Term同士、Tera Termと別ターミナルソフト同士で、シリアル通信を行うことができます。
1470- 
1469+ バイナリ転送プロトコルはシリアル回線で利用されることが多いのですが、最近のPCは、シリアルポートが搭載されていないため、シリアル接続でのテストを行うことが難しくなっています。そこで、<a href="http://com0com.sourceforge.net/">com0comというNull-modem emulator</a>を利用すると、1つのPC内で仮想的に2つのCOMポートを生成し、Tera Term同士、Tera Termと別ターミナルソフト同士で、シリアル通信を行うことができます。
1470+
14711471
14721472 <div align="center">
14731473 <img src="image/devman_com0com.png" width=468 height=171>
@@ -1475,8 +1475,8 @@
14751475
14761476
14771477 <h3>記号</h3>
1478- バイナリ転送プロトコルでは、ACKやCANといったキャラクタ表記が使われますが、これらはASCIIコード表から来ています。man 7 ascii でASCIIコード一覧が参照できます。以下に代表的な記号と値を引用します。
1479- 
1478+ バイナリ転送プロトコルでは、ACKやCANといったキャラクタ表記が使われますが、これらはASCIIコード表から来ています。man 7 ascii でASCIIコード一覧が参照できます。以下に代表的な記号と値を引用します。
1479+
14801480
14811481 <pre class=code>
14821482 Oct Dec Hex Char Oct Dec Hex Char
@@ -1494,14 +1494,14 @@
14941494 <h3>XMODEM</h3>
14951495 XMODEMは、ファイルのデータを一定のサイズ(128バイトおよび1024バイト)に分割し、ブロックごとにACKを確認しながら、送信を行うプロトコルです。ブロック単位で、毎回ACKを確認するため、転送速度は速くはありませんが、実装がシンプルとなります。<br>
14961496 最後のブロックが一定のサイズに満たない場合は、満たすようにCPMEOF(0x1A)がパディングされます。すなわち、データを送ると、かならずデータのサイズが一定のサイズの倍数となり、末尾にCPMEOFが付加される場合があるということです。そのため、ファイルの送信に完全性を求める場合は、XMOMDEは使えません。なお、CPMEOFというのは、MS-DOSの前身であるCP/MというOSにおいて、テキストファイルの終端(EOF)を表す値のことです。<br>
1497- XMODEMのプロトコルについては、下記サイトが参考になります。
1497+ XMODEMのプロトコルについては、下記サイトが参考になります。
14981498
14991499 <ul>
1500- <li><a href="http://ja.wikipedia.org/wiki/XMODEM">XMODEM - Wikipedia</a></li>
1500+ <li><a href="http://ja.wikipedia.org/wiki/XMODEM">XMODEM - Wikipedia</a></li>
15011501 </ul>
15021502 <br>
15031503
1504- teraterm.ini で XmodemLog エントリを有効にすると、通信ログを採取することができます。通信ログファイルは、ttermpro.exe と同じディレクトリに"XMODEM.LOG"という名前で生成されます。
1504+ teraterm.ini で XmodemLog エントリを有効にすると、通信ログを採取することができます。通信ログファイルは、ttermpro.exe と同じディレクトリに"XMODEM.LOG"という名前で生成されます。
15051505
15061506 <pre class=code>
15071507 ; XMODEM log
@@ -1508,8 +1508,8 @@
15081508 XmodemLog=on
15091509 </pre>
15101510
1511- 簡単な例として、Tera Term(COM10)から<a href="http://nanno.dip.jp/softlib/man/rlogin/">RLogin</a>(COM11)に対して、67バイトのファイルを送信した場合の通信ログを示します。「&lt;&lt;&lt;」行はTera Termがホストから受信したデータで、「&gt;&gt;&gt;」行はTera Termが送信したデータです。
1512- 
1511+ 簡単な例として、Tera Term(COM10)から<a href="http://nanno.dip.jp/softlib/man/rlogin/">RLogin</a>(COM11)に対して、67バイトのファイルを送信した場合の通信ログを示します。「&lt;&lt;&lt;」行はTera Termがホストから受信したデータで、「&gt;&gt;&gt;」行はTera Termが送信したデータです。
1512+
15131513 <pre class=code>
15141514 &lt;&lt;&lt;
15151515 15 .
@@ -1535,8 +1535,8 @@
15351535 06
15361536 </pre>
15371537
1538- 上記ログの意味は以下のとおりです。
1539- 
1538+ 上記ログの意味は以下のとおりです。
1539+
15401540 <ol>
15411541 <li>NAK受信</li>
15421542 <li>ブロックデータの送信</li>
@@ -1545,12 +1545,12 @@
15451545 <li>ACK受信</li>
15461546 </ol>
15471547
1548- ブロックデータは、「ヘッダ(3byte)+データ(128byte)+CRC(1byte)」から構成されます。この例では、送信データが128byte未満なので、パディングとしてCPMEOF(0x1A)で埋められています。
1548+ ブロックデータは、「ヘッダ(3byte)+データ(128byte)+CRC(1byte)」から構成されます。この例では、送信データが128byte未満なので、パディングとしてCPMEOF(0x1A)で埋められています。
15491549
15501550 <p></p>
15511551
1552- 次はもう少し大きめのサイズ(1772byte)のデータを送信してみます。(1772+127)/128=14 で、14回ブロック転送されるはずです。下記に通信ログを示します。ヘッダの第2バイトがブロック番号(1オリジン)であり、1(0x01)~14(0x0E)まで増加していることが分かります。最後のブロックは128バイトに収まるように、CPMEOFがパディングとして付加されています。<br>
1553- このようにXMODEMによる通信では、送信後ファイルの末尾にゴミが付いたように見えるので、厳密にはファイルが壊れます。
1552+ 次はもう少し大きめのサイズ(1772byte)のデータを送信してみます。(1772+127)/128=14 で、14回ブロック転送されるはずです。下記に通信ログを示します。ヘッダの第2バイトがブロック番号(1オリジン)であり、1(0x01)~14(0x0E)まで増加していることが分かります。最後のブロックは128バイトに収まるように、CPMEOFがパディングとして付加されています。<br>
1553+ このようにXMODEMによる通信では、送信後ファイルの末尾にゴミが付いたように見えるので、厳密にはファイルが壊れます。
15541554
15551555 <pre class=code>
15561556 &lt;&lt;&lt;
@@ -1625,16 +1625,16 @@
16251625
16261626
16271627 <h3>YMODEM</h3>
1628- YMODEMは、XMODEMを改良したプロトコルです。XMODEMとの違いはいくつかありますが、大きな違いの1つとして、ファイル情報が送れるということです。YMODEMでは、ファイル名やファイルサイズをホストに知らせることができるので、送信したファイルの末尾からCPMEOFを除去することができます。<br>
1628+ YMODEMは、XMODEMを改良したプロトコルです。XMODEMとの違いはいくつかありますが、大きな違いの1つとして、ファイル情報が送れるということです。YMODEMでは、ファイル名やファイルサイズをホストに知らせることができるので、送信したファイルの末尾からCPMEOFを除去することができます。<br>
16291629
1630- YMODEMのプロトコルについては、下記サイトが参考になります。
1630+ YMODEMのプロトコルについては、下記サイトが参考になります。
16311631
16321632 <ul>
1633- <li><a href="http://ja.wikipedia.org/wiki/YMODEM">YMODEM - Wikipedia</a></li>
1633+ <li><a href="http://ja.wikipedia.org/wiki/YMODEM">YMODEM - Wikipedia</a></li>
16341634 </ul>
16351635 <br>
16361636
1637- teraterm.ini で YmodemLog エントリを有効にすると、通信ログを採取することができます。通信ログファイルは、ttermpro.exe と同じディレクトリに"YMODEM.LOG"という名前で生成されます。
1637+ teraterm.ini で YmodemLog エントリを有効にすると、通信ログを採取することができます。通信ログファイルは、ttermpro.exe と同じディレクトリに"YMODEM.LOG"という名前で生成されます。
16381638
16391639 <pre class=code>
16401640 ; YMODEM log
@@ -1641,8 +1641,8 @@
16411641 YmodemLog=on
16421642 </pre>
16431643
1644- 簡単な例として、Tera Term(COM10)から<a href="http://nanno.dip.jp/softlib/man/rlogin/">RLogin</a>(COM11)に対して、67バイトのファイルを送信した場合の通信ログを示します。「&lt;&lt;&lt;」行はTera Termがホストから受信したデータで、「&gt;&gt;&gt;」行はTera Termが送信したデータです。
1645- 
1644+ 簡単な例として、Tera Term(COM10)から<a href="http://nanno.dip.jp/softlib/man/rlogin/">RLogin</a>(COM11)に対して、67バイトのファイルを送信した場合の通信ログを示します。「&lt;&lt;&lt;」行はTera Termがホストから受信したデータで、「&gt;&gt;&gt;」行はTera Termが送信したデータです。
1645+
16461646 <pre class=code>
16471647 &lt;&lt;&lt;
16481648 43 C
@@ -1864,8 +1864,8 @@
18641864 06
18651865 </pre>
18661866
1867- 上記ログの意味は以下のとおりです。
1868- 
1867+ 上記ログの意味は以下のとおりです。
1868+
18691869 <ol>
18701870 <li>'C'(送信要求)受信</li>
18711871 <li>ブロック0(ファイル情報)の送信</li>
@@ -1889,24 +1889,24 @@
18891889
18901890
18911891 <h3>KERMIT</h3>
1892- KERMIT(カーミット:セサミストリートに登場するカエルのマペット)は、1981年にコロンビア大学で開発されたファイル転送プロトコルであり、現在はカーミットプロジェクトによりメンテナンスされています。下記のサイトから仕様書が入手できます。<br>
1893- 
1892+ KERMIT(カーミット:セサミストリートに登場するカエルのマペット)は、1981年にコロンビア大学で開発されたファイル転送プロトコルであり、現在はカーミットプロジェクトによりメンテナンスされています。下記のサイトから仕様書が入手できます。<br>
1893+
18941894 <ul>
18951895 <li><a href="http://www.kermitproject.org/">The Kermit Project</a></li>
18961896 </ul>
18971897 <br>
18981898
1899- 上記サイトでは、ソースコードも配布されており、様々なプラットフォームに実装されています。実装の名称としては、C-KermitやE-Kermit、Kermit95などがあります。<br>
1900- teraterm.ini で KmtLog エントリを有効にすると、通信ログを採取することができます。通信ログファイルは、ttermpro.exe と同じディレクトリに"KERMIT.LOG"という名前で生成されます。
1901- 
1899+ 上記サイトでは、ソースコードも配布されており、様々なプラットフォームに実装されています。実装の名称としては、C-KermitやE-Kermit、Kermit95などがあります。<br>
1900+ teraterm.ini で KmtLog エントリを有効にすると、通信ログを採取することができます。通信ログファイルは、ttermpro.exe と同じディレクトリに"KERMIT.LOG"という名前で生成されます。
1901+
19021902 <pre class=code>
19031903 ; Kermit log
19041904 KmtLog=on
19051905 </pre>
19061906
1907- KERMITは元々低速なシリアル通信を想定しているため、一度に送れるデータサイズはせいぜい94バイトです。ただし、拡張オプションで数千バイトのデータを扱うことはできますが、クライアントとサーバの両方が当該機能をサポートしている必要があります。<br>
1908- パケットのフォーマットは基本形式と拡張形式があり、仕様書の「Appendix I Packet Format and Types」に分かりやすい図解があります。下記に引用します。<br>
1909- 以下は基本形式です。94バイトまでしか扱えません。
1907+ KERMITは元々低速なシリアル通信を想定しているため、一度に送れるデータサイズはせいぜい94バイトです。ただし、拡張オプションで数千バイトのデータを扱うことはできますが、クライアントとサーバの両方が当該機能をサポートしている必要があります。<br>
1908+ パケットのフォーマットは基本形式と拡張形式があり、仕様書の「Appendix I Packet Format and Types」に分かりやすい図解があります。下記に引用します。<br>
1909+ 以下は基本形式です。94バイトまでしか扱えません。
19101910
19111911 <pre class=code>
19121912 Basic Kermit Packet Layout
@@ -1926,7 +1926,7 @@
19261926 CHECK 加算チェックサム。1,2,3バイトのいずれかの形式を選べる。
19271927 </pre>
19281928
1929- 以下は拡張形式です。
1929+ 以下は拡張形式です。
19301930
19311931 <pre class=code>
19321932 Kermit Extended Packet Layout
@@ -1943,11 +1943,11 @@
19431943 HCHECK is a single-character type 1 checksum
19441944 </pre>
19451945
1946- 拡張形式では94バイト以上のデータを一度に送れるようにするため、データサイズを表現する領域が2バイトに増えています。基本形式の"LEN"は常にゼロです(32を加算するので、ASCIIコードの空白になる)。また、ヘッダサイズが3バイト増えており、ヘッダ用のチェックサムが追加されています。<br>
1947- <br>
1948- 
1949- 下記は初期文字列です。
1950- 
1946+ 拡張形式では94バイト以上のデータを一度に送れるようにするため、データサイズを表現する領域が2バイトに増えています。基本形式の"LEN"は常にゼロです(32を加算するので、ASCIIコードの空白になる)。また、ヘッダサイズが3バイト増えており、ヘッダ用のチェックサムが追加されています。<br>
1947+ <br>
1948+
1949+ 下記は初期文字列です。
1950+
19511951 <pre class=code>
19521952 Initialization String
19531953 1 2 3 4 5 6 7 8 9 10
@@ -1975,7 +1975,7 @@
19751975 Low part of extended packet maximum length (mod(max,95)+32)
19761976 </pre>
19771977
1978- 下記はパケット種別です。
1978+ 下記はパケット種別です。
19791979
19801980 <pre class=code>
19811981 Packet Types
旧リポジトリブラウザで表示