2009-05-05 17 views
1

私はちょうどこのような機能を持っている:ネットリンクを使用してカーネル空間からのメッセージを受信するために使用されるLinuxソケットプログラミングのデバッグ?

static int 
rcv_kern(int sock, void *buf, int len, struct sockaddr *addr, 
    socklen_t *addrlen) 
{ 
    struct timeval timeout = {1, 0}; 
    fd_set set; 
    int status; 

    FD_SET(sock, &set); 
    if ((status = select(sock + 1, &set, NULL, NULL, &timeout)) == 0) { 
     FD_ZERO(&set); 
     fprintf(stderr, 
      "timeout while receiving answer from kernel\n"); 
     exit(1); 
    } else if (status == -1) { 
     FD_ZERO(&set); 
     perror("recvfrom failed"); 
     exit(1); 
    } 
    FD_ZERO(&set); 
    return recvfrom(sock, buf, len, 0, addr, addrlen); 
} 

を。しかし、私がそれを実行すると、結果は常に "ソースコードからの応答をカーネルから受け取っている間にタイムアウトする"というメッセージが表示されます。これは、 "select"メソッドが常に "0"を返すという理由によるものです。私はその理由を知らないが、誰が私に何か提案をすることができます、ありがとう。

+0

おそらく、ソケットの作成方法に問題がありますか?ソケットにバインドしたのですか? netlink用のソケットを作成するには、ソケット(PF_NETLINK、SOCK_RAW、NETLINK_ROUTE)を使用する必要があります。バインドするには、構造体sockaddr_nlとメンバnl_family = AF_NETLINKを持つアドレスを指定する必要があります。 –

+0

はい、私はあなたが言ったようにしています。 –

+0

まず最初にrecvfromを行い、正常に動作させてください。あなたのソケットが正常に動作していることを確認したら、選択したものを実行してください – shodanex

答えて

1

はタイムアウトに関連していますが、それ以外のfd_setが初期化されていないだろうし、おそらく多くのセットビットを含む、FD_SET(靴下、&セット)の前にFD_ZERO(&セット)する必要はありませ。また、終了する前のFD_ZERO()はかなり無意味です。

+0

あなたが言ったことは理由ではなく、私のコードをあなたの指示に従って変更しましたが、動作しません。 –

0

私はカーネル空間で自分のコードを調べましたが、カーネルが "skb_dequeue(& sk-> sk_receive_queue)"という方法でクライアントからのメッセージを受信できないことを知っています。 私はそれがどうなるかわかりません。

+0

これは答えではありません。あなたの質問に対する編集でなければなりません。 – ffledgling

0

まず、タイムアウトが発生したときにstrerror(errno)(errnoも有効です)を印刷することで、実際のエラーの内容を知ることができます。

errnoがない場合の問題を推測するには、何か読んでも何の保証もありません。 accept(2)を介してソケットを取得したとしても、設定された接続である可能性がありますが、クライアントは書き込みに回っていませんでした。通常、select(2)を1回だけ実行しません。いつでも何らかの理由でタイムアウトが起こる可能性があるので、プログラムが終了するまでselect(2)を呼び出したままにしておく単一のメインループが必要です。

他の可能性のある問題:

  • クライアントが接続することはできません。
  • ソケットを正しくバインドできません。
  • bind(2)を呼び出した後、サーバーのソケットでlisten(2)を呼び出すことを忘れてしまいます。

IPソケットを使用している場合は、Wiresharkを使用してネットワークトラフィックを調べて、クライアントが期待通りの動作をしているかどうかを確認できます。

+0

エラーではありません、タイムアウトです、私はerrnoが設定されるとは思わない – shodanex

4

チャーリー、
物事のカップルは:FD_ISSET()は、ファイルディスクリプタにtrueを返す場合

1)あなたはおそらく、あなたの選択()の呼び出しの周りにループとはONLYのrecvfromを呼び出す必要があります。
2)netlinkソケットで送信している実際のドライバまたはカーネルコードが実際にデータを書き込み/送信していることを確認してください。そうでなければ、関数は1秒でデータを受信しなければタイムアウトします。 (これがタイムアウトを設定したものです)。

一般的なコメントのカップル... Linuxでは、select()システムコールを使用しています。タイムアウトデータ構造体は各呼び出しの後にリセットされるため、コードをループしてselectをループするようにすると、おそらくループ内のすべての反復に対してタイムアウト値をリセットする必要があります。

また、選択がタイムアウトすると、必ずしもエラーであるとは限りません。選択はノンブロッキングコールであることを覚えておいてください。指定されたタイムアウト期間だけソケットを待機して戻ります。あなたが何であってもファイル記述子から読みたいなら...つまり、recv_kern()関数が返すデータがあるまでブロックし、select()を使用しないでください。 recvfrom()をファイル記述子で直接呼び出してください。このようにして、recv_kernel()関数はブロックし、カーネルが送信したデータを読み込んだ後でのみ復帰します。


このコードがどのように使用されているかのコンテキストについて詳しく知ることなく、ここで具体的な助けをするのは難しいです。私は、あなたが書いたカスタムカーネルモジュールが、ユーザー空間にデータを送信していると仮定していますが、正しいですか?
recv_kern()関数をブロック(コードを選択してrecvfrom()を呼び出す)に変更してみてください。この方法は、カーネルドライバが実際にデータをユーザー空間に正しく送信しているかどうかを確認することができます。 recvfrom()でブロックしていても何も戻ってこない場合は、カーネルドライバに問題があるかもしれません。

希望するものがあります。

+1

上記の質問とは無関係に、あなたの答えが私のソケットの問題を助けました。 –

2

あなたはこのような機能を書き換える必要があります。他の誰かが言ったように

static int 
rcv_kern(int sock, void *buf, int len, struct sockaddr *addr, 
    socklen_t *addrlen) 
{ 
    struct timeval timeout = {1, 0}; 
    fd_set set; 
    int status; 

    FD_ZERO(&set); 
    FD_SET(sock, &set); 
    if ((status = select(sock + 1, &set, NULL, NULL, &timeout)) == 0) { 
     fprintf(stderr, 
       "timeout while receiving answer from kernel\n"); 
     exit(1); 
    } else if (status < 0) { 
     perror("recvfrom failed"); 
     exit(1); 
    } 
    if ((status = recvfrom(sock, buf, len, 0, addr, addrlen)) < 0) { 
     perror("recvfrom error"); 
     exit(1); 
    } 
    if (status == 0) { 
     fprintf(stderr, "kernel closed socket\n"); 
     exit(1); 
    } 
    return status; 
} 

を、あなたは選択を呼び出す前にFD_ZEROを呼び出す必要があります。 FD_ZEROへの他の呼び出しは不必要です。また、完全なエラーチェックが必要です。

関連する問題