これは gensio (ジェネシーオーと発音) で、さまざまなストリーム (およびパケット) I/O タイプの一貫したビューを提供するためのフレームワークです。 gensio オブジェクト (または gensio) を作成すると、その下で何が起こっているかについてあまり知らなくても、その gensio を使用できます。 gensio を別の gensio の上に積み重ねて、プロトコル機能を追加できます。たとえば、TCP gensio を作成し、その上に SSL をスタックし、その上に Telnet をスタックすることができます。多数のネットワーク I/O ポートとシリアル ポートをサポートします。サウンドインターフェイスにも対応しています。他の gensio にスタックされる gensio はフィルターと呼ばれます。
受信ポートでも同じことができます。スタック内の接続を受け入れるように gensio アクセプターをセットアップできます。したがって、前の例では、特定のポートでリッスンするように TCP を設定し、接続が確立されたときに自動的に SSL と Telnet を最上位にスタックすることができます。すべての準備が整うまで通知されません。
gensio は、Linux、BSD、MacOS、および Windows 上で動作します。 Windows では、シングルスレッド対応 (マルチスレッド対応) のイベント ドリブン インターフェイス (ブロッキング インターフェイスも利用可能) を提供し、多くの I/O を使用したプログラミングを簡素化します。これは、移植可能な I/O 駆動型コードの作成を容易にするのに大いに役立ちます。
gensio の非常に重要な機能は、gensio を使用しない場合よりも、暗号化および認証された接続の確立がはるかに簡単になることです。基本的なキー管理を除けば、TCP やその他のものほど難しいものではありません。必要に応じて認証プロセスを制御するための拡張された柔軟性を提供します。使い方はとても簡単です。
gensio(5) のマニュアル ページには、個々の gensio タイプの詳細が記載されていることに注意してください。
これをソースからビルドする手順については、最後の「ビルド」セクションを参照してください。
例として、また実験用として、gensios を使用するツールがいくつか用意されています。これらは:
接続の確立に certauth、ssl、SCTP または TCP gensios を使用する sshd のようなデーモン。標準の PAM 認証を使用し、ptys を使用します。詳細については、gtlsshd(8) を参照してください。
FAQ.rst には「Windows で gtlsshd を実行する方法」という項目があります。対処しなければならないいくつかの注意が必要なため、詳細については、それと以下の「Windows での構築」セクションを参照してください。
次の gensio がライブラリで利用可能です。
gensio スタック文字列をパラメータとして受け取る gensio アクセプター。これにより、gensio をアクセプターとして使用できるようになります。 conacc が開始されると、gensio が開き、gensio が開くと、アクセプターの新しい子が報告されます。子が閉じると、子は再び子を開いてプロセスを再度実行しようとします (conacc で受け入れが無効になっていない限り)。
なぜこれを使用したいのですか? ser2net で、あるシリアル ポートを別のシリアル ポートに接続したいとします。次のような接続が可能です。
connection : &con0
accepter : conacc,serialdev,/dev/ttyS1,115200
connector : serialdev,/dev/ttyS2,115200
そして、/dev/ttyS1 を /dev/ttyS2 に接続します。 conacc がなければ、serialdev をアクセプターとして使用できません。また、シリアル ポート経由で暗号化された認証ログインが必要な場合は、シリアル ポートで gtlsshd を使用することもできます。次のように gtlsshd を実行したとします。
gtlsshd --notcp --nosctp --oneshot --nodaemon --other_acc
' conacc,relpkt(mode=server),msgdelim,/dev/ttyUSB1,115200n81 '
次のように接続できます。
gtlssh --transport ' relpkt,msgdelim,/dev/ttyUSB2,115200n81 ' USB2
これにより、シリアル ポート経由で信頼性の高いパケット トランスポートが作成されます。 relpkt はアクセプターとして起動されていないため、通常はクライアントとして実行されるため、relpkt をサーバーとして実行するには、mode=server が必要です。 ssl gensio (トランスポート経由で実行される) は信頼性の高い通信を必要とするため、シリアル ポート経由で直接実行されません。
はい、文字がごちゃ混ぜになっているように見えます。
Sound gensio の上に置かれ、AX.25 アマチュア無線で使用されているようなオーディオ周波数シフト キーイング モデムを実行するフィルター gensio。
パケット無線用のアマチュア無線プロトコル。これを完全に使用するには、番号なしの情報にチャネルと oob データを使用するため、コードを記述する必要がありますが、必要な通信チャネルが 1 つだけであれば、gensiot だけで基本的なことを行うことができます。たとえば、無線で誰かとチャットしたい場合、両方のマシンの Kiss ポートが 8001 にある場合、受け入れ側のマシンで次のコマンドを実行できます。
gensiot -i ' stdio(self) ' -a
' ax25(laddr=AE5KM-1),kiss,conacc,tcp,localhost,8001 '
これは TNC にフックし、アドレス AE5KM-1 での接続を待ちます。次に、次を実行できます。
gensiot -i ' stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,AE5KM-1,AE5KM-2"),kiss,tcp,localhost,8001 '
他のマシン上で。これにより、指定されたアドレスを持つ TNC 0 を介して他のマシンに接続されます。そうすると、一方に入力した内容がもう一方に 1 行ずつ表示されます。 「Ctrl-D」を入力して終了します。 「stdio(self)」部分は raw モードをオフにするため、一度に 1 行ずつ実行され、ローカル エコーが得られます。そうしないと、入力した文字ごとにパケットが送信され、入力している文字が見えなくなります。
N5COR-11 AX.25 BBS システムに接続するには、次のようにします。
gensiot -i ' xlt(nlcr),stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,N5COR-11,AE5KM-2"),kiss,tcp,localhost,8001 '
ほとんどの BBS システムは改行に NL ではなく CR を使用するため、xlt gensio を使用して受信文字を変換します。
もちろん、これは gensio なので、必要な実行可能な gensio を ax25 の下に置くことができます。したがって、無線を使用せずに遊んだりテストしたりしたい場合は、UDP マルチキャスト経由で ax25 を実行できます。アクセプタ側は次のとおりです。
gensiot -i ' stdio(self) ' -a
' ax25(laddr=AE5KM-1),conacc, '
' udp(mcast="ipv4,224.0.0.20",laddr="ipv4,1234",nocon), '
' ipv4,224.0.0.20,1234 '
コネクタ側は次のとおりです。
gensiot -i ' stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,AE5KM-1,AE5KM-2"), '
' udp(mcast="ipv4,224.0.0.20",laddr="ipv4,1234",nocon), '
' ipv4,224.0.0.20,1234 '
UDP はすでにパケット指向のメディアであるため、kiss は必要ありません。または、グレフレクター プログラムを使用して、シミュレートされた無線状況を作成することもできます。マシン「radiopi2」で次を実行します。
greflector kiss,tcp,1234
これにより、受信したすべての入力を他のすべての接続に反映するプログラムが作成されます。次に、アクセプタ側で次のようにします。
gensiot -i ' stdio(self) ' -a
' ax25(laddr=AE5KM-1),kiss,conacc,tcp,radiopi2,1234 '
そして接続側:
gensiot -i ' stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,AE5KM-1,AE5KM-2"),kiss,tcp,radiopi2,1234 '
リフレクターは非常に便利なので、テスト コードでは一部のテストにリフレクターを使用します。
これらはすべて gensio(5) に詳細に記載されています。特に明記されていない限り、これらはすべてアクセプターまたは接続 gensio として利用できます。
独自の gensio を作成してライブラリに登録し、他の gensio と一緒にスタックすることができます。
これを行う最も簡単な方法は、必要なことを実行するコードを gensio から盗み、それを変更して独自の gensio を作成することです。残念ながら、これを行う方法についての適切なドキュメントはありません。
インクルード ファイル include/gensio/gensio_class.h には、メインの gensio ライブラリと gensio 間のインターフェイスがあります。 gensio 呼び出しはすべて、要求されている関数を識別するための番号を持つ単一の関数を介して行われます。これらすべてを実際の操作にマッピングする必要があります。これは多少面倒ですが、これにより、上位互換性と下位互換性がはるかに簡単になります。
この方法で独自の gensio を作成するのはかなり複雑です。このようなもののステートマシンは驚くほど複雑になる場合があります。掃除が最も難しい部分です。すべてのコールバックが存在しないこと、およびシャットダウン時に競合状態でタイマーがコールバックされないことを確認する必要があります。最も単純な gensio (echo、dummy)、奇妙な gensio (conadd、keepopen、stdio)、およびチャネルを持つ gensio (mux、ax25) のみがインターフェイスを直接実装します。それ以外はすべて include/gensio/gensio_base.h を使用します。 gensio_base は、gensio の基本的なステート マシンを提供します。これには、フィルター部分 (オプション) と、そうでない低レベル (ll) 部分があります。
フィルター インターフェイスでは、処理のためにデータが実行されます。これは、ssl、certauth、ratelimit などに使用されます。フィルター gensios はこれを使用します。これらはすべて、ll に gensio_ll_gensio (gensio を別の gensio の上に積み重ねるため) を使用します。
ターミナル gensio にはそれぞれ独自の ll があり、通常はフィルターがありません。ファイル記述子 (fd) に基づく ll の場合は、gensio_ll_fd が使用されます。 IPMI Serial-over-LAN (ipmisol) およびサウンド用の ll もあります。ほとんどの端末 gensio (tcp、udp、sctp、シリアル ポート、pty) は、明らかに fd ll を使用します。
gensio を取得したら、それをモジュールとしてコンパイルし、$(moduleinstalldir)/<version> に貼り付けることができます。そうすれば、gensio はそれを拾って使用します。また、アプリケーションにリンクして、アプリケーションから init 関数を実行することもできます。
mdns gensio についてはすでに説明しましたが、gensio ライブラリは使いやすい mDNS インターフェイスを提供します。このインクルード ファイルは gensio_mdns.h にあり、gensio_mdns(3) のマニュアル ページを使用して詳細を取得できます。
gensiot を使用して mdns 接続を確立するには、次のように mdns を有効にして ser2net を設定したとします。
connection : &my-port
accepter : telnet(rfc2217),tcp,3001
connector : serialdev,/dev/ttyUSB1,115200N81
options :
mdns : true
次に、gensiot を使用して接続できます。
gensiot ' mdns,my-port '
gensiot はサーバー、ポート、および Telnet と rfc2217 が有効かどうかを見つけて接続を確立します。
さらに、クエリとアドバタイズメントを実行できる gmdns ツールがあり、gtlssh はサービスを見つけるために mDNS クエリを実行できます。 ser2net の安全な認証されたログインがあり、ser2net で mdns を有効にすると、次のようになります。
connection : &access-console
accepter : telnet(rfc2217),mux,certauth(),ssl,tcp,3001
connector : serialdev,/dev/ttyUSBaccess,115200N81
options :
mdns : true
次のようにするだけでセットアップが非常に便利になります。
gtlssh -m access-console
そうです。接続名を直接使用できます。ホスト、Telnet または rfc2217 が有効かどうか、またはポートが何であるかを知る必要はありません。もちろん、その指示に従って、ser2net サーバー上にキーなどを設定する必要があります。
gensio には、イベント駆動型のオブジェクト指向インターフェイスがあります。同期インターフェースも利用できます。 gensio では、gensio と gensio アクセプターという 2 つの主要なオブジェクトを扱います。 gensio は、接続、切断、書き込み、受信などができる通信インターフェイスを提供します。
gensio アクセプターを使用すると、受信接続を受信できます。接続があれば、ジェンシオが得られます。
インターフェイスはほとんどの場合完全にノンブロッキングであるため、イベント駆動型です。 gensio を開く場合は、接続が確立されたとき、または接続が失敗したときに呼び出されるコールバックをそれに与えます。近い場合も同様です。書き込みでは、受け入れられたバイト数が返されますが、すべてのバイト (または一部のバイト) が使用されるわけではないため、呼び出し元はそれを考慮する必要があります。
オープン インターフェイスとクローズ インターフェイスには、便宜上、セカンダリ ブロッキング インターフェイスがあります。これらは _s で終わります。これは便宜上のものですが、必須ではありません。実際にはコールバックからは使用できないため、使用には注意が必要です。
コールバックと言えば、gensio からユーザーに送られるデータと情報は関数コールバックで行われます。データを読み取り、gensio が書き込みの準備ができると、データがコールバックで返されます。ユーザーから gensio レイヤーへの呼び出しには同様のインターフェイスが使用されますが、ユーザーには表示されません。この種のインターフェイスは拡張が容易で、古いインターフェイスを壊すことなく新しい操作を簡単に追加できます。
このライブラリには、gensio または gensio アクセプターを作成するためのいくつかの方法が用意されています。主な方法は str_to_gensio() と str_to_gensio_accepter() です。これらは、gensio またはアクセプターのスタックを文字列として指定してビルドする方法を提供します。一般に、可能であればこのインターフェイスを使用する必要があります。
一般に、パフォーマンスに依存しないインターフェイスは文字列ベースです。これは、gensio_control と、書き込みの特定の側面を制御するための読み取りおよび書き込みインターフェイスの補助データで確認できます。
このライブラリには、gensios をそれぞれ個別に作成してセットアップする方法も提供されています。状況によってはこれが必要になる場合がありますが、gensio ライブラリの拡張に伴う新機能の使用が制限されます。
gensio が複数のストリーム (SCTP など) をサポートしている場合、ストリーム番号は「stream=n」を使用して auxdata で渡されます。ストリームは個別にフロー制御されません。
一方、チャネルは、同じ接続上の個別のデータ フローです。チャネルは個別の gensio として表され、個別にフローを制御できます。
gensios を使用するときに処理する必要がある可能性のあるインクルード ファイルがいくつかあります。
これらの大部分はマニュアルページに記載されています。
独自の gensio を作成するには、次のインクルード ファイルを使用できます。
各インクルード ファイルには、個々の呼び出しとハンドラーに関する多くのドキュメントが含まれています。
gensio には、OS エラー (GE_xxx という名前) から抽象化する独自のエラー セットがあり、エラー レポートの柔軟性が向上します。これらは gensio_err.h インクルード ファイル (gensio.h から自動的にインクルードされる) 内にあり、gensio_err_to_str() を使用して数値から意味のある文字列に変換できます。ゼロはエラーではないと定義されています。
認識できないオペレーティング システム エラーが発生した場合、GE_OSERR が返され、OS ハンドラー ログ インターフェイスを通じてログが報告されます。
gensio に関して少し面倒な点の 1 つは、メモリ割り当て、ミューテックス、ファイル記述子、タイマーと時間、その他いくつかのものを処理する機能などの OS タイプの関数を処理するために、OS ハンドラー (struct gensio_os_funcs) を提供する必要があることです。
ライブラリにはいくつかの OS ハンドラーが用意されています。 gensio_alloc_os_funcs() を呼び出して、システム (POSIX または Windows) にデフォルトの関数を割り当てることができます。詳細については、その man ページを参照してください。通常、これはシステムにとって最高のパフォーマンスを発揮するオプションです。
POSIX システムの場合、glib および TCL の OS ハンドラーが利用可能で、gensio_glib_funcs_alloc() および gensio_tcl_funcs_alloc() で割り当てられます。これらは実際にはあまりうまく機能しません。特にパフォーマンスの観点から見ると、glib と TCL の API は gensio の機能に合わせて適切に設計されていません。 TCL はシングルスレッド操作のみをサポートします。 glib マルチスレッド操作では、I/O を待機するスレッドは一度に 1 つだけです。しかし、それらは機能し、テストはそれらを使用して実行されます。これらは、glib の抽象化が不十分であり、TCL の動機が欠如しているため、Windows では利用できません。
ただし、独自のイベント ループを持つ X Windows などの別のものを使用している場合は、ニーズに合わせてイベント ループを調整する必要があるかもしれません。しかし、良い点は、これを行うことができ、gensio をほとんどあらゆるものと統合できることです。
イベント ループの実行中に何かが発生するのを待つための便利な方法を提供するウェイター インターフェイスもあります。これは、イベント ループに入る一般的な方法です。これは、イベント ループが終了してループを終了する必要があることを知らせる便利な方法となるためです。
これに関するドキュメントは次の場所にあります。
include/gensio/gensio_os_funcs.h
gensio ライブラリはスレッドを完全にサポートしており、完全にスレッドセーフです。ただし、POSIX システムではシグナルを使用し、Windows システムでは COM を使用するため、いくつかの設定が必要です。
「メイン」スレッドは起動時に gensio_os_proc_setup() を呼び出し、完了時に gensio_os_proc_cleanup() を呼び出す必要があります。これにより、シグナルとシグナル ハンドラー、Windows 上のスレッド ローカル ストレージ、その他の種類のものが設定されます。
gensio_os_new_thread() を使用して、すでに設定されているスレッドから新しいスレッドを生成できます。これにより、基本的な OS スレッドが提供され、gensio 用に適切に設定されます。
他の方法で作成されたスレッドを gensio で使用したい場合は、そのスレッドが別のスレッドを作成し、ブロッキング関数 (あらゆる種類の待機、バックグラウンド処理、read_s などの _s で終わる関数、など)設定する必要はありません。そうすることで、一部の外部スレッドがデータを書き込んだり、別のスレッドを起動したり、そのようなことを行うことができます。
外部スレッドがこれらのことを行う必要がある場合は、gensio_os_thread_setup() を呼び出す必要があります。
スレッドのセクションで述べたように、Unix 上の gensio ライブラリはスレッド間のウェイクアップにシグナルを使用します。よく考えてみましたが、これをきれいに行う方法は他にありません。ただし、Windows にもシグナルに似たものがいくつかあり、これらは gensio でも利用できます。
gensio_alloc_os_funcs() を使用すると、IPC に渡された信号を使用して OS 関数を取得します。デフォルト (SIGUSR1) が必要な場合は、シグナルの GENSIO_OS_FUNCS_DEFAULT_THREAD_SIGNAL を渡すことができます。あなたが使用する信号はブロックされ、gensio によって引き継がれるため、使用できなくなります。
gensio は、いくつかの信号に対する汎用処理も提供します。 Unix では、gensio_os_proc_register_reload_handler() 関数を通じて SIGHUP を処理します。
Windows および Unix では、終了要求 (UNIX では SIGINT、SIGTERM、SIGQUIT) と gensio_os_proc_register_winsize_handler() (UNIX では SIGWINCH) を処理する gensio_os_proce_register_term_handler() を使用できます。これらが Windows 経由でどのように入ってくるかは少し複雑ですが、ユーザーには見えません。
シグナル ハンドラーからではなく、待機ルーチンの待機からのすべてのコールバック。そうすればあなたの生活は大幅に簡素化されるはずです。
これらすべての詳細については、man ページを参照してください。
gensio を作成するには、適切にフォーマットされた文字列を使用してstr_to_gensio()
を呼び出すのが一般的な方法です。文字列は次のようにフォーマットされます。
<タイプ>[([<オプション>[,<オプション[...]]])][,<タイプ>...][,<終了オプション>[,<終了オプション>]]
end option
、ターミナル gensio、またはスタックの一番下にある gensio 用です。たとえば、 tcp,localhost,3001
localhost のポート 3001 に接続する gensio を作成します。シリアル ポートの例としては、 serialdev,/dev/ttyS0,9600N81
があり、シリアル ポート /dev/ttyS0 への接続が作成されます。
これにより、gensio レイヤーの上に gensio レイヤーを積み重ねることができます。たとえば、TCP 接続の上に Telnet を重ねるには、次のようにします。
telnet,tcp,localhost,3001
Telnet 接続で RFC2217 を有効にするとします。それを行うためのオプションを追加できます。
telnet(rfc2217=true),tcp,localhost,3001
gensio を作成するときは、ユーザー データを含むコールバックを提供します。 gensio でイベントが発生すると、ユーザーが処理できるようにコールバックが呼び出されます。
gensio アクセプターは接続する gensio に似ていますが、代わりにstr_to_gensio_accepter()
を使用します。形式は同じです。例えば:
telnet(rfc2217=true),tcp,3001
Telnet をトップとする TCP アクセプターを作成します。アクセプターの場合、ローカル マシン上のすべてのインターフェイスにバインドする場合は、通常、ホスト名を指定する必要はありません。
gensio を作成しても、まだ開いていないか、運用可能ではありません。使用するには、それを開く必要があります。それを開くには、次のようにします。
struct gensio * io ;
int rv ;
rv = str_to_gensio ( "tcp,localhost,3001" , oshnd ,
tcpcb , mydata , & io );
if ( rv ) { handle error }
rv = gensio_open ( io , tcp_open_done , mydata );
if ( rv ) { handle error }
gensio_open()
戻ったとき、gensio は開いていないことに注意してください。コールバック (この場合はtcp_open_done()
) が呼び出されるまで待つ必要があります。その後、ご利用いただけます。
gensio が開いても、受信がオフになっているため、すぐにはデータを取得できません。データ受信時にコールバック (この場合はtcpcb
) を呼び出すかどうかをオンまたはオフにするには、 gensio_set_read_callback_enable()
を呼び出す必要があります。
読み取りハンドラーが呼び出されると、バッファーと長さが渡されます。すべてのデータを処理できない場合でも、すべてのデータを処理する必要はありません。実際に処理したバイト数で buflen を更新する必要があります。データを処理しない場合、処理されなかったデータは後で使用するために gensio にバッファリングされます。すべてのデータを処理しない場合は、読み取り有効化をオフにする必要があるというわけではありません。そうしないと、イベントがすぐに再度呼び出されます。
接続で何か問題が発生した場合、エラーが設定された読み取りハンドラーが呼び出されます。この場合、 buf
とbuflen
NULL になります。
書き込みの場合は、 gensio_write()
を呼び出してデータを書き込むことができます。 gensio_write()
、開いている gensio でいつでも使用できます。 gensio_write()
書き込むすべてのデータを取得できるわけではありません。 count
パラメータは、書き込み呼び出しで実際に取得されたバイト数を返します。
送信するデータがあるときにgensio_set_write_callback_enable()
呼び出すようにコードを設計すると、gensio が書き込み準備完了コールバックを呼び出し、そのコールバックから書き込むことができます。これは一般に単純ですが、書き込みコールバックを有効または無効にすると、オーバーヘッドが追加されます。
より効率的なアプローチは、必要なときにいつでもデータを書き込み、書き込みコールバックを無効にすることです。書き込み操作が完全なリクエストよりも少ない量を返す場合は、もう一方の端がフロー制御されているため、書き込みコールバックを有効にして、それが呼び出されるまで待ってからさらにデータを送信する必要があります。
コールバックでは、 gensio_get_user_data()
を使用して作成呼び出しに渡したユーザー データを取得できます。
gensio を開いてすぐに閉じる場合、たとえ open コールバックが呼び出されていなくても、これは問題ないことに注意してください。ただし、その場合、オープン コールバックが呼び出される場合と呼び出されない場合があるため、これを適切に処理するのが難しい場合があります。
gensios を使用すると、基本的な同期 I/O を実行できます。これは、何かをインラインで読み取る必要がある場合に便利です。これを行うには、次のように呼び出します。
err = gensio_set_sync ( io );
指定された gensio は、読み取りおよび書き込みイベントの配信を停止します。その他イベント配信も行っております。次に、次のことができます。
err = gensio_read_s ( io , & count , data , datalen , & timeout );
err = gensio_write_s ( io , & count , data , datalen , & timeout );
Count は、実際の読み取り/書き込みバイト数に設定されます。気にしない場合は NULL にすることもできます (ただし、読み取りにはあまり意味がありません)。
タイムアウトが NULL である可能性があります。その場合は、永遠に待機します。タイムアウトを設定すると、残り時間に更新されます。
シグナルによってこれらはすぐに返されますが、エラーは報告されないことに注意してください。
データが到着してそのデータが返されるまで、読み取りはブロックされます。バッファがいっぱいになるまで待機しません。 timeout が timeval である場合、読み取りは読み取りが完了して戻るまでその時間待機します。タイムアウトはエラーではなく、カウントがゼロに設定されるだけです。
バッファ全体が書き込まれるかタイムアウトが発生するまで、書き込みはブロックされます。繰り返しますが、タイムアウトはエラーではなく、実際に書き込まれた合計バイト数が count で返されます。
gensio による同期 I/O の実行が完了したら、次を呼び出します。
err = gensio_clear_sync ( io );
イベント インターフェイスを介した配信は以前と同様に継続されます。これを呼び出すときは、同期読み取りまたは書き込み呼び出しを実行しないでください。結果は未定義になります。
同期 I/O を待機しているときに、他の gensio 上の他の I/O が引き続き発生することに注意してください。
現在、同期 I/O で複数の gensio を待機する方法はありません。それを行う場合は、実際にはイベント駆動型 I/O を使用する必要があります。そのほうが効率的ですが、結局は同じことをすることになります。
gensio と同様、gensio アクセプターは作成時には動作しません。これを有効にするには、 gensio_acc_startup()
を呼び出す必要があります。
struct gensio_accepter * acc ;
int rv ;
rv = str_to_gensio_accepter ( "tcp,3001" , oshnd ,
tcpacccb , mydata , & acc );
if ( rv ) { handle error }
rv = gensio_startup ( acc );
if ( rv ) { handle error }
起動呼び出しがいつ有効になっているかを知るための起動呼び出しへのコールバックはないことに注意してください。起動呼び出しには書き込むことができず、コールバックのみが行われるため、実際に知る必要はありません。
アクセプターを起動した後でも、 gensio_acc_set_accept_callback_enable()
を呼び出してコールバックを有効にするまでは、何も行われません。
コールバックが呼び出されると、読み取りが無効になってすでに開かれているdata
パラメーターに gensio が提供されます。 gensio アクセプターから受け取った gensio には、いくつかの制限がある場合があります。たとえば、閉じて再度開くことができない場合があります。
gensio アクセプタは、 gensio_acc_set_sync()
およびgensio_acc_accept_s
を使用して同期受け入れを行うことができます。詳細については、それらの man ページを参照してください。
struct gensio_os_funcs
内部 gensio ログを処理するための vlog コールバックがあります。これらは、何か重要なことが起こったときに呼び出されますが、gensio にはエラーを報告する方法がありません。また、何か問題が発生したときに問題を診断しやすくするために呼び出される場合もあります。
gensio クラスと gensio アクセプター クラスには、それぞれシリアル I/O を処理し、シリアル ポートに関連付けられたすべてのパラメーターを設定するためのサブクラスがあります。
gensio_to_sergensio()
を呼び出すことで、gensio (またはその子) がシリアル ポートかどうかを確認できます。 NULL を返した場合、それは sergensio ではなく、その子のどれも sergensio ではありません。 NULL 以外を返した場合は、使用できる sergensio オブジェクトが返されます。 sergensio_to_gensio()
によって返される gensio は、 gensio_to_sergensio()
に渡されるものであり、必ずしも sergensio が直接関連付けられている gensio ではないことに注意してください。
sergensio は、シリアル設定を設定できるクライアントである場合もあれば、接続の相手側からシリアル設定を受信するサーバーである場合もあります。
ほとんどの sergensio はクライアント専用です。serialdev (通常のシリアル ポート)、ipmisol、および stdio アクセプターです。現在、クライアントとサーバーの両方の機能を備えているのは Telnet だけです。
注: ここで説明する Python インターフェイスは非推奨です。今は c++/swig/pygensio のものを使用してください。
Python を介してほぼすべての gensio インターフェイスにアクセスできますが、その方法は C インターフェイスとは少し異なります。
Python は完全なオブジェクト指向であるため、gensios と gensio アクセプターは、gensio_os_funcs、sergensios、waiter とともにファーストクラスのオブジェクトです。
以下に小さなプログラムを示します。
import gensio
class Logger :
def gensio_log ( self , level , log ):
print ( "***%s log: %s" % ( level , log ))
class GHandler :
def __init__ ( self , o , to_write ):
self . to_write = to_write
self . waiter = gensio . waiter ( o )
self . readlen = len ( to_write )
def read_callback ( self , io , err , buf , auxdata ):
if err :
print ( "Got error: " + err )
return 0
print ( "Got data: " + buf );
self . readlen -= len ( buf )
if self . readlen == 0 :
io . read_cb_enable ( False )
self . waiter . wake ()
return len ( buf )
def write_callback ( self , io ):
print ( "Write ready!" )
if self . to_write :
written = io . write ( self . to_write , None )
if ( written >= len ( self . to_write )):
self . to_write = None
io . write_cb_enable ( False )
else :
self . to_write = self . to_write [ written :]
else :
io . write_cb_enable ( False )
def open_done ( self , io , err ):
if err :
print ( "Open error: " + err );
self . waiter . wake ()
else :
print ( "Opened!" )
io . read_cb_enable ( True )
io . write_cb_enable ( True )
def wait ( self ):
self . waiter . wait_timeout ( 1 , 2000 )
o = gensio . alloc_gensio_selector ( Logger ())
h = GHandler ( o , "This is a test" )
g = gensio . gensio ( o , "telnet,tcp,localhost,2002" , h )
g . open ( h )
h . wait ()
このインターフェイスは、C インターフェイスをほぼ直接変換したものです。インターフェイスの Python 表現は swig/python/gensiodoc.py にあり、ドキュメントで参照できます。
C++ インターフェイスについては、c++/README.rst に記載されています。
新しい pygensio インターフェイスは、Python に手動でコード化されたコールバックの代わりに swig ディレクターを使用した、よりクリーンな実装です。 c++/swig/pygensio の README.rst を参照してください。 glib および tcl ディレクトリには、glib および tcl OS_Funcs もあります。
完全な C++ インターフェイスは、swig および swig ディレクターを通じて Go プログラムで利用できます。詳細については、c++/swig/go/README.rst を参照してください。
これは通常の autoconf システムであり、特別なものではありません。これを git から直接取得した場合、ビルド インフラストラクチャが含まれないことに注意してください。メインディレクトリには、これを作成する「reconf」という名前のスクリプトがあります。
autoconf について知らない場合は、INSTALL ファイルに情報があるか、Google で調べてください。
gensio を完全にビルドするには、次のものが必要です。
以下は、openipmi を除くすべてを ubuntu 20.04 で設定します。
- sudo apt install gcc g++ git swig python3-dev libssl-dev pkg-config
- libavahi-client-dev avahi-daemon libtool autoconf automake make libsctp-dev libpam-dev libwrap0-dev libglib2.0-dev tcl-dev libasound2-dev libudev-dev
Redhat では libwrap がなくなったため、これを使用することはできません。また、swig も利用できないようです。そのため、少なくとも go と Python をサポートして自分でビルドする必要があります。 Redhat のようなシステムのコマンドは次のとおりです。
- sudo yum install gcc gcc-c++ git python3-devel swig openssl-devel
- pkg-config avahi-devel libtool autoconf automake lksctp-tools-devel pam-devel glib2-devel tcl-devel alsa-lib-devel systemd-devel
開発パッケージへのアクセスを有効にするには、以下を実行する必要がある場合があります。
sudo dnf config-manager - set-exhabled devel
そして、SCTPカーネルモジュールを取得する必要があるかもしれません。
Sudo YumインストールKernel-Modules-Extra
GO言語を使用するには、SWIG 4.1.0以降のバージョンを取得する必要があります。 Gitから出血エッジバージョンを引き出して使用する必要がある場合があります。
Pythonのインストール構成の取り扱いは少し苦痛です。デフォルトでは、ビルドスクリプトは、PythonプログラムがインストールされたPythonプログラムが予想される場所に配置されます。通常のユーザーは通常、そのディレクトリへの書き込みアクセスがありません。
これをオーバーライドするには、-with-pythoninstallと-with-pythoninstalllib configure optionsを使用するか、ライブラリとモジュールの移動する場所にpythoninstalldirおよびpythoninstalllibdir環境変数を設定できます。
lockdirに - UUCPロックを設定する必要がある場合があることに注意してください(古いシステムでは/var/lockです。これはデフォルトです。新しい場合は/run/lock/lockdevである可能性があります。シリアルデバイスやロックを開くことができるように、ダイヤルアウトおよびロックグループのメンバー。
GO言語サポートには、インストールしてパスに移動する必要があります。
Crypto、MDNS、Sound、IPMI、SCTPなどのようなライブラリにGensiosを追加し続けました。ライブラリの依存関係の数は制御不能になっています。必要にならないのに、なぜLibasound、またはLibopenipmiをロードする必要があるのですか?さらに、図書館はプログラマティックAPIを介して独自のGensiosを追加することをサポートしていましたが、システムにそれらを追加する標準的な方法はありませんでした。
Gensio Libraryは、Gensiosを動的にロードするか、ライブラリに組み込むことをサポートしています。デフォルトでは、共有ライブラリを作成する場合、すべてのGensiosは動的荷重のモジュールとしてコンパイルされ、可能な場所にインストールされます。共有ライブラリを作成しない場合、すべてのGensiosがライブラリに組み込まれています。ただし、この動作をオーバーライドできます。
すべてのGensiosをライブラリに組み込むように設定するには、Configureコマンドラインに「-all-all-gensios = yes」を追加でき、ライブラリに組み込まれます。
また、「-all-all-gensios = dynamic」を追加することにより、すべてを動的にロードすることもできますが、これはデフォルトです。
また、「-all-all-gensios = no」を指定することにより、デフォルトですべてのGensiosを無効にすることもできます。デフォルトでは、Gensiosは構築されません。これは、いくつかのGensiosしか必要ない場合に便利です。すべてのGensiosをオフにしてから、必要なものを有効にすることができます。
個々のgensiosがどのように構築されるかを設定するには、 "-with- <gensio> = x" "ここで、xは" no(build)、yes(build into build into build)or dynamic(動的にロードされた実行可能ファイル)を行います。たとえば、たとえば、 TCP Gensioをライブラリに組み込み、RESTを動的にしたい場合は、すべての動的なGensiosを設定してから、「-net = yes」を追加できます。
これらのモジュールはデフォルトで配置されます
ライブラリ内のすべてのGensiosを構築しても、動的荷重が常に利用可能であることに注意してください。そのため、適切なディレクトリに追加することで、独自のGensiosを追加できます。
Gensiosは、最初に環境変数LD_LIBRARY_PATHからロードされ、次にgensio_library_pathから、次にデフォルトの場所からロードされます。
ある種の* nixであるMacosは、Homebrew(https://brew.sh)でかなりきれいに構築されています。もちろん、必要なすべてのライブラリをインストールする必要があります。次の例外を除いて、ほとんどすべてが機能します。
* CM108GPIO * sctp * UUCPロック
組み込みのDNSSDコードはMDNに使用されるため、Avahiは必要ありません。
シリアルポート用の群れロックは機能するため、UUCPロックは本当に必要ありません。
Openipmiは機能するはずですが、Homebrewでは利用できないため、自分で構築する必要があります。
必要なソフトウェアをインストールします。
- PKGインストールGCC PORTAUDIO AUTOCONF AUTOMAKE LIBTOOL MDNSRESPONDER SWIG
- python3 gmakeに行きます
Gmakeを使用してコンパイルする必要があります。何らかの理由で、BSD上の標準メイクは要件のリストに「C ++」変数を受け入れません。以下は機能せず、編集されていません。
* sctp * IPMISOL * CM108GPIO
/etc/rc.confに以下を追加します。
MDNSD_ENABLE =はい
再起動またはサービスを開始します。
Pty gensioはoomtest(oomtest 14)に失敗し、BSD Ptysに何かがあるようです。ケースでデータストリームに07文字が挿入されているのが見えます。しかし、私はそれにあまり時間を費やしていませんが、これはLinuxとMacosで頻繁にテストされているため、問題はGensioコードにあるとは思いません。
Gensioライブラリは、MINGW64を使用してWindowsの下に構築できます。次のことは機能しません:
* sctp *パム * libwrap * IPMISOL
また、ALSAをインストールする必要はありません。WindowsSoundインターフェイスをサウンドに使用します。
CM108GPIOはネイティブWindowsインターフェイスを使用するため、UDEVは必要ありません。
Windows内蔵のMDNSインターフェイスが使用されるため、AvahiやDNSSDは必要ありません。正規表現が必要な場合は、PCREライブラリをインストールする必要があります。
https://msys2.orgからmsys2を取得する必要があります。次に、ホストツールとしてAutoconf、autoconf、libtool、git、make、swigをインストールします。
Pacman -S Autoconf Automake libtool git make swig
すべてのライブラリのMINGW-W64-X86_64-XXXバージョンまたはすべてのライブラリのMINGW-W64-I686-XXXバージョンをインストールする必要があります。 32ビットは十分にテストされていません:
Pacman -S MingW-W64-X86_64-GCC MingW-W64-X86_64-Python3 mingw-w64-x86_64-pcre MINGW-W64-X86_64-Openssl
MINGW64の場合、またはUCRT64の場合:
Pacman -S MINGW-W64-UCRT-X86_64-GCC mingw-w64-ucrt-x86_64-python3 mingw-w64-ucrt-x86_64-pcre MINGW-W64-UCRT-X86_64-OPENSSL
Goの場合は、https://go.devから移動してログアウトしてログインします。その後、パスにログインしますが、そうでない場合はパスに追加する必要があります。 MINGW32に取り組むことはできませんでしたが、32ビットバージョンのGoを試していません。
gtlsshdの場合、-sysconfdirにはWindowsで意味がありません。代わりに、sysconf dirは、in in firtc/gtlsshの実行可能ファイルのパッチに関連しています。したがって、gtlsshdが存在する場合:
C:/プログラムファイル/gensio/bin/gtlsshd
sysconfdirは次のとおりです。
c:/プログラムファイル/gensio/etc/gtlssh
標準インストールの場合、実行できます。
../configure - sbindir =/gensio/bin - libexecdir =/gensio/bin -mandir =/gensio/man -includedir =/gensio/include -with-pythoninstall =/gensio/python3 - -prefix =/gensio
「install destdir = ...」を実行すると、「c:/プログラムファイル」のように、destdirを行きたい場所に設定します。次に、コントロールパネルを使用してパスに追加できます。 GTLSSHDを使用するには、GensioディレクトリにETC/GTLSSHDディレクトリを作成します。このディレクトリに権限を設定する必要があります。これにより、システムと管理者のみがアクセスできます。
PS c:プログラムファイル(x86) gensio etc> icacls gtlssh gtlssh nt authority system :( oi)(ci)(f) Builtin Administrators:(oi)(ci)(f)
それ以外の場合、GTLSSHDは、キーの権限に関するエラーで失敗します。これらの許可をディレクトリの代わりに.keyファイルに設定できますが、新しいキーを生成するたびに再度設定する必要があります。
Innoセットアップコンパイラを使用するには、「destdir = $ home/install」を「インストール」してから、gensio.issでinnoを実行します。 Gensioをインストールするための実行可能なインストーラーを作成します。
次に、インストールディレクトリから.LAファイルを削除する必要があります。
rm $ home/install/gensio/lib/*。la
Gensiosのテストは多数あります。シリアルシムカーネルモジュールがある場合、それらはすべてLinuxで実行されます。シリアルポートのものに加えて、Gensiosがそのプラットフォームでサポートされているため、他のプラットフォームで実行されます。
シリアルポートテストでは、シリアルシムカーネルモジュールとPythonインターフェイスが必要です。これらはhttps://github.com/cminyard/serialsimにあり、テストでシミュレートされたシリアルポートを使用してモデム制御ライン、注入エラーなどを読み取ることができます。
3つのシリアルデバイスがある場合は、SerialSimなしでは、1つがエコーモード(RXとTXが一緒に結ばれます)をフックし、2つのシリアルデバイスを一緒にフックしている場合は、1つのデバイスでI/Oが他のデバイスに由来します。これは、非Linuxプラットフォームで動作するはずです。次に、次の環境変数を設定します。
export GENSIO_TEST_PIPE_DEVS= " /dev/ttyxxx:/dev/ttywww "
export GENSIO_TEST_ECHO_DEV= " /dev/ttyzzz "
ModemStateまたはRS485をテストすることはできません。
また、IPMISOLテストを実行するには、https://github.com/cminyard/openipmiのOpenIPMIライブラリのIPMI_SIMプログラムも必要です。
テストを実行するには、完全な効果を得るために内部デバッグを有効にする必要があります。あなたは一般的に次のようなものを実行したいです:
./configure --enable-internal-trace CFLAGS= ' -g -Wall '
必要に応じて、CFLAGSで-O3をオンにすることもできますが、デバッグを難しくします。
テストには2つの基本的なタイプがあります。 Pythonテストは、PythonインターフェイスとGensioライブラリの両方をテストする機能的テストです。現在、彼らは大丈夫ですが、改善の余地が十分にあります。支援したい場合は、テストを作成できます。
OOMTESTはかつてはメモリテスターから外れていましたが、より広範なものに変身しています。特定のポイントで失敗し、メモリリークやその他のメモリチェックを行うために、特定の環境変数を備えたジェンシオットプログラムを生成します。 Stdinを通じてJensiotにデータを書き込み、Stdoutのデータを受信します。一部のテスト(SerialDevなど)はエコーを使用します。他のテストはネットワーク上に個別の接続を行い、データがStdinの両方に流れ込み、個別の接続に戻り、別の接続に流れ込み、Stdoutを介して戻ってきます。 oomtestはマルチスレッドで、スレッドの数を制御できます。 Oomtestは多くのバグを見つけました。たくさんのノブがありますが、オプションのソースコードを確認する必要があります。誰かがボランティアをしたい場合は、文書化する必要があります...
ファジング用にセットアップするには、AFLをインストールしてから、次のように構成します。
mkdir Zfuzz ; cd Zfuzz
../configure --enable-internal-trace=yes --disable-shared --with-go=no
CC=afl-gcc CXX=afl-g++
または、利用可能な場合はClangを使用します。
../configure --enable-internal-trace=yes --disable-shared --with-go=no
CC=afl-clang-fast CXX=afl-clang-fast++ LIBS= ' -lstdc++ '
なぜLibsのものが上記で必要なのかはわかりませんが、コンパイルするために追加する必要がありました。
次に、構築します。次に、「CDテスト」と実行「test_fuzz_xxx」を作成します。ここで、xxxはcertauth、mux、ssl、telnet、またはrelpktの1つです。おそらくいくつかのことを調整する必要があるでしょう、AFLはあなたに伝えます。それは永遠に実行されることに注意してください、あなたが終わったらそれを ^cする必要があります。
テスト/makefile.amのmakefileには、デバッグのために再現の失敗を処理する方法についての指示があります。
ライブラリでコードカバレッジを実行するのは非常に簡単です。まず、カバレッジを有効にするためにコードを構成する必要があります。
mkdir Ocov ; cd Ocov
../configure --enable-internal-trace=yes
CC= ' gcc -fprofile-arcs -ftest-coverage '
CXX= ' g++ -fprofile-arcs -ftest-coverage '
コンパイルして「メイクチェック」を実行します。
レポートを生成するには、実行してください。
gcovr -f ' .*/.libs/.* ' -e ' .*python.* '
これにより、要約が生成されます。ファイル内の個々の行のカバレッジを確認したい場合は、次のことができます。
cd lib
gcov -o .libs/ * .o
カバーされているものに関する情報のために作成された個々の.gcovファイルを調べることができます。詳細については、GCOVドキュメントを参照してください。
執筆時点で、私は約74%のコードカバレッジを取得していたので、それは本当に良いことです。主に機能テストの改善を通じて、それを改善するために取り組んでいます。
Ser2Netは、主にシリアルポート構成(TermiosおよびRFC2217)のテストに使用されます。 GCOVバージョンのGensioライブラリに対してSer2Netを構築し、Ser2Netで「チェック」を実行して、これらの部品をカバーすることができます。それで、私は約76%のカバレッジを見ているので、それは合計にあまり追加されません。
これをファジングと組み合わせることができるのはいいことですが、それを行う方法はわかりません。 AFLは、コードカバレッジでそれ自身のことです。何らかの形でGCOVを統合したAFL-COVパッケージがあるように見えますが、私はそれを調べていません。