6    拡張 SNMP アプリケーション・プログラミング・インタフェース

シンプル・ネットワーク管理プロトコル (SNMP) は,ルータ,ブリッジ,ホストなど,ネットワークに接続されているデバイスのリモート管理とデータ収集を可能にするアプリケーション層プロトコルです。

管理されたネットーワーク接続デバイスは,そのデバイスのための SNMP エージェントとして機能するソフトウェアを含んでいます。 このソフトウェアは,SNMP に対するアプリケーション層プロトコルを処理し,管理コマンドを実行します。 管理コマンドは,情報収集パラメータおよび操作に関する設定パラメータで構成されます。

ネットワーク上の各管理デバイスに SNMP コマンドを送って管理タスクを実行するネットワーク管理プログラムもあります。 通常このプログラムは,ネットワーク上のいずれかの単一ホストで実行されます。 このプログラムが実行する管理タスクとしては,構成管理,ネットワーク・トラフィックの監視,ネットワークに関するトラブル・シューティングなどがあります。

eSNMP (Extensible Simple Network Management Protocol) は,Tru64 UNIX あるいは DIGITAL UNIX の以前のバージョンのための SNMP エージェントです。 このエージェントは,マスタ・エージェント・プロセスと eSNMP サブエージェントなどの複数の関連プロセスで構成されます。 マスタ・エージェントは SNMP プロトコルを処理し,サブエージェントは要求された管理コマンドを実行します。 この章では,次の項目については既知であると仮定して説明します。

この章では次の情報を提供します。

6.1    eSNMP の概要

以降の節では,eSNMP エージェントの構成要素とアーキテクチャについて下記の順に説明します。

6.1.1    eSNMP の構成要素

eSNMP の構成要素は次のとおりです。

MIB (Management Information Base) 定義は,ネットワーク管理に関係するデータ要素群です。 これらの多くは,インターネット協会 (Internet Society) の IETF (Internet Engineering Task Force) ワーキング・グループの標準化作業の成果物として作成された RFC で標準化されています。

RFC で定義されているデータ要素は,階層構造のネーミング・スキームで識別されます。 階層構造の各レベルのそれぞれの名前は,それに対応する番号を持っています。 MIB 定義のデータ要素は,データ要素の名前あるいはオブジェクト識別子 (OID) と呼ばれる対応するシーケンス番号によって参照することができます。 各データ要素の OID は,さらに番号を追加することにより,データ要素の特定のインスタンスを識別するように拡張できます。 管理されたデータ要素の集合全体を MIB ツリーと呼びます。

各 SNMP エージェントは,管理されているデバイスに属する MIB 要素と,いくつかの共通 MIB 要素を実現します。 これらの MIB 要素をサポート MIB ツリー要素と呼びます。 拡張 SNMP エージェントは,このサポート MIB ツリー要素を複数のプロセス間に分散させ,動的に変更することができます。

eSNMP には,1 つのマスタ・エージェントといくつかのサブエージェントがあります。 マスタ・エージェントは,SNMP プロトコルを扱い,SNMP 自身に関連した MIB をサポートし,接続されたサブエージェントおよびサブエージェントがサポートする MIB サブツリーの登録の管理を行います。 eSNMP のためのマスタ・エージェントは,デーモン・プロセス /usr/sbin/snmpd です。

Tru64 UNIX は,IETF 標準もしくは HP 独自の異なる MIB をいくつか実現しているサブエージェントを提供します。 詳細は,『QuickSpecs』,『Tru64 UNIX 概要』 および snmpd(8) を参照してください。 これらのサブエージェント (および他社のサブエージェント) はマスタ・エージェントとともにホストに対して,1 つの SNMP エージェントであるかのように機能します。

6.1.2    アーキテクチャ

マスタ・エージェントは,事前に割り当てられている UDP (ユーザ・データグラム・プロトコル) ポート上で,SNMP 要求が送られてくるのを待っています。 SNMP 要求を受信すると,マスタ・エージェントはローカル・セキュリティ・データベース ( snmpd(8) を参照) に対して認証を行い,認証エラーあるいはプロトコル・エラーが発生した場合はそれを処理します。 要求が有効な場合,snmpd デーモンはその MIB 登録を照会します。 要求に含まれているそれぞれの要求 MIB オブジェクトに対して,どの登録済 MIB がそのオブジェクトを含み,どのサブエージェントがその MIB を登録したかを判断します。 その後,マスタ・エージェントは (SNMP 要求に含まれる各サブエージェントに対して) 一連のメッセージを作成します。

各サブエージェント・プログラムは,シェアード・ライブラリ libesnmp.so にリンクしています。 このライブラリには,マスタ・エージェントとサブエージェントとの通信を可能にするプロトコルのインプリメンテーションが含まれています。 このコードは,マスタ・エージェントのメッセージを解析し,ローカル・オブジェクト・テーブルを照会します。

オブジェクト・テーブルは,snmpi および mosy MIB コンパイラ・ツールで生成されたコードで定義および初期化されたデータ構造体です。 このデータ構造体には,サブエージェントで実現されている MIB に含まれる各 MIB オブジェクトに対するエントリが含まれています。 オブジェクト・テーブル・エントリのある部分は,MIB オブジェクトに対する要求をサービスする関数のアドレスです。 この関数をメソッド・ルーチンと呼びます。

eSNMP ライブラリ・コードは,マスタ・エージェントのメッセージにおいて各 MIB 変数に対して指定されたメソッド・ルーチンに呼び込まれます。 eSNMP ライブラリ・コードは,戻り値をもとに応答パケットを作成し,それをマスタ・エージェントへ返します。

マスタ・エージェントはタイマを起動し,すべてのサブエージェントからの応答パケットを整理します。 (たとえば GetNext 要求など) 特定の要求に依存して,マスタ・エージェントは新しいサブエージェント・メッセージを再作成し再送します。 必要なデータあるいはエラー応答をマスタ・エージェントがすべて持っている場合 (あるいはサブエージェントからの応答が時間切れになっても届かない場合), マスタ・エージェントは SNMP 応答メッセージを作成し,もとの SNMP アプリケーションに送ります。 要求を出している SNMP 管理アプリケーションには,マスタ・エージェントとサブエージェントとのやり取りは見えません。

サブエージェント・プログラムは,すべてのプロトコル処理および発送を行う libesnmp.so シェアラブル・ライブラリにリンクしています。 サブエージェント開発者は,それらの定義済みの MIB オブジェクトだけに対するメソッド・ルーチンをコーディングする必要があります。

6.1.3    SNMP バージョン

拡張 SNMP は,次の範囲で SNMPv2c をサポートします。 これは,RFC 1901 から RFC 1908 までをベースにしています。

6.1.4    AgentX

マスタ・エージェント間で libesnmp.so ライブラリによって実行される通信はすべて,RFC 2741,『Agent Extensibility (AgentX) Version 1 を実現して行われています。 RFC 2741 は,拡張可能なエージェント構成要素,マスタ・エージェント,複数のサブエージェントの間の通信に関する標準的なプロトコルを定義しています。 すなわち,eSNMP API を使用するサブエージェントは,異なるベンダのマスタ・エージェント (RFC 2741 に準拠しているもの) が Tru64 UNIX ホスト上で実行されていても,修正なしで正しく動作します。

6.2    拡張 SNMP アプリケーション・プログラミング・インタフェースの概要

サブエージェントの機能は,マスタ・エージェントとの通信を確立し,処理しようとしている MIB サブツリーを登録し,マスタ・エージェントからの要求を処理することです。 また,ホスト・アプリケーションに代わって SNMP トラップを送ることができます。

サブエージェントは,次のものから構成されます。

通常,サブエージェントはルータ・デーモンなどのアプリケーション内に組み込まれています。 サブエージェントの処理はプロセスが実行する処理のほんの一部分です。 この場合,アプリケーションのメイン・イベント・ループは,eSNMP ライブラリを呼び出します。 また,サブエージェントが独自のメインルーチンを持つスタンドアロン・デーモンである場合もあります。

マスタ・エージェントからのパケット処理中に eSNMP ライブラリは,要求された各 MIB 変数に対して指定のメソッド・ルーチンを呼び出します。 オブジェクト・テーブルの定義済みの各 MIB 変数は,その MIB 変数の要求を処理するためのメソッド・ルーチンへのポインタを含んでいます。 サブエージェントのオブジェクト・テーブルは mosy および snmpi プログラムによって生成されるため, メソッド・ルーチン名は静的です。

オペレーティング・システムで提供される eSNMP 開発者キットには次のものが含まれます。

eSNMP シェアード・ライブラリ (libesnmp.so) は次のサービスを提供しています。

6.2.1    MIB サブツリー

サブエージェントの動作と eSNMP API について理解するためには,MIB サブツリーについて理解することが非常に重要です。

注意

この項では,SNMP で使用される OID 命名構造については理解しているものとして説明します。 OID 命名構造については,RFC 1902『Structure of Management Information for Version 2 of the Simple Network Management Protocol (SNMPv2)を参照してください。

SNMP における情報は,逆ツリー構造の階層構造になっています。 この階層構造のなかで,データは,リーフ・ノードに対応付けられます。 各ノードには名称と番号が付けられます。 各ノードは,OID によっても識別することができます。 OID は,ツリーのルートからそのノードまでのパス上に存在する,サブ識別子と呼ばれる負でない番号を連鎖したものです。 OID の長さは,最低でサブ識別子が 2 つなければならず,サブ識別子が,たかだか 128 個の長さです。 有効なサブ識別子 1 の値は,込みで 0 から 2 の範囲であり,サブ識別子 2 の値は,込みで 0 から 39 の範囲であり,残りのサブ識別子の値は,負でない番号です。

たとえば,/usr/examples/esnmp ディレクトリのサンプル・コードで提供される chess MIB は,chess という名前の要素を持っています。 要素 chess の OID は,ツリーの階層構造における位置を表す 1.3.6.1.4.1.36.2.15.2.99 です。

iso(1)
 org(3)
  dod(6)
   internet(1)
    private(4)
     enterprise(1)
      digital(36)
       ema(2)
        sysobjects(15)
         decosf(2)
          chess(99)
 

MIB 階層構造のどのノードも MIB サブツリーを定義することができます。 サブツリー内のすべての要素は,サブツリー・ベースの OID で始まる OID を持っています。 たとえば chess を MIB サブツリー・ベースとして定義した場合,chess OID をプレフィックスとして持つ要素は,次のようにすべて MIB サブツリー内に存在します。

chess                  1.3.6.1.4.1.36.2.15.2.99
 chessProductID        1.3.6.1.4.1.36.2.15.2.99.1
 chessMaxGames         1.3.6.1.4.1.36.2.15.2.99.2
 chessNumGames         1.3.6.1.4.1.36.2.15.2.99.3
 gameTable             1.3.6.1.4.1.36.2.15.2.99.4
  gameEntry            1.3.6.1.4.1.36.2.15.2.99.4.1
   gameIndex           1.3.6.1.4.1.36.2.15.2.99.4.1.1
   gameDescr           1.3.6.1.4.1.36.2.15.2.99.4.1.2
gameNumMoves           1.3.6.1.4.1.36.2.15.2.99.4.1.3
   gameStatus          1.3.6.1.4.1.36.2.15.2.99.4.1.4
 moveTable             1.3.6.1.4.1.36.2.15.2.99.5
  moveEntry            1.3.6.1.4.1.36.2.15.2.99.5.1
   moveIndex           1.3.6.1.4.1.36.2.15.2.99.5.1.1
   moveByWhite         1.3.6.1.4.1.36.2.15.2.99.5.1.2
   moveByBlack         1.3.6.1.4.1.36.2.15.2.99.5.1.3
   moveStatus          1.3.6.1.4.1.36.2.15.2.99.5.1.4
 chessTraps            1.3.6.1.4.1.36.2.15.2.99.6
  moveTrap             1.3.6.1.4.1.36.2.15.2.99.6.1
 

サブツリー内の要素に関連するすべての要求をこのサブエージェントが処理することを,マスタ・エージェントに知らせるために登録されるのは,この MIB サブツリー・ベースです。

マスタ・エージェントは,登録されている MIB サブツリーに従属するすべてのオブジェクトをサブエージェントが処理することを期待します。 この原則を考慮して MIB サブツリーを選択してください。

たとえば,サブエージェントが chess サブツリーの要素に関する要求をすべて処理できると考えるのは現実的なので,chess のサブツリーを登録するのは妥当です。 また,特定のアプリケーションはアプリケーション固有の MIB で定義されているすべてのオブジェクトを処理することを期待するため,アプリケーション固有の MIB 全体を登録するのも通常は適切です。

(FDDI や トークンリングなど) transmission に従属するすべての定義済み MIB オブジェクトをサブエージェントが処理できるように用意されていることはありえないので,(MIB-2 の下の) transmission のサブツリーを登録するのは間違いです。

サブエージェントは必要な数の MIB サブツリーを登録します。 サブエージェントは,そのサブエージェント自身あるいは他のサブエージェントによる別の登録と重複して OID を登録することができます。 ただし,サブエージェントは同じ OID を 2 回以上登録することはできません。 サブエージェントがマスタ・エージェントとの通信を確立した後は,いつでも MIB サブツリーの登録および登録の解除を行うことができます。

通常,サブツリーとしてマスタ・エージェントに登録されるのは非リーフ・ノードです。 ただし,リーフ・ノード (インスタンスと対応する値を持ちうる MIB 変数に相当),あるいは特定のインスタンスも,サブツリーとして登録することができます。

マスタ・エージェントは,プレフィックスが最長で,最適な優先度の MIB サブツリーを持つサブエージェントへ要求を送ります。

6.2.2    オブジェクト・テーブル

mosy および snmpi ユーティリティによって,MIB からオブジェクト・テーブルを定義する C 言語コードが生成されます。 オブジェクト・テーブルは,サブエージェント内にコンパイルされる subtree_tbl.h および subtree_tbl.c ファイルで定義されます。

これらのモジュールは,上記のユーティリティによって作成されます。 編集しないことをお勧めします。 MIB を変更する場合,あるいは将来のバージョンの eSNMP 開発ユーティリティがオブジェクト・テーブルを再作成する場合,これらのファイルに対して編集を加えていなければより簡単にファイルを再作成/再コンパイルできます。

6.2.2.1    subtree_tbl.h ファイル

subtree_tbl.h ファイルには,次の情報が含まれています。

MIB サブツリー構造の宣言

MIB サブツリーは,subtree_tbl.c ファイルのコードによって自動的に初期化されます。 この構造へのポインタは,マスタ・エージェントに MIB サブツリーを登録するために esnmp_register ルーチンへ渡されます。 この MIB サブツリーに関するオブジェクト・テーブルへのすべてのアクセスは,このポインタを通して行なわれます。 宣言の形式は次のとおりです。

extern SUBTREE subtree_subtree;

インデックス定義

SUBTREE における各 MIB 変数に対するインデックス定義は,次の形式です。

#define I_mib-variable    nnnn

これらの値は MIB サブツリー内の各 MIB 変数に対してユニークで,この MIB 変数のためのオブジェクト・テーブルへのインデックスです。 また,これらの値は,スイッチ操作で使用できるように同じメソッド・ルーチンでインプリメントされている変数を区別するのにも使用されます。

列挙定義

"SYNTAX INTEGER" および列挙された値で定義される MIB 変数に対する列挙定義は,次の形式です。

#define D_mib-variable_enumeration-name    value

列挙定義は,計数 MIB 値がとる可能性のある構造値を記述するため,有用です。 次に例を示します。

/* enumerations for gameEntry group */
   #define   D_gameStatus_complete         1
   #define   D_gameStatus_underway         2
   #define   D_gameStatus_delete           3
 

データ構造体定義

MIB グループ・データ構造体定義は,次の形式です。

typedef struct xxx {      type mib-variable;          
.
.
.
     char mib-variable_mark;          
.
.
.
}  mib-group_type

データ構造体が,MIB サブツリー内の各MIB グループに対して送られます。 各構造体定義には,グループ内の各MIB 変数を表すフィールドが含まれています。 subtree_tbl.h ファイルが作成されるときに snmpi プログラムに渡される MIB のプール内で MIB 変数名が ユニークでない場合,それをユニークにするために snmpi プログラムは,親変数の名前 (グループ名) で名前を限定しません。 MIB 変数フィールドに加えて,各変数に対して 1 バイトの mib-variable_mark フィールドが構造体に含まれています。 このフィールドは,MIB 変数の状態を管理するために使用することができます。 次に示すのは,chess MIB のグループ構造体の例です。

typedef struct _chess_type {
    OID   chessProductID;
    int   chessMaxGames;
    int   chessNumGames;
 
    char chessProductID_mark;
    char chessMaxGames_mark;
    char chessNumGames_mark;
} chess_type;
 

MIB グループ構造体はユーザが使用するために提供されますが,必須ではありません。 メソッド・ルーチンの中で最も簡単な構造体を使用することができます。

メソッド・ルーチン関数プロトタイプ

MIB サブツリー内の各 MIB グループは,メソッド・ルーチン・プロトタイプを定義してます。 MIB グループは,同じ親ノードを持つリーフ・ノードの MIB 変数の集まりです。

GetGetNext,および GetBulk 操作を処理するメソッド・ルーチンに対しては関数プロトタイプが常にあります。 グループに書き込み可能変数が含まれる場合は,SET 操作を処理するメソッド・ルーチン用の関数プロトタイプもあります。 これらのルーチンへのポインタは,subtree_tbl.c モジュールで初期化される MIB サブツリーのオブジェクト・テーブルに含まれています。 次のように,定義されている各プロトタイプに対してメソッド・ルーチンを作成する必要があります。

extern int mib-group_get(
        METHOD *method );

extern int mib-group_set(
        METHOD *method );

次に例を示します。

extern int chess_get(METHOD *method);
extern int chess_set(METHOD *method);
 

メソッド・ルーチンについての詳細は,6.3.2.3 項を参照してください。

6.2.2.2    subtree_tbl.c ファイル

subtree_tbl.c ファイルには次の情報が含まれています。

整数の配列

MIB サブツリーにおける各 MIB 変数の OID として使用される整数の配列は,次の形式です。

static unsigned int elems[] = { ...
 

OBJECT 構造体

MIB サブツリー内の各 MIB 変数に対して 1 つの OBJECT があります (esnmp.h を参照)。

OBJECT は MIB 変数を表現し,次のフィールドを持ちます。

マスタ・エージェントは,オブジェクト・テーブルあるいは MIB 変数についての情報は持っていません。 マスタ・エージェントは,MIB サブツリーの登録情報のみを管理します。 特定の MIB 変数に対する要求を受け取った場合,次のように処理されます。 以下の手順では,MIB 変数は mib_var で MIB サブツリーは subtree_1 です。

  1. マスタ・エージェントは,MIB サブツリーの登録情報内で mib_var の最も優先度が高い領域として subtree_1 を見つけます。 最も優先度の高い領域は,プレフィックスが最長で,最適な優先度を持つ登録済みの MIB サブツリーとして決定されます。

  2. マスタ・エージェントは,subtree_1 を登録したサブエージェントに eSNMP メッセージを送ります。

  3. サブエージェントは登録済み MIB サブツリーのリストを照会して subtree_1 を探し,subtree_1 のオブジェクト・テーブルで次のものを探します。

  4. サブエージェントは,適切なメソッド・ルーチンを呼び出します。 メソッド・ルーチンが正常に終了すると,マスタ・エージェントへデータが返されます。 正常に終了しなかった場合,Get あるいは Set に対してはエラーが返されます。 GetNext あるいは GetBulk に対しては,メソッド・ルーチンが正常に終了するかあるいはすべてのオブジェクトを実行するまで,libesnmp ライブラリ・コードはその後に続く subtree_1 のオブジェクト・テーブルのオブジェクトを実行し続けます。 どちらの場合も適切な応答が返されます。

  5. GetNext あるいは GetBulk ルーチンで subtree_1 がデータを返せなかったことをマスタ・エージェントが検出した場合,サブエージェントが値を返すか,MIB サブツリーの登録情報がなくなるまでsubtree_1 の後のサブツリーを繰り返し実行します。

初期化済み SUBTREE 構造体

SUBTREE 構造体へのポインタが,MIB サブツリーを登録するために esnmp_register eSNMP ライブラリ・ルーチンへ渡されます。 ライブラリ・ルーチンは,このポインタを通してオブジェクト構造体を見つけます。 次に示すのは chess サブツリー構造体の例です。

SUBTREE chess_subtree = { "chess", "1.3.6.1.4.1.36.2.15.2.99",
                        { 11, &elems[0] }, objects, I_moveStatus};
 

SUBTREE 構造体は次の要素を含んでいます。

subtree_tbl.c の最後のセクションには,mib-group_type 構造体を割り当て/解放するための短いルーチンが含まれています。 この部分は必ずしも API の一部として提供する必要はありません。

6.2.3    サブエージェントの実現

サブエージェント開発者は,通常,UNIX アプリケーションや,デーモン,ドライバ (たとえば gated デーモンや ATM ドライバ) が提供されており,SNMP インタフェースを実現する必要があります。 以下に,その手順を示します。

  1. MIB 仕様の入手

    MIB の開発は MIB 仕様から始まり,通常は RFC の形式です。 SNMPv1 については,仕様は RFC 1212 に従って コンサイス MIB フォーマットで作成されます。 SNMPv2c については,仕様は,それぞれ RFC 1902 および RFC 1903 で指定されている SMIv2 および textual conventions で作成されます。 MIB の設計および仕様決定については,本書では触れません。 すでに MIB 仕様をお持ちであることを前提に説明します。

    標準の RFC は,次の URL の RFC サイトから入手できます。

    
    http://www.rfc-editor.org/rfc.html
     
    

    ユーザ自身の MIB 仕様を作成する必要がある場合は,他のベンダが作成した同じような MIB を参考にして行うことができます。 公開 MIB のソースは,次の URL の Network Management ページのアーカイブ・セクションで参照することができます。

    http://smurfland.cit.buffalo.edu/NetMan/index.html
     
    

    サブエージェントで実現しようとしているすべての要素に対する MIB,およびそれらが参照する MIB が必要になります。 最低限必要なのは,SMIv2 MIB snmp-smi.my と textual convention snmp-tc.myです。 これらは /usr/examples/esnmp ディレクトリにあります。

  2. MIB をコンパイルします。

    MIB 定義を入手したら,それらを使用して新しいサブエージェント用のオブジェクト・テーブルを生成します。 目的は,各 MIB の MIB 仕様テキストを取り出し,ASN.1 仕様を抽出して,それらをローカル・オブジェクト・テーブルを含む C 言語モジュールにコンパイルすることです。

    次のツールを使用して MIB をコンパイルします。

  3. メソッド・ルーチンおよび API コールをコーディングします。

    マスタ・エージェント (snmpd) との通信を初期化し MIB を登録するための eSNMP ライブラリ API を呼び出すコードを作成します (6.2.4 項参照)。

    必要なメソッド・ルーチンのためのコードを作成します (6.3 節参照)。 通常は,登録された MIB サブツリー内の各 MIB グループに対して,1 つの Get メソッド・ルーチンと 1 つの SET メソッド・ルーチンが必要になります。 前のステップで生成された subtree_tbl.h ファイルは,各メソッド・ルーチンの名前と関数プロトタイプを定義します。

  4. サブエージェントを作成します。

    /usr/examples/esnmp ディレクトリにサンプルの Makefile (chess.mk) が提供されています。

  5. サブエージェントの実行とテストを行います。

    他のプログラムやデーモンと同じようにサブエージェントを実行します。 デバッグ処理で使用できるように eSNMP ライブラリ・ルーチンにトレース機能が組み込まれています。 この機能を使用する場合は,main セクションで set_debug_level ルーチンを使用してください。

    サブエージェントが初期化され,MIB サブツリーが正しく登録されると,HP Insight Manager,HP Openview,あるいはその他の MIB ブラウザなどの標準アプリケーションを使用して,SNMP 要求を送信することができます。 SNMP アプリケーションにアクセスできない場合は,snmp_requestsnmp_traprcv および snmp_trapsnd プログラムを使用してサブエージェントのデバッグを行うことができます。

    対話式デバッグを行うと,サブエージェントが SNMP 要求のタイムアウトの原因になることに注意してください。

    通常,すべてのエラーおよび警告メッセージは,システムのデーモン・ログに記録されます。 chess サブエージェントおよび os_mibs サブエージェントを実行する場合,次のようにトレース実行時引数を指定します。

    os_mibs -trace
     
    

    トレース・オプションが有効な場合,プログラムはデーモンとして実行されず,すべてのトレース出力は stdout に送られ,処理される各メッセージを表示します。

    この機能は,サブエージェントで set_debug_level ルーチンを呼び出し TRACE パラメータを渡すことによって使用できます。

    デバッグ・マクロで渡されるものは,次のように stdout に送られます。

    ESNMP_LOG ((TRACE,("message_text \n"));

    警告メッセージを表示しないですべてをデーモン・ログに送るには,set_debug_level ルーチンを呼び出して WARNING || DAEMON_LOG パラメータを渡すか,あるいは,set_debug_level ルーチンを呼び出して ERROR || DAEMON_LOG パラメータを渡します。

6.2.4    サブエージェント・プロトコルの操作

eSNMP API は,マスタ・エージェント (snmpd) に密接に結び付かない自主的なサブエージェントのために提供します。 サブエージェントは,他のサブシステムあるは製品の 1 部分でもあり,SNMP とは関連しない本来の機能を持っています。 たとえば,gated デーモンは本来はインターネット・ルーティングに関係していますが,サブエージェントとしても機能します。

特に,snmpd デーモンは,スタートアップあるいはシャットダウン・プロシージャの中ではどのサブエージェント・デーモンの起動/停止も行いません。 また,サブエージェントに関するディスク上の構成情報の保守も行いません。 snmpd デーモンは,以前のサブエージェントあるいはサブツリーの登録情報については,起動時には何も持っていません。

通常,オペレーティング・システム上の各デーモンは,システムの実行レベルが変わる際にすべて一緒に開始あるいは停止します。 しかしサブエージェントは,snmpd デーモンの前にそれらをどこで開始するか,あるいは構成ファイルから情報を再ロードするために snmpd デーモンを再起動する間それらをどこで実行しているか,正しく状況を処理する必要があります。 このような状況では,サブエージェントは,次の項で説明するように eSNMP プロトコルを再起動する必要があります。

6.2.4.1    操作の順序

一連のサブエージェント・プロトコルの操作は次のとおりです。

  1. 初期化 (esnmp_init)

  2. 複数のサブエージェント間で共用されるテーブルで必要なインデックスの割り当て (esnmp_allocate)

  3. 登録 (esnmp_register [esnmp_register ...])

  4. データ通信

    次のようなループを繰り返し実行します。

    {
       determine sockets with data pending
     
       if the eSNMP socket has data pending
          esnmp_poll
     
       periodically call esnmp_are_you_there as required
       during periods of inactivity
    }
     
    

  5. 終了 (esnmp_term)

    サブエージェントを終了する際に esnmp_term 関数を呼び出すことは非常に重要です。 この操作によって eSNMP は,サブエージェントが使用していたシステム・リソースを解放します。

サブエージェント・プロトコル操作のコーディング方法については,/usr/examples/esnmp ディレクトリのサンプル・サブエージェントを参照してください。

6.2.4.2    関数の戻り値

eSNMP API 関数の戻り値は,要求された操作の成功あるいは失敗と,マスタ・エージェントの状態を,サブエージェントに示します。 以下に,各戻り値の意味とサブエージェントの対処を示します。

6.3    拡張 SNMP アプリケーション・プログラミング・インタフェース

以降の節では,SNMP アプリケーション・プログラミング・インタフェースに関して,次の項目について詳しく説明します。

6.3.1    呼び出しインタフェース

呼び出しインタフェースには次のルーチンが含まれます。

6.3.1.1    esnmp_init ルーチン

esnmp_init ルーチンは,eSNMP サブエージェントをローカルに初期化し,マスタ・エージェントとの通信を開始します。

このコールは,マスタ・エージェントからの応答を待つ間ブロックは行いません。 esnmp_init ルーチンを呼び出したら,サブエージェントが扱う各 MIB サブツリーに対して esnmp_register ルーチンを呼び出します。

このルーチンは,プログラム初期化中か,eSNMP プロトコルの再起動のために呼び出してください。 再起動の場合,esnmp_init ルーチンはすべての登録をクリアするので各サブツリーを再登録する必要があります。

プログラム名 (argv[0]) に説明的なテキストを追加して,ユニークな subagent_identifier を作成するようにします。

esnmp_init ルーチンの構文は次のとおりです。

int esnmp_init(
        int *socket,
        char *subagent_identifier );

引数は次のとおりです。

socket

eSNMP が使用するソケット記述子を受信する整数のアドレス。

subagent_identifier

サブエージェントを識別するヌルで終る文字列 (通常はプログラム名) のアドレス。

戻り値は次のとおりです。

ESNMP_LIB_NO_CONNECTION

初期化できないかあるいはマスタ・エージェントと通信できません。 後で再度実行してください。

ESNMP_LIB_OK

esnmp_init ルーチンが正常に終了しました。

ESNMP_LIB_NOTOK

サブエージェントにメモリを割り当てられませんでした。

次に示すのは esnmp_init ルーチンの例です。

#include <esnmp.h>
int socket;
status = esnmp_init(&socket, "gated");
 

6.3.1.2    esnmp_allocate ルーチン

esnmp_allocate ルーチンは,1 つまたは複数の特定のインデックス・オブジェクトに対する値の割り当てを要求します。

インデックスの割り当ては,AgentX に準拠したマスタ・エージェントが提供するサービスです。 これは,お互いに関する知識を持たないサブエージェント間で,MIB の概念的テーブルを共用するための機能です。 マスタ・エージェントはインデックス・オブジェクト (OID) と,各インデックスに割り当てられている値からなるデータベースを保守します。 マスタ・エージェントは,各インデックスが表す MIB 変数 (ある場合) を意識しません。 規約により,サブエージェントの開発者は,INDEX 句にリストされている MIB 変数を,値を割り当てるインデックス・オブジェクトとして使用する必要があります。

複数の変数でインデックスされるテーブルでは,各インデックスに対してそれぞれ値を割り当てることができますが,多くの場合これは不要です。 サブエージェントは,次の割り当てタイプのいずれかで要求することができます。

2 番目と 3 番目のタイプは,多くの MIB 仕様で,不特定の整数インデックスに対し一意性と不変性が要求されるために必要になります。 たとえば,IF-MIB (RFC 2233) の ifIndex,FDDI MIB (RFC 1285) の snmpFddiSMTIndex,System Application MIB (RFC 2287) の sysApplInstallPkgIndex があります。 サブエージェントがこのようなインデックスを用いてテーブルを共用しなければならないということが,インデックス割り当てメカニズムが必要な主な理由です。

インデックス割り当てと MIB リージョン登録は,マスタ・エージェント内で連動していません。 マスタ・エージェントは,登録要求を処理する際に,インデックス割り当ての現在の状態を考慮しません。 また,インデックスの割り当て要求を処理する際に,現在の登録状況を考慮することもありません。 これは主に,非 AgentX のサブエージェントの便宜を図るためです。

サブエージェントの開発者は,まずインデックスの割り当てを要求し,次に対応するリージョンを登録しなければなりません。 この順序で実行すると,インデックス割り当て要求に成功したときに,サブエージェントは,何を登録できるかということに対する適切なヒント (ただし保証ではない) を得ることができます。 他のエージェントがテーブルのその row にすでに登録しているために,登録に失敗することがあります。

サブエージェントは,共用テーブルの概念的な row を次の順序で登録する必要があります。

  1. インデックス値を正常に割り当てます。

  2. 割り当てられたインデックス値をESNMP_REG 構造体の instance フィールドに設定し,esnmp_register2 ルーチンに渡します。 このようにして,eSNMP サブエージェント開発者は,サブツリーとその ESNMP_REG 構造体の任意の range_subid および range_upper_bound フィールドで指定される MIB リージョンを完全に限定できます。 サブエージェントの開発者は,インスタンスにより登録を行う場合は,priority フィールドを 255 に設定しなければなりません。

  3. 結果コード ESNMP_REG_STATE_REGDUP で登録に失敗した場合は,以前に割り当てたインデックス値を esnmp_deallocate ルーチンでこの row から割り当て解除し,ステップ 1 からもう一度処理を始めます。

インデックス割り当ては,インデックスが任意の値であり,サブエージェント開発者が,どのインデックス値を使えばよいか判断できない場合にのみ必要になります。 インデックス値に固有の意味がある場合,サブエージェントではそのインデックス値を割り当てないようにします。 たとえば,RFC 1514 では,実行中のソフトウェア・プロセスのテーブル (hrSWRunTable) は,システム固有のプロセス識別子 (pid) によってインデックスされます。 サブエージェント自身のプロセスに対応する hrSWRunTable の row を実装するサブエージェントでは,その row のオブジェクト・インスタンスを定義するリージョンを登録します。 インデックス値を割り当てる必要はありません。

esnmp_allocate ルーチンの構文は次のとおりです。

int esnmp_allocate(
        ESNMP_ALLOC *alloc_parm );

引数の定義は次のとおりです。

alloc_parm

ESNMP_ALLOC 構造体へのポインタ。 呼び出す側は,この構造体とこれから参照される VARBIND リストを (メモリ内に) 継続的に確保しなければなりません。 これは,eSNMP の実行時ライブラリが,マスタ・エージェントから返される,インデックス割り当て要求の結果をフィールドに格納するために必要です。 この構造体には,次のようなフィールドがあります。

vb

1 つまたは複数の VARBIND からなる変数バインディング・リストへのポインタ。 リスト内の VARBIND にはそれぞれ,値を割り当てるインデックス・オブジェクトの名前が含まれています。 各 VARBIND にはそれぞれ値が必要です。

ESNMP_ALLOC_ANY_INDEX フラグと ESNMP_ALLOC_NEW_INDEX フラグのどちらも指定されていない場合,マスタ・エージェントは,インデックス割り当て要求を処理する際に,指定された値すべてを使用します。 ESNMP_ALLOC_ANY_INDEX フラグまたは ESNMP_ALLOC_NEW_INDEX フラグが指定された場合,マスタ・エージェントは,インデックス割り当て要求を処理する際に,指定された値をすべて無視し,各 VARBIND には適切な値を生成します。

options

次の値のビットマスク。

ESNMP_ALLOC_CLUSTER

インデックス割り当て要求は,クラスタ・コンテキストに対するものです。

ESNMP_ALLOC_NEW_INDEX

このインデックス割り当て要求では,新しい値の割り当てを要求します。 マスタ・エージェントは,実行を開始して以来使用されていない VARBIND に対してそれぞれ値を生成します。 これらの値は,成功応答で返されます。

ESNMP_ALLOC_ANY_INDEX

このインデックス割り当て要求では,未使用の値の割り当てを要求します。 マスタ・エージェントは,実行を開始してから使用されたか使用されていないかに関係なく VARBIND に対してそれぞれ値を生成します。 これらの値は,成功応答で返されます。

status

次に示す整数値のいずれかをとり,呼び出し側に対して,インデックス割り当て要求の状態を示します。 この状態コードは非同期に更新されます。 esnmp_poll ルーチンから戻った後,呼び出し側は,このパラメータを調べることができます。 以下の状態コードでは,alloc->error_index フィールドには値ゼロ (0) が格納されています。

ESNMP_ALLOC_STATE_PENDING

インデックス割り当て要求は,現在ローカルに保留されており,マスタ・エージェントへの接続を待っています。

ESNMP_ALLOC_STATE_SENT

インデックス割り当て要求は,マスタ・エージェントに送信されました (最終状態はまだ保留)。

ESNMP_ALLOC_STATE_DONE

マスタ・エージェントは,インデックス割り当て要求の処理に成功し肯定応答を返しました。 これでサブエージェントは,esnmp_register2 呼び出しに渡す esnmp_reg->instance フィールドで,割り当てられたインデックス値を使用できます。

以下の状態コードでは,alloc->error_index フィールドにはゼロ以外の値が格納されています。

ESNMP_ALLOC_STATE_ALLOCTYPE

インデックス・タイプまたはオプションが不正のため,マスタ・エージェントはインデックス割り当て要求をリジェクトしました。

ESNMP_ALLOC_STATE_ALLOCINUSE

指定されたインデックス・オブジェクトの値が現在使用されているため,マスタ・エージェントはインデックス割り当て要求をリジェクトしました。

ESNMP_ALLOC_STATE_ALLOCAVAIL

要求されたインデックス・オブジェクトに対して使用できる値がないため,マスタ・エージェントはインデックス割り当て要求をリジェクトしました。 この状態は,ESNMP_ALLOC_NEW_INDEX または ESNMP_ALLOC_ANY_INDEX オプションを指定した場合にのみ返されます。

ESNMP_ALLOC_STATE_ALLOCNOCLU

クラスタ・コンテキスト・オプションをサポートしていないため,マスタ・エージェントはインデックス割り当て要求をリジェクトしました。

ESNMP_ALLOC_STATE_REJ

マスタ・エージェントはその他の理由でインデックス割り当て要求をリジェクトしました。

error_index

状態コードが alloc.vb varbind リスト内のどの VARBIND (1 から開始) に対応しているかを示します。 esnmp_poll ルーチンから戻った後,呼び出し側はこのパラメータを調べることができます。

戻り値は次のとおりです。

ESNMP_LIB_NOTOK

alloc_parm 引数が指定されていません。

ESNMP_LIB_OK

esnmp_allocate ルーチンは正常に終了しました。

ESNMP_LIB_LOST_CONNECTION

サブエージェントとマスタ・エージェントの通信が途切れました。

ESNMP_LIB_BAD_ALLOC

サブエージェントとマスタ・エージェントが接続されていないか,alloc_parm 引数によって指定された VARBIND に有効なものがありません。 ログ・ファイルにもメッセージが出力されます。

この戻り値は,インデックス割り当て要求の開始のみを示していることに注意してください。 マスタ・エージェントからの応答で返された実際の状態コードは,その後 esnmp_poll ルーチンを呼び出したときに,alloc->status および alloc->error_index フィールドに返されます。

esnmp_allocate ルーチンの例を,次に示します。

#define  INDENT_SIZE             4
#define RESPONSE_TIMEOUT         0  /* use the default time set
                                       in esnmp_init message */
#define REGISTRATION_PRIORITY  128  /* priority at which the MIB
                                      subtree will register */
#define RANGE_SUBID             10  /* the identifier position in
                                       oid->elements just after ifEntry */
#define RANGE_UPPER_BOUND       22  /* the identifier for ifSpecific, under ifEntry */
 
int rc, status;
unsigned int our_ifIndex_instance = 0;
int ready_to_register        = 0;
int have_a_good_registration = 0;
extern SUBTREE ifEntry_subtree;     /* generated by /usr/sbin/snmpi -r ifEntry  */
OBJECT  *ifIndex_object = &ifEntry_subtree.object_tbl[I_ifIndex];
static ESNMP_ALLOC esnmp_alloc_for_ifIndex;  /* retain this structure to obtain status
                                                code and index object values.  Also,
                                                retain this structure for a subsequent
                                                call to esnmp_deallocate  */
static ESNMP_REG esnmp_reg_for_ifEntry;      /* retain this structure for a subsequent
                                                call to esnmp_unregister2  */
static OID ifEntry_instance_oid;
VARBIND  *vb;
/*
 *  initialize the ESNMP_ALLOC structure
 */
memset(&esnmp_alloc_for_ifIndex, 0, sizeof(ESNMP_ALLOC));
 
esnmp_alloc_for_ifIndex.options = ESNMP_ALLOC_NEW_INDEX;
esnmp_alloc_for_ifIndex.vb = vb = (VARBIND *)malloc(sizeof(VARBIND));
bzero((char *)vb, sizeof(VARBIND));
clone_oid(&vb->name, &ifIndex_object->oid);
o_integer(vb, ifIndex_object, (unsigned long)0); /* master will return actual
                                                    value assigned */
while(!have_a_good_registration) {
    status = esnmp_allocate(&esnmp_alloc_for_ifIndex );
    if (status != ESNMP_LIB_OK) {
        printf("Could not queue the 'ifIndex' \n");
        printf("index object for index allocation\n")
    }
    
.
.
.
rc = esnmp_poll();
.
.
.
if (esnmp_alloc_for_ifIndex.status > ESNMP_ALLOC_STATE_SENT) { /* * esnmp_alloc_for_ifIndex.status nows contain the final * status from the master agent. */ switch(esnmp_alloc_for_ifIndex.status) { case ESNMP_ALLOC_STATE_DONE our_ifIndex_instance = esnmp_alloc_for_ifIndex.vb->value.ul; ready_to_register = 1; printf("\n*** Successful index allocation. Our conceptual row in the"); printf("\n*** interfaces table was allocated. ifIndex value is %i\n\n", our_ifIndex_instance); break; case ESNMP_ALLOC_STATE_ALLOCTYPE: printf("\n*** Failed index allocation - 'allocation type'"); printf("\n*** associated with supplied varbind #%i.\n\n", esnmp_alloc_for_ifIndex.error_index); break; case ESNMP_ALLOC_STATE_ALLOCINUSE: printf("\n*** Failed index allocation - 'allocation in use'"); printf("\n*** associated with supplied varbind #%i.\n\n", esnmp_alloc_for_ifIndex.error_index); break; case ESNMP_ALLOC_STATE_ALLOCAVAIL: printf("\n*** Failed index allocation - 'no available values'"); printf("\n*** associated with supplied varbind #%i.\n\n", esnmp_alloc_for_ifIndex.error_index); break; case ESNMP_ALLOC_STATE_ALLOCNOCLU: printf("\n*** Failed index allocation - 'cluster context not supported'"); printf("\n*** associated with supplied varbind #%i.\n\n", esnmp_alloc_for_ifIndex.error_index); esnmp_alloc_for_ifIndex.options &= ~ESNMP_ALLOC_CLUSTER; break; case ESNMP_ALLOC_STATE_REJ: printf("\n*** failed index allocation - 'other reasons'"); printf("\n*** associated with supplied varbind #%i.\n\n", esnmp_alloc_for_ifIndex.error_index); break; } /* End switch */ } /* End if */ if (ready_to_register) { vb = esnmp_alloc_for_ifIndex.vb; memset(&esnmp_reg_for_ifEntry, 0, sizeof(ESNMP_REG)); esnmp_reg_for_ifEntry.subtree = &ifEntry_subtree; esnmp_reg_for_ifEntry.priority = REGISTRATION_PRIORITY; esnmp_reg_for_ifEntry.timeout = RESPONSE_TIMEOUT; esnmp_reg_for_ifEntry.range_subid = RANGE_SUBID; esnmp_reg_for_ifEntry.range_upper_bound = RANGE_UPPER_BOUND;   ifEntry_instance_oid.nelem = 1; ifEntry_instance_oid.elements = &our_ifIndex_instance; esnmp_reg_for_ifEntry.instance = (OID *)malloc(sizeof(OID)); esnmp_reg_for_ifEntry.instance = clone_oid(esnmp_reg_for_ifEntry.instance, &ifEntry_instance_oid); status = esnmp_register2(&esnmp_reg_for_ifEntry); if (status != ESNMP_LIB_OK) { printf("Could not queue the registration for 'ifEntry'\n"); } else {
.
.
.
rc = esnmp_poll();
.
.
.
if (esnmp_reg_for_ifEntry.state > ESNMP_REG_STATE_SENT) { /* * esnmp_reg_for_ifEntry.status nows contain the final * status from the master agent. */ switch(esnmp_reg_for_ifEntry.state) { case ESNMP_REG_STATE_DONE: printf("\n*** Successful registration for conceptual row in"); printf("\n*** the interfaces table indexed by an ifIndex"); printf("\n*** value of %i.\n\n", our_ifIndex_instance); have_a_good_registration = 1; break; case ESNMP_REG_STATE_REGDUP: printf("\n*** Failed registration - Duplicate registration."); printf("\n*** We need to deallocate this ifIndex value and"; printf("\n*** allocate a new value\n\n"); break; case ESNMP_REG_STATE_REGNOCLU: printf("\n*** Failed registration - Cluster context not supported."); printf("\n*** Need to deallocate this ifIndex value and to"); printf("\n*** allocate a new value in the default context\n\n"); esnmp_alloc_for_ifIndex.options &= ~ESNMP_ALLOC_CLUSTER; break; case ESNMP_REG_STATE_REJ: printf("\n*** Failed registration - Other reasons\n\n"); break; } if (!have_a_good_registration) { esnmp_deallocate(&esnmp_alloc_for_ifIndex); ready_to_register = 0; rc = esnmp_poll(); free_oid(esnmp_reg_for_ifEntry.instance); free(esnmp_reg_for_ifEntry.instance); esnmp_reg_for_ifEntry.instance = NULL; } } } } }

6.3.1.3    esnmp_deallocate ルーチン

esnmp_deallocate ルーチンは,1 つまたは複数のインデックス・オブジェクトについて,このサブエージェントに以前に割り当てた値の割り当てを解除するよう,マスタ・エージェントに要求します。

マスタ・エージェントはインデックスの割り当て解除要求を受けると,インデックス・オブジェクト (OID) のデータベースを更新し,指定された値に割り当て解除のマークを付けます。 ここで解放された値は,その後のインデックス割り当て要求での割り当てに使用できます。

esnmp_deallocate ルーチンの構文は,次のとおりです。

int esnmp_deallocate(
        ESNMP_ALLOC *alloc_parm );

引数の定義は次のとおりです。

alloc_parm

ESNMP_ALLOC 構造体へのポインタ。 通常,これは前に呼び出した esnmp_allocate で使用された構造体と同じものです。 呼び出す側は,この構造体とこれから参照される VARBIND リストを (メモリ内に) 継続的に確保しなければなりません。 これは,eSNMP の実行時ライブラリが,マスタ・エージェントから返される,インデックス割り当て解除要求の結果をフィールドに格納するために必要です。 この構造体には,次のようなフィールドがあります。

vb

1 つまたは複数の VARBIND からなる変数バインディング・リストへのポインタ。 リスト内の VARBIND にはそれぞれ,割り当て済みインデックス・オブジェクトの名前と値が含まれています。

options

次の値のビットマスク。

ESNMP_ALLOC_CLUSTER

インデックス割り当て要求は,クラスタ・コンテキストに対するものです。

status

次に示す整数値のいずれかをとり,呼び出し側に対して,インデックス割り当て解除要求の状態を示します。 この状態コードは非同期に更新されます。 esnmp_poll ルーチンから戻った後,呼び出し側は,このパラメータを調べることができます。 以下の状態コードでは,alloc->error_index フィールドには値ゼロ (0) が格納されています。

ESNMP_ALLOC_STATE_SENT

インデックス割り当て解除要求は,マスタ・エージェントに送信されました (最終状態はまだ保留)。

ESNMP_ALLOC_STATE_DONE

マスタ・エージェントは,インデックス割り当て解除要求の処理に成功し肯定応答を返しました。 これでマスタ・エージェントは,その後のインデックス割り当て要求を処理する際に,このインデックス値を再度使用できるようになります。

以下の状態コードでは,alloc->error_index フィールドにはゼロ以外の値が格納されています。

ESNMP_ALLOC_STATE_DEALLOC_REJ

割り当てが未知であるため,マスタ・エージェントはインデックス割り当て解除要求をリジェクトしました。

ESNMP_ALLOC_STATE_REJ

マスタ・エージェントはその他の理由でインデックス割り当て解除要求をリジェクトしました。

error_index

状態コードが alloc.vb リスト内のどの VARBIND (1 から開始) に対応しているかを示します。 esnmp_poll ルーチンから戻った後,呼び出し側はこのパラメータを調べることができます。

戻り値は次のとおりです。

ESNMP_LIB_NOTOK

alloc_parm 引数が指定されていません。

ESNMP_LIB_OK

esnmp_allocate ルーチンは正常に終了しました。

ESNMP_LIB_LOST_CONNECTION

サブエージェントとマスタ・エージェントの通信が途切れました。

ESNMP_LIB_BAD_DEALLOC

サブエージェントとマスタ・エージェントが接続されていないか,alloc_parm 引数によって指定された VARBIND に有効なものがありません。 ログ・ファイルを参照してください。

この戻り値は,インデックス割り当て解除要求の開始のみを示していることに注意してください。 マスタ・エージェントからの応答で返された実際の状態コードは,その後 esnmp_poll ルーチンを呼び出したときに,alloc->status および alloc->error_index フィールドに返されます。

esnmp_deallocate ルーチンの例を,次に示します。

#include <esnmp.h>
 
int status;
static ESNMP_ALLOC esnmp_alloc_for_ifIndex;  /* structure retained from a previous call
                                                to esnmp_allocation().  Retain this
                                                structure for update with final status
                                                from the master agent */
 
/* call to unregister2()  goes here */
 
esnmp_alloc_for_ifIndex.options = 0;   /* clear options */
status = esnmp_deallocate( &esnmp_alloc_for_ifIndex );
if (status != ESNMP_LIB_OK) {
    printf("Could not queue the 'ifIndex' \n");
    printf("index object for index allocation\n");
}

.
.
.
esnmp_poll();
.
.
.
if (esnmp_alloc_for_ifIndex.status > ESNMP_ALLOC_STATE_SENT) { /* * the final status from the master agent is available */ switch(esnmp_alloc_for_ifIndex.status) { case ESNMP_ALLOC_STATE_DONE: printf("Successful index deallocation for value(s) associated\n"); printf("with the 'ifIndex' index object.\n"); free_varbind(esnmp_alloc_forifIndex.vb); break; case ESNMP_ALLOC_STATE_DEALLOC_REJ: printf("Failed index deallocation due to 'unknown allocation'\n"); printf("associated with supplied varbind #%i.\n", esnmp_alloc_for_ifIndex.error_index); break; case ESNMP_ALLOC_STATE_REJ: printf("Failed index deallocation due to 'other reasons'\n"); printf("associated with supplied varbind #%i.\n", esnmp_alloc_for_ifIndex.error_index); break; } }

6.3.1.4    esnmp_register ルーチン

esnmp_register ルーチンは,単一の MIB サブツリーの登録を要求します。 これは,サブエージェントが登録された MIB サブツリー内で MIB 変数のインスタンスを生成することをマスタ・エージェントに示します。

esnmp_register を呼び出す前に,初期化ルーチン (esnmp_init) を呼び出す必要があります。 処理しようとする各 MIB サブツリーに対応するそれぞれの SUBTREE 構造体に対して,esnmp_register ルーチンを呼び出す必要があります。 esnmp_unregister を呼び出すと MIB サブツリーの登録が解除され,その後 esnmp_register を呼び出すと再登録されます。

esnmp_init を呼び出してeSNMP プロトコルを再起動すると,すべての MIB サブツリーの登録がクリアされます。 この場合,すべての MIB サブツリーを再登録する必要があります。

MIB サブツリーは,MIB 変数名と対応する OID によって識別されます。 この集合は,MIB サブツリーに含まれるすべての MIB 変数の親に相当します。 たとえば,MIB-2 tcp サブツリーの OID は 1.3.6.1.2.1.6 です。 この OID に従属する (同じ 7 つの識別子で始まる) すべての MIB 変数がサブツリーの領域に含まれています。 MIB サブツリーは,単一の MIB 変数 (リーフ・ノード) でも特定のインスタンスでもかまいません。

MIB サブツリーを登録すると,サブエージェントは,その MIB サブツリーの領域内のすべての MIB 変数 (もしくは OID) に対するSNMP 要求を処理することを表示します。 したがって,サブエージェントは MIB 変数をまだ組み込んでいるいる MIB サブツリーの中で最も完全に (長く) 修飾されたものを登録します。

マスタ・エージェントは,サブエーエジェントが同じ MIB サブツリーを 2 回以上登録できないようにします。 この制限事項を除いて,サブエージェントは,以前に登録した MIB サブツリーの OID 範囲に重複して, あるいは他のサブエージェントが登録した MIB サブツリーの OID 範囲に重複して MIB サブツリーを登録できます。

たとえば,os_mibs および gated の 2 つの Tru64 UNIX デーモンを考えてみると,os_mibs デーモンは ip MIB サブツリー (1.3.6.1.2.1.4) を登録し,gated デーモンは ipRouteEntry MIB サブツリー (1.3.6.1.2.1.4.21.1) を登録します。 ipRouteIfIndex (1.3.6.1.2.1.4.21.1.2) などの ipRouteEntry 内の ip MIB 変数に対する要求は,gated サブエージェントへ送られます。 ipNetToMediaIfIndex (1.3.6.1.2.1.4.22.1.1) などの他の ip 変数への要求は,os_mibs サブエージェントへ送られます。 gated プロセスを終了した場合あるいは ipRouteEntry MIB サブツリーの登録を解除した場合,すべての ipRouteEntry MIB 変数を含む ip MIB サブツリーがipRouteIfIndex に対する要求のもっとも優先度が高い領域となっているので,その後の ipRouteIfIndex への要求は os_mibs サブエージェントへ送られます。

マスタ・エージェントが SIGUSR1 シグナルを受け取ると,その MIB 登録が /usr/tmp/snmpd_dump.log ファイルへ送られます。 詳細については snmpd(8) を参照してください。

esnmp_register ルーチンの構文は次のとおりです。

int esnmp_register(
        SUBTREE *subtree,
        int timeout,
        int priority );

引数の定義は次のとおりです。

subtree

処理する MIB サブツリーに対応する SUBTREE 構造体へのポインタ。 SUBTREE 構造体は,MIB ドキュメントから直接得られた mosy および snmpi ユーティリティで生成されたコードで (xxx_tbl.c および xxx_tbl.hxxx は MIB サブツリー名) 外部的に宣言され初期化されます。

注意

subtree フィールドでポイントされているすべてのメモリは,プログラムの存続期間中,libesnmp によって参照されるため,永続的なストレージを持っていなければなりません。 snmpi ユーティリティによって発行されたデータ宣言を使用してください。

timeout

この MIB サブツリーでデータを要求した際にマスタ・エージェントが応答を待つ秒数。 0 〜 300 の値を指定します。 0 を指定した場合は,省略時のタイムアウト (3 秒) が使用されます。 省略時の値を使用することをお勧めします。

priority

登録の優先順位。 番号の大きいエントリの方が優先順位が高くなります。 指定できる範囲は 1 〜 255 です。 OID (オブジェクトID) の範囲内で最も高い優先順位の MIB サブツリーを登録したサブエージェントが,その範囲の OID (オブジェクト識別子) に対するすべての要求を受け取ります。

同じ優先順位で登録されている MIB サブツリーは,重複しているとされ,登録はマスタ・エージェントによってリジェクトされます。

priority 引数は,異なる構成を処理する協力関係のある複数のサブエージェントのためのメカニズムです。

戻り値は次のとおりです。

ESNMP_LIB_OK

esnmp_register ルーチンが正常に終了しました。

ESNMP_LIB_BAD_REG

esnmp_init ルーチンが呼び出されていない,タイムアウト・パラメータが正しくない,あるいはその MIB サブツリーがすでに登録されています。

ESNMP_LIB_LOST_CONNECTION

サブエージェントとマスタ・エージェントとの通信が途絶えています。

状態は要求の開始のみを示します。 マスタ・エージェントの応答で返される実際の状態は,その後の esnmp_poll ルーチンへの呼び出しで返されます。

次に示すのは esnmp_register ルーチンの例です。

#include <esnmp.h>
#define RESPONSE_TIMEOUT     0    /* use the default time set
                                     in OPEN message */
#define REGISTRATION_PRIORITY 10  /* priority at which subtrees
                                     will register */
int status;
 
extern SUBTREE ipRouteEntry_subtree;
 
status = esnmp_register( &ipRouteEntry_subtree,
                         RESPONSE_TIMEOUT,
                         REGISTRATION_PRIORITY );
if (status != ESNMP_LIB_OK) {
    printf ("Could not queue the 'ipRouteEntry' \n");
    printf ("subtree for registration\n");
}
 

6.3.1.5    esnmp_unregister ルーチン

esnmp_unregister ルーチンは,マスタ・エージェントから MIB サブツリーの登録を解除します。

このルーチンは,この MIB サブツリーの変数に対する要求をそれ以上処理しないことを eSNMP サブエージェントに伝えるアプリケーション・コードによって呼び出されます。 esnmp_register ルーチンを呼び出すことによって,必要に応じて MIB サブツリーを後で再登録することができます。

esnmp_unregister ルーチンの構文は次のとおりです。

int esnmp_unregister(
        SUBTREE *subtree );

引数は次のとおりです。

subtree

登録を解除する MIB サブツリーのSUBTREE 構造体へのポインタ。

戻り値は次のとおりです。

ESNMP_LIB_OK

ルーチンが正常に終了しました。

ESNMP_LIB_BAD_REG

指定した MIB サブツリーが登録されていません。

ESNMP_LIB_LOST_CONNECTION

MIB サブツリーの登録を解除する要求が送信できませんでした。 プロトコルを再起動する必要があります。

次は,esnmp_unregister ルーチンの例です。

#include <esnmp.h>
int status
 
extern SUBTREE ipRouteEntry_subtree;
 
status = esnmp_unregister( &ipRouteEntry_subtree );
 
switch (status) {
   case ESNMP_LIB_OK:
    printf ("The esnmp_unregister routine completed successfully.\n");
    break;
 
   case ESNMP_LIB_BAD_REG:
    printf ("The MIB subtree was not registered.\n");
    break;
 
   case ESNMP_LIB_LOST_CONNECTION:
   printf("%s%s%s\n", "The request to unregister the ",
                      "MIB subtree could not be sent.  ",
                      "You should restart the protocol.\n");
   break;
}
 

6.3.1.6    esnmp_register2 ルーチン

esnmp_register2 ルーチンは,esnmp_register ルーチンを拡張したものです。

esnmp_register2 ルーチンを呼び出す前に,初期化ルーチン (esnmp_init) を呼び出す必要があります。 処理しようとする各 MIB サブツリーに対応するそれぞれのサブツリー構造体に対して,esnmp_register2 関数を呼び出す必要があります。 いつでも,esnmp_unregister2 を呼び出すと MIB サブツリーの登録が解除され,その後 esnmp_register2 を呼び出すと再登録されます。

esnmp_init を呼び出して eSNMP プロトコルを再起動すると,すべての MIB サブツリーの登録がクリアされます。 MIB サブツリーはすべて再登録する必要があります。

MIB サブツリーは,ベース MIB 名と対応する OID によって識別されます。 この集合は,MIB サブツリーに含まれるすべての MIB 変数の親を表します。 たとえば,MIB-2 tcp サブツリーの OID は 1.3.6.1.2.1.6 です。 この OID に従属する (同じ 7 つの識別子で始まる) すべての要素は,サブツリーのオブジェクト・テーブルに含まれています。 MIB サブツリーは,単一の MIB オブジェクト (リーフ・ノード) でも特定のインスタンスでもかまいません。

MIB サブツリーを登録することにより,サブエージェントは,その MIB サブツリーの領域内部にあるすべての MIB 変数 (または OID) に対する SNMP 要求を処理するということを示します。 したがって,サブエージェントは MIB 変数をまだ組み込んでいるいる MIB サブツリーの中で最も完全に (長く) 修飾されたものを登録します。

esnmp_register2 ルーチンを使用するサブエージェントは,ローカル・ノードとクラスタに対して,同じ MIB サブツリーを登録できます。 MIB サブツリーを両方に登録するには,esnmp_register2 ルーチンを 2 回呼び出す必要があります。 1 回は options パラメータで ESNMP_REG_OPT_CLUSTER ビットをセットし,もう 1 回は options パラメータで ESNMP_REG_OPT_CLUSTER ビットをクリアして呼び出します。 あるいは,MIB サブツリーをクラスタのみ,またはローカル・ノードのみに対して登録することもできます。 この場合は,options パラメータで ESNMP_REG_OPT_CLUSTER ビットをそれぞれセット/クリアします。

また,サブエージェントは,以前に登録したサブツリーの OID 範囲に重複して,あるいは他のサブエージェントが登録したサブツリーの OID の範囲に重複して MIB サブツリーを登録できます。

たとえば,os_mibsgated という 2 つの Tru64 UNIX デーモンを考えてみます。 os_mibs デーモンは ip MIB サブツリー (1.3.6.1.2.1.4) を登録し,gated デーモンは ipRouteEntry MIB サブツリー (1.3.6.1.2.1.4.21.1) を登録します。 これらの登録はどちらも,options パラメータで ESNMP_REG_OPT_CLUSTER ビットをセットして行われます。 ipRouteIfIndex (1.3.6.1.2.1.4.21.1.2) などの ipRouteEntry 内の ip MIB 変数に対する要求は,gated サブエージェントへ送られます。 ipNetToMediaIfIndex (1.3.6.1.2.1.4.22.1.1) などの他の ip 変数に対する要求は,os_mibs サブエージェントへ送られます。 gated プロセスが終了した場合,またはipRouteEntry MIB サブツリーへの登録を解除した場合,その後の ipRouteIfIndex への要求は,os_mibs サブエージェントへ送られます。 これは,すべての ipRouteEntry MIB 変数を含む ip MIB サブツリーが,ipRouteIfIndex に対する要求の最も優先順位が高い領域となっているためです。

esnmp_register2 ルーチンの構文は次のとおりです。

int esnmp_register2(
        ESNMP_REG *reg );

引数の定義は次のとおりです。

reg

ESNMP_REG 構造体へのポインタ。 次のようなフィールドがあります。

subtree

処理する MIB サブツリーに対応する SUBTREE 構造体へのポインタ。 SUBTREE 構造体は,MIB ドキュメントから直接得られた mosy および snmpi ユーティリティで生成されたコードで外部宣言され初期化されます (xxx_tbl.c および xxx_tbl.hxxx はサブツリー名)。

注意

このフィールドによってポイントされているメモリはすべて,プログラムの存続期間中に libesnmp によって参照されるため,永続的なストレージを持っていなければなりません。 snmpi ユーティリティによって発行されたデータ宣言を使用してください。

priority

登録の優先順位。 数値が最大のエントリは,優先順位が最も高くなっています。 範囲は 1 〜 255 です。 OID (オブジェクト識別子) の範囲内で優先順位が最も高い MIB サブツリーを登録したサブエージェントは,その OID の範囲内の要求をすべて受け取ります。

同じ優先順位で登録されているサブツリーは重複しているとされ,マスタ・エージェントにより登録はリジェクトされます。

priority フィールドは異なる構成を処理するために協力するサブエージェントのためのメカニズムです。

timeout

この MIB サブツリーでデータを要求した際に,マスタ・エージェントが応答を待つ秒数。 0 〜 300 までの値を指定します。 0 を指定した場合は,省略時のタイムアウト (3 秒) が使用されます。 省略時の値を使用することをお勧めします。

range_subid

整数の値。 0 以外の場合,range_upper_bound フィールドとともに,MIB サブツリーの OID サブ識別子の 1 つの代わりに範囲を指定します。 range_subid フィールドは,range_upper_bound フィールドによって変更される OID サブ識別子を指定します。

range_upper_bound

整数の値。 0 以外の range_subid フィールドと組み合わせて,MIB サブツリーの OID サブ識別子の 1 つの代わりに範囲を指定します。 MIB サブツリーの OID サブ識別子の範囲に関して,range_upper_bound フィールドは上限,range_subid は下限になります。

options

整数の値。 ESNMP_REG_OPT_CLUSTER に設定されると,登録がクラスタ全体で有効であることを示し,0 に設定されると,登録がローカル・ノードに対して有効であることを示します。

state

次に示す整数の値のいずれかをとり,呼び出す側に対して,この MIB サブツリーの登録の非同期更新を行います。 esnmp_poll ルーチンが終了した後,呼び出す側はこのパラメータを調べることができます。

ESNMP_REG_STATE_PENDING

登録は現在ローカルに保留されており,マスタ・エージェントとの接続を待っています。

ESNMP_REG_STATE_SENT

登録はマスタ・エージェントに送られました。

ESNMP_REG_STATE_DONE

登録はマスタ・エージェントから正常に肯定応答されました。

ESNMP_REG_STATE_REGDUP

重複しているため,登録はマスタ・エージェントからリジェクトされました。

ESNMP_REG_STATE_REGNOCLU

マスタ・エージェントはクラスタ登録をサポートしていません。

ESNMP_REG_STATE_REJ

マスタ・エージェントは他の理由でリジェクトしました。

instance

ヌルでない場合,この入力パラメータは,登録内の MIB サブツリーに対して部分的にまたは完全に限定されたインスタンスを指定します。 テーブル内の row を登録する際は,このパラメータを使用します。 テーブル内の row の登録についての詳細は,6.3.1.2 項snmpi(8) を参照してください。

戻り値は次のとおりです。

ESNMP_LIB_OK

esnmp_register2 ルーチンが正常に終了しました。

ESNMP_LIB_BAD_REG

esnmp_init が呼び出されていないか,タイムアウト・パラメータが正しくないか,登録の余地がないか,MIB サブツリーがすでに登録のキューにいれられているかしています。 また,ログ・ファイルにもメッセージがあります。

ESNMP_LIB_LOST_CONNECTION

サブエージェントとマスタ・エージェントとの通信が途絶えています。

状態は,要求の開始のみを示しています。 マスタ・エージェントの応答に返される実際の状態は,その後の esnmp_poll ルーチンへの呼び出しで reg->state フィールドに返されます。

次に示すのは esnmp_register2 ルーチンの例です。

#include <esnmp.h>
#define RESPONSE_TIMEOUT	        0    /* use the default time set
                                        in esnmp_init message */
#define REGISTRATION_PRIORITY	10	    /* priority at which the MIB
                                        subtree will register */
#define RANGE_SUBID             7    /* the identifier position in
                                        oid->elements just after
                                        mib-2 */
#define RANGE_UPPER_BOUND       8    /* the identifier for egp,
                                        under mib-2 */
int status;
 
extern SUBTREE ip_subtree;
static ESNMP_REG esnmp_reg_for_ip2egp;  /* retain this structure
                                           for a subsequent call to
                                           esnmp_unregister2  */
 
/*
 *  initialize the ESNMP_REG structure
 */
memset(&esnmp_reg_for_ip2egp, 0, sizeof(ESNMP_REG));
esnmp_reg_for_ip2egp.subtree           = &ip_subtree;
esnmp_reg_for_ip2egp.priority          = REGISTRATION_PRIORITY;
esnmp_reg_for_ip2egp.timeout           = RESPONSE_TIMEOUT;
esnmp_reg_for_ip2egp.range_subid       = RANGE_SUBID;
esnmp_reg_for_ip2egp.range_upper_bound = RANGE_UPPER_BOUND;
 
status = esnmp_register2( &esnmp_reg_for_ip2egp );
if (status != ESNMP_LIB_OK) {
    printf("Could not queue the 'ipRouteEntry' \n");
    printf("subtree for registration\n");
}
 

6.3.1.7    esnmp_unregister2 ルーチン

esnmp_unregister2 ルーチンは マスタ・エージェントから MIB サブツリーの登録を解除します。 このルーチンは,MIB サブツリーが esnmp_register2 ルーチンを用いて登録されている場合にのみ使用してください。

このルーチンをアプリケーションから呼び出して,eSNMP サブエージェントに対して,この MIB サブツリーの変数への要求をそれ以上処理しないように通知することができます。 MIB サブツリーは,その後必要に応じて esnmp_register2 ルーチンを呼び出して登録できます。

esnmp_unregister2 ルーチンの構文は次のとおりです。

int esnmp_unregister2(
        ESNMP_REG *reg );

引数は次のとおりです。

reg

esnmp_register2 ルーチンが呼び出されたときに使用される,ESNMP_REG 構造体へのポインタ。

戻り値は次のとおりです。

ESNMP_LIB_OK

ルーチンは正常に終了しました。

ESNMP_LIB_BAD_REG

MIB サブツリーが登録されていません。

ESNMP_LIB_LOST_CONNECTION

MIB サブツリーの登録を解除する要求が送信できませんでした。 プロトコルを再起動する必要があります。

次に示すのは esnmp_unregister2 ルーチンの例です。

#include <esnmp.h>
int status
 
extern ESNMP_REG esnmp_reg_for_ip2egp;
 
status = esnmp_unregister2( &esnmp_reg_for_ip2egp );
 
switch(status) {
   case ESNMP_LIB_OK:
   printf("The esnmp_unregister2 routine completed successfully.\n");
   break;
 
   case ESNMP_LIB_BAD_REG:
   printf("The MIB subtree was not registered.\n");
   break;
 
   case ESNMP_LIB_LOST_CONNECTION:
   printf("%s%s%s\n", "The request to unregister the ",
                      "MIB subtree could not be sent.  ",
                      "You should restart the protocol.\n");
   break;
}
 

6.3.1.8    esnmp_capabilities ルーチン

esnmp_capabilities ルーチンは,サブエージェントの機能をマスタ・エージェントの sysORTable に追加します。 sysORTable はエージェントのオブジェクト・リソースを含む概念的なテーブルであり,RFC 1907 で記述されています。

このルーチンは,esnmp_init ルーチンを呼び出して eSNMP を初期化した後の任意の時点で呼び出されます。

esnmp_capabilities ルーチンの構文は次のとおりです。

void esnmp_capabilities(
        OID *agent_cap_id,
        char *agent_cap_descr );

引数は次のとおりです。

agent_cap_id

最も優先順位が高いエージェント機能識別子を表すオブジェクト識別子へのポインタ。 この値は,管理対象ノードの sysORTable で sysORID オブジェクトに対して使用されます。

agent_cap_descr

agent_cap_id を記述するヌル終了文字列へのポインタ。 この値は,管理対象ノードの sysORTable で sysORDescr オブジェクトに対して使用されます。

6.3.1.9    esnmp_uncapabilities ルーチン

esnmp_uncapabilities ルーチンは,サブエージェントの機能をマスタ・エージェントの sysORTable から削除します。

このルーチンは,サブエージェントがその機能を動的に変更する場合に呼び出されます。 サブエージェントに対する論理接続がクローズされると,マスタ・エージェントは sysORTable 内の関連エントリを削除します。

esnmp_uncapabilities ルーチンの構文は次のとおりです。

void esnmp_uncapabilities(
        OID *agent_cap_id );

引数は次のとおりです。

agent_cap_id

sysORTable から削除されるエージェント機能文のオブジェクト識別子へのポインタ。

6.3.1.10    esnmp_poll ルーチン

esnmp_poll ルーチンは,マスタ・エージェントによって送信されているペンディング・メッセージを処理します。 このルーチンは,ユーザの select() コールが eSNMP ソケットにデータが用意されていることを示した後に呼び出されます (このソケットは esnmp_init ルーチンに対する呼び出しから返されます)。 そのソケットでメッセージがペンディングされていない場合は,esnmp_poll ルーチンはメッセージを受け取るまでブロックします。

受けとったメッセージが問題を指摘している場合,ルーチンは syslog ファイルにエントリを作成し,エラー状態を返します。

受けとったメッセージが SNMP データに対する要求である場合,ルーチンはオブジェクト・テーブルを照会し,適切なメソッド・ルーチンを呼び出します。

esnmp_poll ルーチンの構文は次のとおりです。

int esnmp_poll(void );

戻り値は次のとおりです。

ESNMP_LIB_OK

esnmp_poll ルーチンが正しく終了しました。

ESNMP_LIB_BAD_REG

マスタ・エージェントによる以前の再登録が失敗しています。 ログ・ファイルを参照してください。

ESNMP_LIB_DUPLICATE

重複するサブエージェント ID がマスタ・エージェントによって既に受け取られています。 これは,esnmp_init エラーです。

ESNMP_LIB_NO_CONNECTION

マスタ・エージェントは esnmp_init 要求の開始に失敗しました。 後で再実行してください。 また,ログ・ファイルを参照してください。

ESNMP_LIB_CLOSE

CLOSE メッセージが受信されました。

ESNMP_LIB_NOTOK

eSNMP プロトコル・エラーが発生しました。 パケットは放棄されました。

ESNMP_LIB_LOST_CONNECTION

マスタ・エージェントとの通信がロストしました。 再度接続してください。

6.3.1.11    esnmp_are_you_there ルーチン

esnmp_are_you_there ルーチンは,ネットワーク・インタフェースが動作しているかどうかをすぐに報告することをマスタ・エージェントに要求します。 この呼び出しは応答を待つ間ブロックしません。 応答は,esnmp_poll ルーチンを呼び出すことによって処理されます。

タイムアウト時間内に応答がない場合,アプリケーションはesnmp_init ルーチンを呼び出すことによって eSNMP プロトコルを再起動します。 eSNMP ライブラリが管理するタイマはありません。

esnmp_are_you_there ルーチンの構文は次のとおりです。

int esnmp_are_you_there(void );

戻り値は次のとおりです。

ESNMP_LIB_OK

要求が送信されました。

ESNMP_LIB_LOST_CONNECTION

マスタ・エージェントがダウンしているため要求を送信できません。

6.3.1.12    esnmp_trap ルーチン

esnmp_trap ルーチンは,マスタ・エージェントへトラップ・メッセージを送ります。 この関数はいつでも呼び出すことができます。 マスタ・エージェントが eSNMP プロトコルを実行していない場合,トラップはキュー登録され,通信が確立したときに送られます。

トラップ・メッセージが実際にマスタ・エージェントへ送られるのは,esnmp_init 呼び出しに対するマスタ・エージェントの応答が処理された後です。 esnmp_poll ルーチンの後の呼び出し中のほとんどの場合に対して,この処理は API コール内で行われます。 esnmp_initesnmp_poll,および esnmp_trap ルーチンを呼び出すのが,マスタ・エージェントへトラップを送る最も速い方法です。

マスタ・エージェントはトラップを SNMP トラップ・メッセージへフォーマットし,現在の構成のベースになっている管理ステーションへ送ります。 マスタ・エージェントの構成については, snmpd(8) および snmpd.conf(4) を参照してください。

マスタ・エージェントから返されるトラップに関する応答はありません。

esnmp_trap ルーチンの構文は次のとおりです。

int esnmp_trap(
        int generic_trap,
        int specific_trap,
        char *enterprise,
        VARBIND *vb );

引数は次のとおりです。

generic_trap

汎用トラップ・コード。 SNMPv2 トラップに対しては 0 を設定します。

specific_trap

特定トラップ・コード。 SNMPv2 トラップに対しては 0 を設定します。

enterprise

ドット表記の エンタープライズ OID 文字列。 MIB 仕様を定義する際に NOTIFICATION-TYPE マクロによって定義されるオブジェクト識別子を設定します。 この値は,SNMPv2-Trap-PDU 内の SnmpTrapOID.0 の値として受け渡されます。

vb

データの VARBIND リスト (NULL ポインタはデータがないことを示します。 )

戻り値は次のとおりです。

ESNMP_LIB_OK

ルーチンが正しく終了しました。

ESNMP_LIB_LOST_CONNECTION

ルーチンは,マスタ・エージェントへトラップ・メッセージを送信できませんでした。

ESNMP_LIB_NOTOK

何らかの原因でメッセージが生成されませんでした。

6.3.1.13    esnmp_term ルーチン

esnmp_term ルーチンは,マスタ・エージェントにクローズ・メッセージを送り,eSNMP プロトコルをシャット・ダウンします。 すべてのサブエージェントは,終了時にこのルーチンを呼び出して,マスタ・エージェントが MIB 登録をすぐに更新できるようにして,サブエージェントに代わって eSNMP によって使用されているシステム・リソースを解放できるようにする必要があります。

esnmp_term ルーチンの構文は次のとおりです。

void esnmp_term(void );

戻り値は次のとおりです。

ESNMP_LIB_OK

esnmp_term ルーチンは,パケットを送信できない場合でも,常に ESNMP_LIB_OK を返します。

6.3.1.14    esnmp_sysuptime ルーチン

esnmp_sysuptime ルーチンは,gettimeofday によって取得した UNIX システム時間を sysUpTime と同じタイム・ベースに変換します。 このデータは,1/100 秒の単位で TimeTicks データ・タイプ (マスタ・エージェントが起動されてからの時間) として使用することができます。 このタイム・ベースは,esnmp_init ルーチンに応答してマスタ・エージェントから取得されます。

このルーチンは UNIX タイムスタンプを SNMP TimeTicks に変換するための一般的なメカニズムを提供します。 この関数は,特定のUNIXに対する sysUpTime の適切な値を返します。 ヌルのタイムスタンプを渡すと sysUpTime の現在の値が返されます。

構文は次のとおりです。

unsigned int esnmp_sysuptime(
        struct timeval *timestamp );

引数は次のとおりです。

timestamp

gettimeofday システム・コールから取得した値を含んでいる struct timeval へのポインタです。 構造体は include/sys/time.h に定義されています。

NULL ポインタは現在の sysUpTimeを返すことを意味します。

esnmp_sysuptime ルーチンの例を次に示します。

#include <sys/time.h>
#include <esnmp.h>
struct timeval timestamp;
 
gettimeofday(&timestamp, NULL);
o_integer(vb, object, esnmp_sysuptime(&timestamp));
 

戻り値は次のとおりです。

0

エラー (gettimeofday の失敗) を示します。 それ以外の場合は,timestamp に,マスタ・エージェント・プロトコルが開始されてからの時間が 1/100 秒の単位で含まれます。

6.3.2    メソッド・ルーチン呼び出しインタフェース

SNMP 要求には,多数の VariableBindings (コード化された MIB 変数) が含まれていることがあります。 サブエジェントで実行されている libsnmp コードは,それぞれの VariableBinding をオブジェクト・テーブル項目と照合します。 そのとき,オブジェクト・テーブルのメソッド・ルーチンが呼ばれます。

このため,メソッド・ルーチンは単一の MIB 変数をサービスするため呼び出され,単一の SNMP 要求の中で同じメソッド・ルーチンが複数回呼び出されることもあります。

メソッド・ルーチン呼び出しインタフェースには次の関数が含まれます。

メソッド・ルーチンについての詳細は,6.3.2.3 項を参照してください。

6.3.2.1    *_get ルーチン

*_get ルーチンは,MIB グループ (たとえば MIB-2 における system) やテーブル・エントリ (たとえば MIB-2 における ifEntry) などの,指定した MIB 項目に対するメソッド・ルーチンです。 しかし,それはどうとでもできます。 詳細については, snmpi(8) を参照してください。

libesnmp ルーチンは,登録されているサブツリーによって認識されるオブジェクト・テーブルの Get 操作に対して指定されているルーチンを呼び出します。

この関数は,サブエージェント・オブジェクト・テーブルのいくつかの要素によってポイントされます。 要求がオブジェクトに届くと,そのメソッド・ルーチンが呼び出されます。 *_get メソッド・ルーチンが Get SNMP 要求に対する応答の際に呼び出されます。

*_get ルーチンの構文は次のとおりです。

int mib-group_get(
        METHOD *method );

引数は次のとおりです。

method

次のフィールドを含む METHOD へのポインタです。

action

ESNMP_ACT_GET,ESNMP_ACT_GETNEXT,あるいは ESNMP_ACT_GETBULK のいずれか。

serial_num

この SNMP 要求に対してユニークな整数値。 単一の SNMP 要求をサービスしている間に呼び出されるメソッド・ルーチンは,同じ値 serial_num を受け取ります。 新しい SNMP 要求は,新しい値 serial_num によって示されます。

repeat_cnt

GetBulk に対してのみ使用します。 この値は,反復している VARBIND の現在の反復値を示します。 この値は,1〜 max_repetitions の間で増加します。 0 の値は,VARBIND 構造体を反復しないことを示します。

max_repetitions

GetBulk に使用します。 反復数の最大値です。 VARBIND 構造体を反復しない場合は 0 になります。 呼び出しの繰り返し数の最大値を知ることによって,その後の処理を最適化することができます。

varbind

OID およびデータ・フィールドを埋めなければならない VARBIND 構造体に対するポインタ。 メソッド・ルーチンのエントリ時,method->varbind->name フィールドは要求された OID です。

メソッド・ルーチンの終了時,要求されたデータが method->varbind フィールドに含まれ,返された VARBIND に対する実際のインスタンス OID を反映して method->varbind->name フィールドが変更されます。

libsnmp ルーチン (o_integero_stringo_oid,および o_octet) は一般にデータをロードするために使用されます。 libsnmp instance2oid ルーチンは,method->varbind->name フィールドで OID を更新するために使用されます。

object

MIB 変数が参照されているオブジェクト・テーブル・エントリへのポインタ。 method->object->object_index フィールドは,(1 つのメソッド・ルーチンが多くのオブジェクトをサービスする際に便利な) オブジェクト・テーブル内でのこのオブジェクトのユニークなインデックスです。

method->object->oid フィールドは,MIB においてこのオブジェクトに対して定義される OID です。 要求されたインスタンスは,この OID と method->varbind->name フィールドで発見された要求の OID とを比較することによって引き出されます。 この操作には oid2instance が便利です。

*_getルーチンに対する可能な戻り値は次のとおりです。

ESNMP_MTHD_noError

ルーチンが正常終了しました。

ESNMP_MTHD_noSuchObject

要求したオブジェクトが返されないか,あるいは存在していません。

ESNMP_MTHD_noSuchInstance

オブジェクトの要求したインスタンスが返されないか,あるいは存在していません。

ESNMP_MTHD_genErr

一般的な処理エラー。

6.3.2.2    *_set メソッド・ルーチン

*_set メソッド・ルーチンは,MIB グループ (たとえば MIB-2 の system) あるいはテーブル・エントリ (たとえば MIB-2 の ifEntry) などの,指定された MIB 項目のためのものです。 しかし,どうとでもなります。 詳細については, snmpi(8) を参照してください。

libesnmp ルーチンは,登録されているサブツリーによって認識されるオブジェクト・テーブルの Set 操作に対して指定されているルーチンを呼び出します。

この関数は,サブエージェント・オブジェクト・テーブルのいくつかの要素によってポイントされます。 オブジェクトに対する要求が到着すると,そのメソッド・ルーチンが呼び出されます。 *_set メソッド・ルーチンは Set SNMP 要求に応答して呼び出されます。

*_set メソッド・ルーチンの構文は次のとおりです。

int mib-group_set(
        METHOD *method );

引数は次のとおりです。

method

次のフィールドを含む METHOD 構造体へのポインタです。

action

ESNMP_ACT_SET,ESNMP_ACT_COMMIT,ESNMP_ACT_UNDO,あるいは ESNMP_ACT_CLEANUP のいずれか。

serial_num

この SNMP 要求に対してユニークな整数値。 単一の SNMP 要求をサービスしている間に呼び出されるメソッド・ルーチンは,同じ値 serial_num を受け取ります。 新しい SNMP 要求は,新しい値 serial_num によって示されます。

varbind

MIB 変数の提供するデータおよび名前 (OID) を含む VARBIND 構造体に対するポインタ。 インスタンス情報は OID から展開され,method->row->instance フィールドに置かれます。

object

MIB 変数が参照されているオブジェクト・テーブル・エントリへのポインタ。 method->object->object_index フィールドは,(1 つのメソッド・ルーチンが多くのオブジェクトをサービスする際に便利な) オブジェクト・テーブル内でのこのオブジェクトのユニークなインデックスです。 method->object->oid フィールドは,MIB においてこのオブジェクトに対して定義される OID です。

flags

libesnmp によって設定される読み取り専用の整数ビットマスクです。 ESNMP_FIRST_IN_ROW ビットを設定すると,この呼び出しが row に設定される最初のオブジェクトであることを示します。 ESNMP_LAST_IN_ROW ビットを設定すると,この呼び出しが row に設定される最後のオブジェクトであることを示します。 ESNMP_LAST_IN_ROW ビットが設定されている METHOD 構造体だけが,commit,undo,cleanup のフェーズのメソッド・ルーチンに渡されます。

row

esnmp.h ヘッダ・ファイルで定義されている ROW_CONTEXT 構造体へのポインタです。 同じグループを参照し同じインスタンス番号を持つメソッド・ルーチンに対するすべての Set 呼び出しは,同じ row 構造体に存在します。 メソッド・ルーチンは,Set 呼び出し実行中に,commit および undo フェーズで使用する情報を row 構造体に蓄積することができます。 累積されたデータは,cleanup フェーズでメソッド・ルーチンを使用して解放することができます。 ROW_CONTEXT 構造体には次のファールドがあります。

instance

概念的 row に対するインスタンス OID を含む配列のアドレスです。 libesnmp ルーチンは,要求された変数binding oid から object oid を引くことによってこの配列を作成します。

instance_len

method->row->instance フィールドのサイズです。

context

要求の処理に必要となるデータを参照するために,メソッド・ルーチンが使用するプライベートなポインタです。

save

要求の undo に必要となるデータを参照するために,メソッド・ルーチンがプライベートに使用するポインタです。

state

状態情報を保持するためにメソッド・ルーチンがプライベートに使用する整数です。

*_set メソッド・ルーチンの可能な戻り値は次のとおりです。

ESNMP_MTHD_noError

ルーチンが正常終了しました。

ESNMP_MTHD_notWritable

要求したオブジェクトが設定できないか,あるいは実現されていません。

ESNMP_MTHD_wrongType

要求された値のデータ型が正しくありません。

ESNMP_MTHD_wrongLength

要求した値の長さが正しくありません。

ESNMP_MTHD_wrongEncoding

要求した値の表現が正しくありません。

ESNMP_MTHD_wrongValue

要求した値が範囲外です。

ESNMP_MTHD_noCreation

要求したインスタンスは常に作成できません。

ESNMP_MTHD_inconsistentName

要求したインスタンスは現在作成できません。

ESNMP_MTHD_inconsistentValue

要求した値に矛盾があります。

ESNMP_MTHD_resourceUnavailable

リソースの制約によって失敗しました。

ESNMP_MTHD_genErr

一般的な処理エラーが発生しました。

ESNMP_MTHD_commitFailed

commit フェーズが失敗しました。

ESNMP_MTHD_undoFailed

undo フェーズが失敗しました。

*_set ルーチンの処理

各変数割り当ては解析され,そのオブジェクトはオブジェクト・テーブルに置かれます。 各 VARBIND 構造体に対して METHOD 構造体が作成されます。 これらの METHOD 構造体は,各フェーズの処理に便利な ROW_CONTEXT 構造体をポイントします。 同じ概念的 row の オブジェクトは,すべて同じ ROW_CONTEXT 構造体をポイントします。 決定は,次の項目をチェックすることによって行われます。

ROW_CONTEXT 構造体は,概念的 row に対するインスタンス情報でロードされます。 ROW_CONTEXT 構造体の context および save フィールドは NULL に設定され, state フィールドは ESNMP_SET_UNKNOWN に設定されます。

各オブジェクトに対するメソッド・ルーチンが呼び出され,アクション・コードに ESNMP_ACT_SET を持つ METHOD 構造体が渡されます。

すべてのメソッド・ルーチンが正常終了を返す場合,各 row に対して単一のメソッド・ルーチン (最後に呼び出されたメソッド・ルーチン) が method->action == ESNMP_ACT_COMMIT で呼び出されます。

いずれかの row が失敗を報告すると,正常にコミットしたすべての row に対してフェーズを行わないよう伝えます。 この処理は,method->action == ESNMP_ACT_UNDO で,各 row に対して単一のメソッド・ルーチン (commit フェーズで呼び出されたメソッド・ルーチン) を呼び出すことによって行われます。

最後に各 row が解放されます。 各 row に対する単一のメソッド・ルーチンは,method->action == ESNMP_ACT_CLEANUP で呼び出されます。 この処理は,前の処理の結果にかかわらず,各 row ごとに行われます。

次のリストでアクション・コードを説明しています。

ESNMP_ACT_SET

各オブジェクトのメソッド・ルーチンは,Set フェーズですべてのオブジェクトが処理されるかメソッド・ルーチンがエラー状態値を返すまでの間に呼び出されます (これは,各オブジェクトのメソッド・ルーチンが呼び出される唯一のフェーズです)。 同じ概念 row における変数割り当てのために,method->row は共通の ROW_CONTEXT をポイントします。

呼び出されてるのが ROW_CONTEXT に対する最後のオブジェクトである場合,method->flags ビットマスクは ESNMP_LAST_IN_ROW ビットを設定します。 これによって,概念的 row に対する各変数割り当てを見ることができるため,最後の整合性チェックが可能になります。

このフェーズにおけるメソッド・ルーチンのジョブは,SetRequest が動作するかどうか判断し,そうでない場合は正しい SNMP エラー・コードを返し,commit フェーズで Set を実際に実行するのに必要なコンテキスト・データを用意することです。

method->row->context はメソッド・ルーチンに対してプライベートで,libesnmp はこれを使用しません。 典型的な使用方法は,概念的 row に対する VARBIND からのデータでロードされた,エミットされた foo_type 構造体のアドレスを保管することです。

ESNMP_ACT_COMMIT

いくつかの変数割り当てが概念的 row に存在していたとしても,(SetRequest の順序で) 最後の変数割り当てのみが処理されます。 そのため,共通の row をポイントするすべてのメソッド・ルーチンのうち最後のルーチンのみが呼び出されます。

このメソッド・ルーチンは,操作を実行するのに必要なすべてのデータおよびコンテキストが利用できなければなりません。 また,現在のデータのスナップショットあるいは Set を undo するために必要なデータを保管する必要があります。 method->row->save フィールドは,この処理を実行するのに必要なデータへのポインタを保持します。 典型的な使用方法は,概念的 row の現在のデータでロードされた,xxx 構造体のアドレスを保管することです。 xxx 構造体は,snmpi プログラムが自動的に生成したものです。

method->row->save フィールドもメソッド・ルーチンに対してプライベートで,libesnmp はこれを使用しません。

set 操作が成功した場合,ESNMP_MTHD_noError を返します。 失敗した場合はコミットを取消し,ESNMP_MTHD_commitFailed の値を返します。

commit フェーズでエラーが返された場合,libesnmp は undo フェーズに入ります。 それ以外の場合は,cleanup フェーズに入ります。

注意

現在のサブエージェントで Set 操作が成功しても,SetRequest が他のサブエージェントに及び,他のサブエージェントが失敗するため,undo フェーズが発生する場合があります。

ESNMP_ACT_UNDO

正しくコミットした各概念的 row に対しては,method->action == ESNMP_ACT_UNDO で同じメソッド・ルーチンが呼び出されます。 commit フェーズでまだ呼び出されていないROW_CONTEXT 構造体は,undo フェーズで呼び出されることはなく,cleanup フェーズで呼び出されます。

メソッド・ルーチンは,commit フェーズで実行されたときの条件をリストアすべきです (この処理は,method->row->save フィールドによってポイントされるデータを使用して行われます)。

成功した場合は ESNMP_MTHD_noError を返し,失敗した場合は ESNMP_MTHD_undoFail を返します。

ESNMP_ACT_CLEANUP

何が発生したかに関係なく,この時点で各 ROW_CONTEXT は cleanup フェーズに入ります。 commit フェーズで呼び出されたのと同じメソッド・ルーチンは,method->action == ESNMP_ACT_CLEANUP で呼び出されます。

これは,SetRequest の処理の終わりを示します。 メソッド・ルーチンは,method->row->context および method->row->save フィールドで割り当てられ保管されていたダイナミック・メモリの解放など,必要な処理を行います。

cleanup フェーズの関数の戻り状態値は無視されます。

6.3.2.3    メソッド・ルーチンのアプリケーションでのプログラミング

subtree_tbl.h ファイルで宣言されるているメソッド・ルーチンのコードを作成する必要があります。 各メソッド・ルーチンは,次のように METHOD 構造体へのポインタを引数として持ちます。

int mib_group_get(
        METHOD *method int mib_group_set(
        METHOD *method );

Get メソッド・ルーチンは,GetGetNext および GetBulk を実行するのに使用されます。

Get メソッド・ルーチンは次のタスクを行います。

  1. 必要な OID のインスタンス部分を抽出します。 この処理は oid2instance libesnmpルーチンで行います。 method->object->oid フィールド (オブジェクトのベース OID) と method->varbind->name フィールド (要求された OID) とを比較することによって手作業でこの処理を行うこともできます。

  2. インスタンスの妥当性を判断します。 インスタンス OID は,ヌル,あるいはいずれかの長さです (何が要求され,オブジェクトがどのように選択されたかに依存します)。 インスタンス OID のチェックによって,要求をすぐにリジェクトすることができます。

  3. データを抽出します。 インスタンス OID と method->action フィールドをもとに,どのようなデータを返すべきかを判断します。

  4. 応答 OID をそのメソッドの VARBIND 構造体にロードします。 返されている実際の MIB 変数インスタンスの OID を method->varbind フィールドに設定します。 この処理は,返したいインスタンス OID を整数の配列にロードし instance2OID libesnmp ルーチンを呼び出すことによって行われます。

  5. 応答データをメソッドの VARBIND 構造体にロードします。

    次に示す,データ・タイプに対応する libesnmp ライブラリを使用して,返すデータを method->varbind フィールドにロードします。

    これらのルーチンは,指定したデータのコピーを作成します。 libesnmp 関数はコピーされたデータに関係するメモリの管理を行います。 メソッド・ルーチンはオリジナル・データのメモリ管理を行う必要があります。

    ルーチンは,MIB 変数に対するオブジェクト・テーブルで定義されているタイプへの必要な変換を行い,変換したデータを method->varbind フィールドへコピーします。

    データ値の表現については,値の表現の項を参照してください。

  6. 次のように正しい状態値を返します。

値の表現

各データ型に対する VARBIND 構造体の値は次のように表現されます。 (OCT および OID 構造体については esnmp.hファイルを参照してください。 )

6.3.3    libsnmp サポート・ルーチン

以降の節では,libsnmp サポート・ルーチンについて説明します。 libsnmp サポート・ルーチンには次のルーチンがあります。

6.3.3.1    o_integer ルーチン

o_integer ルーチンは,整数値を適切なデータ型で VARBIND 構造体にロードします。

構文は次のとおりです。

int o_integer(
        VARBIND *vb,
        OBJECT *obj,
        unsigned long value );

引数は次のとおりです。

vb

データを受け取る VARBIND 構造体へのポインタです。 この関数はVARBIND 構造体は割り当てません。

obj

VARBIND 構造体において OID と関連する MIB 変数に対する OBJECT 構造体へのポインタです。

value

VARBIND 構造体に挿入される値です。

オブジェクト構造体で定義されているように,実数型は次のいずれかでなければなりません。 これ以外の場合は,エラーが返されます。

実数型が IpAddress の場合,ネットワーク・バイト順で 4 バイト整数が仮定されます。

ESNMP_TYPE_Integer32:32 ビット INTEGER
ESNMP_TYPE_Counter32:32 ビット Counter (符号なし)
ESNMP_TYPE_Gauge32:32 ビット Gauge (符号なし)
ESNMP_TYPE_TimeTicks:32 ビット TimeTicks (符号なし)
ESNMP_TYPE_UInteger32:32 ビット INTEGER (符号なし)
ESNMP_TYPE_Counter64:64 ビット Counter (符号なし)
ESNMP_TYPE_IpAddress:IMPLICIT OCTET STRING (4)

o_integer ルーチンの例を次に示します。

#include <esnmp.h>
#include "ip_tbl.h"  <-- for ipNetToMediaEntry_type definition
VARBIND     *vb       = method->varbind;
OBJECT      *object   = method->object;
ipNetToMediaEntry_type *data;
:
: assume buffer and structure member assignments occur here
:
switch(arg) {
case I_atIfIndex:
return o_integer(vb, object, data->ipNetToMediaIfIndex);
 

戻り値は次のとおりです。

ESNMP_MTHD_noError

ルーチンが正常に終了しました。

ESNMP_MTHD_genErr

エラーが発生しました。

6.3.3.2    o_octet ルーチン

o_octet ルーチンはオクテット値を適切なデータ型で VARBIND 構造体へロードします。

構文は次のとおりです。

int o_octet(
        VARBIND *vb,
        OBJECT *obj,
        OCT *oct );

引数は次のとおりです。

vb

データを受け取る VARBIND 構造体へのポインタです。 この関数は VARBIND 構造体を割り当てません。

注意

vb フィールドのもとの値が NULL でない場合,このルーチンはそれを解放しようとします。 このため,自身の vb 構造体を割り当てるために malloc コマンドを使用する場合は,使用する前にゼロ詰めします。

obj

VARBIND 構造体の OID に関係する MIB 変数に対する OBJECT 構造体へのポインタです。

value

VARBIND 構造体に挿入される値です。

オブジェクト構造体で定義されているように,実数型は次のいずれかでなければなりません。 これ以外の場合は,エラーが返されます。

ESNMP_TYPE_OCTET_STRING OCTET STRING
ESNMP_TYPE_IpAddress IMPLICIT OCTET STRING (4) -- オクテット型,ネットワーク・バイト順
ESNMP_TYPE_DisplayString DisplayString (Textual Convention)
ESNMP_TYPE_Opaque IMPLICIT OCTET STRING

o_octet ルーチンの例を次に示します。

#include <esnmp.h>
#include "ip_tbl.h"  <-- for ipNetToMediaEntry_type definition
VARBIND     *vb       = method->varbind;
OBJECT      *object   = method->object;
ipNetToMediaEntry_type *data;
:
: assume buffer and structure member assignments occur here
:
switch(arg) {
 case I_atPhysAddress:
 return o_octet(vb, object, &data->ipNetToMediaPhysAddress);
 

戻り値は次のとおりです。

ESNMP_MTHD_noError

ルーチンが正常に終了しました。

ESNMP_MTHD_genErr

エラー状態が発生しました。

6.3.3.3    o_oid ルーチン

o_oid ルーチンは,OID 値を適切なデータ型で VARBIND 構造体にロードします。

構文は次のとおりです。

int o_oid(
        VARBIND *vb,
        OBJECT *obj,
        OID *oid );

引数は次のとおりです。

vb

データを受け取る VARBIND 構造体へのポインタです。 この関数は VARBIND 構造体の割り当ては行いません。

注意

vb フィールドのもとの値が NULL でない場合,このルーチンはそれを解放しようとします。 このため,自身の vb 構造体を割り当てるために malloc コマンドを使用する場合は,使用する前にゼロ詰めします。

obj

VARBIND 構造体の OID と関係する MIB 変数に対する OBJECT 構造体へのポインタです。

value

VARBIND 構造体にデータとして挿入される値です。 OID の長さと値については,6.2.1 項を参照してください。

オブジェクト構造体で定義されているように,実数型は次のいずれかでなければなりません。 これ以外の場合は,エラーが返されます。

ESNMP_TYPE_OBJECT_IDENTIFIEROBJECT IDENTIFIER

o_oid ルーチンの例を次に示します。

#include <esnmp.h>
#include "ip_tbl.h"  <-- for ipNetToMediaEntry_type definition
VARBIND     *vb       = method->varbind;
OBJECT      *object   = method->object;
ipNetToMediaEntry_type *data;
:
: assume buffer and structure member assignments occur here
:
switch(arg) {
 case I_atObjectID:
  return o_oid(vb, object, &data->ipNetToMediaObjectID);
 

戻り値は次のとおりです。

ESNMP_MTHD_noError

ルーチンが正常に完了しました。

ESNMP_MTHD_genErr

エラー状態が発生しました。

6.3.3.4    o_string ルーチン

o_string ルーチンは,文字列値を適切なデータ型で VARBIND 構造体へロードします。

構文は次のとおりです。

int o_string(
        VARBIND *vb,
        OBJECT *obj,
        unsigned char *ptr,
        int len );

引数は次のとおりです。

vb

データを受け取る VARBIND 構造体へのポインタです。 この関数は VARBIND 構造体を割り当てません。

注意

vb フィールドのもとの値が NULL でない場合,このルーチンはそれを解放しようとします。 このため,自身の vb 構造体を割り当てるために malloc コマンドを使用する場合は,使用する前にゼロ詰めします。

obj

VARBIND 構造体の oid と関係する MIB 変数に対する OBJECT 構造体へのポインタです。

ptr

VARBIND 構造体へ挿入するデータを含んでいるバッファへのポインタです。

len

ptr フィールドがポイントするバッファ内のデータの長さです。

オブジェクト構造体で定義されているように,実数型は次のいずれかでなければなりません。 これ以外の場合は,エラーが返されます。

ESNMP_TYPE_OCTET_STRINGOCTET STRING
ESNMP_TYPE_IpAddressIMPLICIT OCTET STRING (4) -- オクテット型,ネットワーク・バイト順
ESNMP_TYPE_DisplayStringDisplayString (Textual Convention)
ESNMP_TYPE_OpaqueIMPLICIT OCTET STRING
ESNMP_TYPE_OBJECT_IDENTIFIEROBJECT IDENTIFIER -- ドット表記では 1.3.6.1.4.1.3.6

o_string ルーチンの例を次に示します。

#include <esnmp.h>
#include "ip_tbl.h"  <-- for ipNetToMediaEntry_type definition
VARBIND     *vb       = method->varbind;
OBJECT      *object   = method->object;
ipNetToMediaEntry_type *data;
:
: assume buffer and structure member assignments occur here
:
switch(arg) {
 case I_atPhysAddress:
  return o_string(vb, object, data->ipNetToMediaPhysAddress.ptr,
                              data->ipNetToMediaPhysAddress.len);
 

戻り値は次のとおりです。

ESNMP_MTHD_noError

ルーチンが正常に終了しました。

ESNMP_MTHD_genErr

エラー状態が発生しました。

6.3.3.5    str2oid ルーチン

str2oid ルーチンは,ヌルで終了する OID 文字列 (ドット表記) を OID 構造体へ変換します。

このルーチンは要素バッファを動的に割り当て,そのポインタを OID 構造体に挿入します。 このバッファは呼び出し元の責任で解放されます。 OID は最大 128 の要素を持つことができます。 空文字列もしくは空き文字列は,0 の要素をひとつ持つ OID 構造体を返します。

str2oid ルーチンは,OID 構造体を割り当てません。

構文は次のとおりです。

OID * str2oid(
        OID *oid,
        char *s );

str2oid ルーチンの例を次に示します。

#include <esnmp.h>
OID abc;
if (str2oid(&abc, "1.2.5.4.3.6") == NULL)
    DPRINTF((WARNING,"It did not work...\n"));
 

戻り値は次のとおりです。

NULL

エラーが発生しました。 そうでない場合は,OID へのポインタ (最初の引数) が返されます。

6.3.3.6    sprintoid ルーチン

sprintoid ルーチンは OID をヌルで終わるドット表記の文字列に変換します。 OID 構造体は要素を 128 まで持つことができます。 フル・サイズの OID 構造体は大きなバッファを必要とします。

構文は次のとおりです。

char * sprintoid(
        char *buffer,
        OID *oid );

sprintoid ルーチンの例を次に示します。

#include <esnmp.h>
#define SOMETHING_BIG 1024
OID abc;
char buffer[SOMETHING_BIG];
:
: assume abc gets initialized with some value
:
printf("dots=%s\n", sprintoid(buffer, &abc));
 

戻り値は最初の引数をポイントします。

6.3.3.7    instance2oid ルーチン

instance2oid ルーチンは,オブジェクトのベース OID のコピーを作成しインスタンス配列のコピーを追加して,値に対する完全な OID を作成します。 instance は整数の配列で,len は要素数です。 インスタンス配列は oid2instance によって作成されるか,あるいは get_next 探索の結果としてキー値から作成されます。

このルーチンは要素バッファを動的に割り当て,呼び出しで渡される OID 構造体にそのポインタを挿入します。 このバッファの解放は呼び出し元のプログラムもしくはモジュールの責任で行われます。

このルーチンを使うには,新しい OID 値を受け取る OID 構造体をポイントして,このルーチンを呼び出してください。 OID 構造体の以前の値は free_oid を最初に呼び出すときに解放され,新しい値が動的に割り当てられ挿入されます。 新しい OID 構造体の初期値はすべて 0 です。

instance2oid ルーチンは OID 構造体を割り当てるのではなく,要素を含む配列のみを割り当てることに注意してください。

構文は次のとおりです。

OID * instance2oid(
        OID *new,
        OBJECT *obj,
        unsigned int *instance,
        int len );

引数は次のとおりです。

new

新しい OID 値を受け取る OID 構造体のポインタです。

obj

入手されている MIB 変数に対するオプジェクト・テーブル・エントリのポインタです。 新しい OID の最初の部分は,MIB オブジェクト・テーブル・エントリから得られた OID です。

instance

instance 値の配列のポインタです。 これらの値は,MIB オブジェクト・テーブル・エントリから得られたベース OID に追加され,新しい OID を構成します。

len

instance 配列の要素数です。

instance2oid ルーチンの例を次に示します。

#include <esnmp.h>
VARBIND *vb;      <-- filled in
OBJECT  *object;  <-- filled in
unsigned int instance[6];
 
-- Construct the outgoing OID in a GETNEXT          --
-- Instance is N.1.A.A.A.A where A's are IP address --
instance[0] = data->ipNetToMediaIfIndex;
instance[1] = 1;
for (i = 0; i < 4; i++) {
instance[i+2]=((unsigned char *)(&data->ipNetToMediaNetAddress))[i];
}
instance2oid(&vb->name, object, instance, 6);
 

戻り値は次のとおりです。

NULL

エラーが発生しました。 それ以外の場合は,OID 構造体のポインタ (最初の引数) が返されます。

6.3.3.8    oid2instance ルーチン

oid2instance ルーチンは,OID 構造体からインスタンス値を取り出し,それらを指定した整数配列にコピーします。 その後,配列内の要素数を返します。 インスタンスは,MIB 変数を識別する要素以外の OID の要素です。 それらは,MIB 値の特定のインスタンスを識別するためのインデックスとして使用されます。

OID 構造体が予想より多くの要素を含んでいる場合は (max_len パラメータで指定した値より大きい場合),この関数は max_len で指定した要素数だけをコピーし,コピーした要素の総数を返します。

構文は次のとおりです。

int oid2instance(
        OID *oid,
        OBJECT *obj,
        unsigned int *instance,
        int max_len );

引数は次のとおりです。

oid

インスタンスあるいはインスタンスの一部が含まれている OID 構造体へのポインタ。

obj

MIB 変数に対するオブジェクト・テーブル・エントリへのポインタ。

instance

インデックスが置かれる符号なし整数配列へのポインタ。

max_len

インスタンス配列で使用できる要素の数。

#include <esnmp.h>
OID         *incoming = &method->varbind->name;
OBJECT      *object   = method->object;
int         instLength;
unsigned int instance[6];
 
-- in a GET operation --
-- Expected Instance is N.1.A.A.A.A where A's are IP address --
instLength = oid2instance(incoming, object, instance, 6);
if (instLength != 6)
    return ESNMP_MTHD_noSuchInstance;
 

Ninstance[0],IP アドレスは instance[2]instance[3]instance[4] および instance[5] になります。

戻り値は次のとおりです。

6.3.3.9    inst2ip ルーチン

inst2ip ルーチンは,OID インスタンスから得られた IP アドレスを返します。 Get および Set 操作のインスタンスの評価には,EXACT モードを使用します。 GetNext および GetBulk 操作には,NEXT モードを使用します。 NEXT モードを使用する場合,このルーチンのロジックは,一致するデータあるいはそれより大きいデータでデータ探索を実行すると想定します。

構文は次のとおりです。

int inst2ip(
        unsigned int *inst,
        int length,
        unsigned int *ipAddr,
        int exact,
        int carry );

引数は次のとおりです。

inst

IP アドレスへ変換するために oid2instance ルーチンによって返されるインスタンス番号を含む unsigned int の配列へのポインタ。

各要素は 0 〜 255 の範囲にあります。 EXACT モードを使用すると,要素が範囲外の場合 1 を返します。 NEXT モードを使用すると,255 より大きな値は要素がオーバフローする原因となります。 0 にセットされ,次に重要な要素が増分されると,辞書的に次に来る ipAddress と同等な値を返します。

length

インスタンス配列の要素数です。 4 つ目以降のインスタンスは無視されます。 長さが 4 より小さい場合,足りない値には 0 が使用されます。 長さが負の場合,ipAddr の値は 0 です。 Get など正確な照合のためには,正確に 4 つの要素でなければなりません。

ipAddr

IP アドレス値を返す場所へのポインタです。 ネットワーク・バイト順で最も顕著な要素が最初にきます。

exact

TRUE あるいは FALSE のどちらかです。

TRUE の場合 EXACT を使用します。 要素が 255 より大きい場合,あるいは正確に 4 つの要素がない場合は,1 を返します。 引数 carry は無視されます。

FALSE の場合 NEXT を使用します。 carry が設定されていて長さが 4 以上ある場合は,辞書的に次にくる IP アドレスが返されます。 要素数が 4 より小さい場合,足りない値には 0 が使用されます。 いずれかの要素が 255 より大きい場合,0 が使用され次の要素が増加します。

carry

NEXT で IP アドレスを追加するキャリィです。 次の IP アドレスを調べる場合は 1 を渡します。 それ以外は 0 を渡します。 4 より小さい長さはキャリィをキャンセルします。

次に示すのは,inst2ip ルーチンの例です。

次の例では,EXACT で,インスタンスを Get のための IP アドレスに変換します。

#include <esnmp.h>
OID         *incoming = &method->varbind->name;
OBJECT      *object   = method->object;
int instLength;
unsigned int instance[6];
unsigned int ip_addr;
int          iface;
 
-- The instance is N.1.A.A.A.A where A.A.A.A is the IP address--
instLength = oid2instance(incoming, object, instance, 6);
if (instLength == 6 && !inst2ip(&instance[2], 4, &ip_addr, TRUE,0)) {
    iface = (int) instance[0];
}
else
   return ESNMP_MTHD_noSuchInstance;
 

次の例は,キーが 1 つしかないか,または ipAddr 値がキーの一番重要でない部分の場合の GetNext オペレーションを示しています。 これは NEXT であるため,carry 値に 1 が渡されます。

#include <esnmp.h>
OID         *incoming = &method->varbind->name;
OBJECT      *object   = method->object;
int instLength;
unsigned int instance[6];
unsigned int ip_addr;
int          iface;
 
-- The instance is N.1.A.A.A.A where A.A.A.A is the IP address--
instLength = oid2instance(incoming, object, instance, 6);
iface = (instLength < 1) ? 0 :(int) instance[0];
 
iface += inst2ip(&instance[2], instLength - 2, &ip_addr, FALSE, 1);
 

次の例では,検索キーに複数の部分があり,GetNext オペレーションを行っている場合は,検索キーについて次にありそうな値を見つけて,カスケード式に「greater-than」または「equal-to」検索をします。

OID のインスタンス部分で N.A.A.A.A.B.B.B.B として表現される 1 つの数と 2 つの ipAddr 値からなる検索キーがある場合は (N は 1 つの値を持つ整数,A.A.A.A は 1 つの IP アドレス,B.B.B.B は 2 番目の IP アドレスとし,すべて指定された場合の長さが 9 になる),キーの一番重要でない部分 (B.B.B.B の部分) を変更することによって検索を開始します。 inst2ip ルーチンを呼び出して,キャリィに 1 を渡し,長さに (length-5) を渡すことによってこれを行います。

B.B.B.B 部分の変換でキャリィが生成された場合 (1 が返される) は,それをキーの次に重要な部分に渡します。

したがって,inst2ip ルーチンを呼び出し,B.B.B.B 部分の変換から返されたキャリィおよび長さに (length-1) を渡すことにより,A.A.A.A 部分を変換します。 最も重要な要素である N は数です。 したがって,A.A.A.A 変換から返されたキャリィをその数に加算します。 それもオーバフローした場合,それは有効な検索キーではありません。

#include <esnmp.h>
OID         *incoming = &method->varbind->name;
OBJECT      *object   = method->object;
int instLength;
unsigned int instance[9];
unsigned int ip_addrA;
unsigned int ip_addrB;
int          iface;
int 	     carry;
 
-- The instance is N.A.A.A.A.B.B.B.B --
instLength = oid2instance(incoming, object, instance, 9);
iface = (instLength < 1) ? 0 :(int) instance[0];
carry = inst2ip(&instance[5],instLength - 5,&ip_addrB,FALSE,1);
carry = inst2ip(&instance[1],instLength - 1,&ip_addrA,FALSE,carry);
iface += carry;
if (iface > carry) {
-- a carry caused an overflow in the most significant element
  return ESNMP_MTHD_noSuchInstance;
}
 
 

戻り値は次のとおりです。

6.3.3.10    cmp_oid ルーチン

cmp_oid ルーチンは 2 つの OID 構造体を比較します。 このルーチンは,要素 0 から各要素ごとに比較を行います。 他の要素がすべて等しければ,最も小さな要素の OID 構造体がより小さいと考えられます。

構文は次のとおりです。

int cmp_oid(
        OID *q,
        OID *p );

戻り値は次のとおりです。

6.3.3.11    cmp_oid_prefix ルーチン

cmp_oid_prefix ルーチンは,プレフィックスに対して OID 構造体を比較します。 プレフィックスは,おそらくオブジェクト・テーブル内のオブジェクトの OID です。 プレフィックスを越える要素はインスタンス情報です。

このルーチンは,要素 0 から各要素ごとに比較を行います。 プレフィックス OID のすべての要素が OID q 構造体の対応する要素と正確に一致する場合は,OID q 構造体に別の要素が含まれていても等しいと考えられます。 最初の一致しない要素が大きければ,OID q 構造体は OID プレフィックスより大きいと考えられます。 最初の一致しない要素が小さければ,OID q はプレフィックスより小さいと考えられます。

構文は次のとおりです。

int cmp_oid_prefix(
        OID *q,
        OID *prefix );

cmp_oid_prefix ルーチンの例を次に示します。

#include <esnmp.h>
OID *q;
OBJECT *object;
if (cmp_oid_prefix(q, &object->oid) == 0)
   printf("matches prefix\n");
 

戻り値は次のとおりです。

6.3.3.12    clone_oid ルーチン

clone_oid ルーチンは OID 構造体のコピーを作成します。

このルーチンは要素のバッファを動的に割り当て,そのポインタを渡される OID 構造体に挿入します。

このルーチンを使うには,コピーされる古い OID 構造体へのポインタとコピーされた OID 値を受け取る新しい OID 構造体へのポインタを渡します。

このバッファの解放は呼び出し元のプログラムもしくはモジュールの責任で行われます。

新しい OID 構造体によってポイントされる以前の要素のバッファは解放され,動的に割り当てられる新しいバッファへのポインタが挿入されます。 解放できる要素バッファを含んでいない場合は,OID 構造体を 0 で初期化します。

このルーチンは OID 構造体を割り当てません。

古い OID 構造体が NULL であるか,要素バッファへの NULL ポインタを含んでいる場合は,{0.0} の新しい OID が生成されます。

構文は次のとおりです。

OID *clone_oid(
        OID *new,
        OID *oid );

引数は次のとおりです。

new

コピーを受け取る OID 構造体へのポインタです。

old

データを入手する OID 構造体のポインタです。

clone_oid ルーチンの例を次に示します。

#include <esnmp.h>
OID oid1;
OID oid2;
:
: assume oid1 gets assigned a value
:
memset(&oid2, 0, sizeof(OID));
if (clone_oid(&oid2, &oid1) == NULL)
    ESNMP_LOG((WARNING, "It did not work\n"));
 

戻り値は次のとおりです。

NULL

エラーが生じました。 そうでない場合は新しい OID へのポインタ (最初の引数) が返されます。

6.3.3.13    free_oid ルーチン

free_oid ルーチンは,OID 構造体の要素バッファを解放します。

oid->elements フィールドによってポイントされるバッファを解放する場合,そのフィールドと oid->nelem フィールドをゼロにします。

このルーチンは OID 構造体自身の割り当て解除は行いません。 要素バッファの割り当て解除のみを行います。

構文は次のとおりです。

void free_oid(
        OID *oid );

free_oid ルーチンの例を次に示します。

#include <esnmp.h>
OID oid;
:
: assume oid was assigned a value (perhaps with clone_oid()
: and we are now finished with it.
:
free_oid(&oid);
 

6.3.3.14    clone_buf ルーチン

clone_buf ルーチンは,動的に割り当てられた領域のバッファのコピーを作成します。 1 つの特別なバイトが最後に割り当てられ,\0 が埋め込まれます。 len パラメータが 0 より小さい場合は,複製バッファ長は 0 に設定されます。 ルーチンは,malloc エラーがない限り常にバッファ・ポインタを返します。

割り当てたバッファの解放は呼び出し元の責任で行われます。

構文は次のとおりです。

char *clone_buf(
        char *str,
        int len );

引数は次のとおりです。

str

コピーを作成したバッファへのポインタ。

len

コピーするバイト数。

clone_buf ルーチンの例を次に示します。

#include <esnmp.h>
char *str = "something nice";
char *copy;
copy = clone_buf(str, strlen(str));
 

戻り値は次のとおりです。

NULL

malloc エラーが生じました。 それ以外の場合は,オリジナル・バッファのコピーを含む割り当てバッファへのポインタが返されます。

6.3.3.15    mem2oct ルーチン

mem2oct ルーチンは文字列 (バッファおよび長さ) を OCT 構造体に変換します。

このルーチンは新しいバッファを動的に割り当て,指定されたデータをそこにコピーし,OID 構造体を新しいバッファのアドレスと長さで更新します。

このバッファの解放は呼び出し元の責任で行われます。

このルーチンは OCT 構造体を割り当てません。 以前に割り当てた OCT 構造体でポイントしているデータの解放は行いません。

構文は次のとおりです。

OCT * mem2oct(
        OCT *new,
        char *buffer,
        int len );

mem2oct ルーチンの例を次に示します。

#include <esnmp.h>
char buffer;
int len;
OCT abc;
:
: buffer and len are initialized to something
:
memset(&abc, 0, sizeof(OCT));
if (mem2oct(&abc, buffer, len) == NULL)
    ESNMP_LOG((WARNING,"It did not work...\n"));
 

戻り値は次のとおりです。

NULL

エラーが生じました。 それ以外の場合は,OCT 構造体へのポインタ (最初の引数) が返されます。

6.3.3.16    cmp_oct ルーチン

cmp_oct は 2 つのオクテット文字列を比較します。 2 つのオクテット文字列は,バイトごとに最も短いオクテット文字列の長さを比較されます。 すべてのバイトが等しい場合は,長さが比較されます。 ヌル・ポインタのオクテットは,長さ0 のオクテットと同じであると考えられます。

構文は次のとおりです。

int cmp_oct(
        OCT *oct1,
        OCT *oct2 );

cmp_oct ルーチンの例を次に示します。

#include <esnmp.h>
OCT abc, efg;
:
: abc and efg are initialized to something
:
if (cmp_oct(&abc, &efg) > 0)
    ESNMP_LOG((WARNING,"octet abc is larger than efg...\n"));

戻り値は次のとおりです。

6.3.3.17    clone_oct ルーチン

clone_oct ルーチンは,OCT 構造体のコピーを作成します。

呼び出し元は,コピーされる古い OCT 構造体のへのポインタとコピーされた OCT 構造体の値を受け取る新しい OCT 構造体へのポインタを渡します。

このルーチンはバッファを動的に割り当て,バッファのアドレスと長さで新しい OCT 構造体を更新します。

この割り当てられたバッファの解放は呼び出し元の責任で行われます。

新しい OID 構造体によってポイントされる以前のバッファは解放され,動的に割り当てられる新しいバッファへのポインタが挿入されます。 解放できる要素バッファを含んでいない場合は,新しい OCT 構造体を 0 で初期化します。

このルーチンは OCT 構造体を割り当てません。 OCT 構造体によってポイントされる要素バッファのみを割り当てます。

構文は次のとおりです。

OCT *clone_oct(
        OCT *new,
        OCT *old );

引数は次のとおりです。

new

コピーを受け取る OCT 構造体へのポインタです。

old

データを入手する OCT 構造体のポインタです。

clone_oct ルーチンの例を次に示します。

#include <esnmp.h>
OCT octet1;
OCT octet2;
:
: assume octet1 gets assigned a value
:
memset(&octet2, 0, sizeof(OCT));
if (clone_oct(&octet2, &octet1) == NULL)
    ESNMP_LOG((WARNING, "It did not work\n"));
 

戻り値は次のとおりです。

NULL

エラーが生じました。 それ以外の場合は,OCT 構造体へのポインタ (最初の引数) が返されます。

6.3.3.18    free_oct ルーチン

free_oct ルーチンは OCT 構造体のバッファを解放します。

OCT 構造体がポイントする動的に割り当てられたバッファを解放し,OCT 構造体のポインタと長さフィールドを 0 にします。 OCT 構造体がすでに NULL の場合は何もしません。 OCT 構造体に接続されたバッファがすでに NULL の場合は,OCT 構造体の length フィールドを 0 にします。

このルーチンは OCT 構造体の割り当て解除は行わず,ポイントするバッファの割り当て解除のみを行います。

構文は次のとおりです。

void free_oct(
        OCT *oct );

free_oct ルーチンの例を次に示します。

#include <esnmp.h>
OCT octet;
:
: assume octet was assigned a value (perhaps with clone_oct()
: and we are now finished with it.
:
free_oct(&octet);
 

6.3.3.19    free_varbind_data ルーチン

free_varbind_data ルーチンは,VARBIND 構造体に動的に割り当てられたフィールドを解放します。

このルーチンは,free_oid (vb->name) 操作を行います。 vb->type フィールドを指定すると,free_out あるいは free_oid ルーチンのどちらかを使用して vb->value データを解放します。

VARBIND 構造体自身の割り当て解除は行わず,それがポイントする名前バッファおよびデータ・バッファのみを割り当て解除します。

構文は次のとおりです。

void free_varbind_data(
        VARBIND *vb );

free_varbind_data ルーチンの例を次に示します。

#include <esnmp.h>
VARBIND *vb;
:
: assume oid and data are declared and
: assigned appropriate values
:
vb = (VARBIND*)malloc(sizeof(VARBIND));
clone_oid(&vb->name, oid);
clone_oct(&vb->value.oct, data);
:
: some processing that uses vb occurs here
:
free_varbind_data(vb);
free(vb);
 

6.3.3.20    set_debug_level ルーチン

set_debug_level ルーチンは,どのようなログ・メッセージが生成されたかを検出するロギング・レベルを設定します。 プログラムもしくはモジュールが,実行時オプションに応じて,プログラムの初期化時にこのルーチンを呼び出します。 このルーチンが呼び出されていない場合,省略時の設定として WARNING および ERROR メッセージが stdout に送られます。

構文は次のとおりです。

void set_debug_level(
        int stat,
        LOG_CALLBACK_ROUTINE callback_routine );

引数は次のとおりです.

stat

ログ・レベル。 次の値が,個別もしくは組み合わせで設定されます。

ERROR

エラーが発生し,再起動を必要とする場合。

WARNING

パケットを処理できない場合。 ERROR も含む。

TRACE

すべてのパケットをトレースする場合。 ERROR および WARNING を含む。

DAEMON_LOG

標準出力でなく syslog へ出力が送られる。

EXTERN_LOG

ログ・メッセージを出力するためにコールバック関数が呼び出される。 このビットが設定されている場合は,2 つ目の引数としてユーザが提供する外部コールバック関数のポインタを指定する必要がある。 DAEMON_LOG および EXTERN_LOG が指定されていない場合は,標準出力へ送られる。

callback_routine

ユーザ定義の外部コールバック関数。 たとえば,次のように定義します。

void callback_function(
        int level,
        char *message );

level には,ERRORWARNING あるいは TRACE を指定します。 EXTERN_LOG ビットが stat に設定されている場合,ESNMP_LOG マクロが実行されると callback 関数が呼び出され,ログ・レベルは生成するログ・メッセージを指定します。

この機能によって,eSNMP ライブラリ関数がログ・メッセージを出力する場所を制御できます。 EXTERN_LOG ビットが設定されていない場合は,コールバック関数の引数として NULL ポインタが渡されます。

set_debug_level ルーチンの例を次に示します。

#include <esnmp.h>
extern void log_handler(int level, char *message);
 
if (daemonize)
    set_debug_level(EXTERN_LOG | WARNING, log_handler);
else
    set_debug_level(TRACE, NULL);
 

6.3.3.21    is_debug_level ルーチン

is_debug_level ルーチンは,指定したレベルが設定されているかどうかロギングのレベルをテストします。 次のようにレベルをテストできます。

構文は次のとおりです。

int is_debug_level(
        int type );

戻り値は次のとおりです。

TRUE

要求したレベルが設定されており ESNMP_LOG が出力を生成します。 あるいは指定した場所へ出力されます。

FALSE

ロギング・レベルが設定されていません。

is_debug_level ルーチンの例を次に示します。

#include <esnmp.h>
 
if (is_debug_level(TRACE))
    dump_packet();
 

6.3.3.22    ESNMP_LOG ルーチン

ESNMP_LOG ルーチンは,<esnmp.h> ヘッダファイルで定義されているエラー宣言 C マクロです。 取得できる情報を集め,ログに送ります。 DAEMON_LOG が設定されている場合,ログ・メッセージはデーモン・ログへ送られます。 EXTERN_LOG が設定されている場合,ログ・メッセージは callback 関数へ送られます。 それ以外の場合は,標準出力へ出力されます。

注意

esnmp_log ルーチンは,ESNMP_LOG マクロを使用して呼び出されます。 ESNMP_LOG マクロは,テキスト部分をフォーマットするのにヘルパー・ルーチン esnmp_logs を使用します。 これらの関数は ESNMP_LOG マクロなしで使用しないでください。

#define ESNMP_LOG(level, x) if (is_debug_level(level)) { \
         esnmp_log(level, esnmp_logs x, __LINE__, __FILE__);}
 

x には次の構文で文字列を指定します。

text - format, arguments, ....

たとえば printf 文を指定します。

level

次のいずれかを指定します。

ERROR

エラー状態を宣言します。

WARNING

警告を宣言します。

TRACE

トレースがアクティブな場合ログ・ファイルを挿入します。

構文は次のとおりです。

ESNMP_LOG(level,(format,...))

ESNMP_LOG ルーチンの例を次に示します。

#include <esnmp.h>
ESNMP_LOG( ERROR, ("Cannot open file %s\n", file));