Linuxカーネルに関する技術情報を集めていくプロジェクトです。現在、Linuxカーネル2.6解読室の第2章までを公開中。
まず、プロセス側の動きから説明する。
アプリケーションからのデータ受信処理要求は、socketレイヤを経由しinet_recvmsg関数を呼び出す(struct proto_ops inet_stream_opsインターフェイステーブル経由)ことにより実現される。inet_recvmsg関数は、即tcp_recvmsg関数を呼び出す。(struct proto tcp_protインターフェイステーブル経由)。
tcp_recvmsg関数は、ソケットのreceive_queueにリンクされているパケットのデータをユーザ空間にコピーし、パケットを解放する。もしreceive_queueにデータが無い場合は、パケット到着を待つ。
tcp_recvmsg関数は、ソケットのreceive_queueの先頭から順にパケット内を参照(skb_peek関数)し、指定されたサイズ分だけパケット内のデータをユーザ空間にコピー(memcpy_toiovec関数)する。処理は複数のパケットに跨ることもある。(この時点ではreceive_queueから外さない)
目的としたサイズのデータの読み込みを終了すると、完全にデータを読みだされたパケットの後処理を行う(cleanup_rbuf関数)。cleanup_rbuf関数は、ソケットのreceive_queueから不必要になったパケットを外し、パケットを捨てる(tcp_eat_skb関数)。またtcp_read_wakeup関数により、受信windowサイズ大きくなったことを送信相手に即通知する(tcp_send_ack関数)。これによりフロー制御で停止していた送信処理(相手からこちら)が即再開される。
もし目的としたサイズを満たすデータがreceive_queueにつながっているパケットだけでは不十分な場合、パケット到着待ちの状態に入る(tcp_data_wait関数)。(指定されたオプションにより、期待されたサイズ以下でも処理を完了させたり、 データが全くない場合はエラーにすることもある)
しばらくしてパケット到着すると、ソケットで待ちに入っているプロセスを起床する。起床したプロセスはtcp_recvmsg処理を再開する。
次に、割り込み側のパケット受信処理に関して説明する。
受信パケットはtcp_v4_rcv関数経由でTCPプロトコルスタックに送られる。tcp_v4_rcv関数は、受信パケットの送信ポート番号(TCPヘッダのdestフィールド)を元に、TCP port番号キャッシュを検索し、そのポートにbindされているソケット(またはそれに相当するもの)をわりだす(tcp_v4_lookup関数)。
わりだした結果、それがTCP_TIME_WAIT状態のtcp_tw_bucket構造体(ソケットに相当する)であった場合は、tcp_timewait_state_process関数を呼び出す。この先の処理に関してはコネクションの切断処理の章で説明する。
TCP_TIME_WAIT状態以外の場合はtcp_v4_do_rcv関数を呼び出す。tcp_v4_do_rcv関数は、受信するソケットの状態により呼び出す関数を切り替える。TCP_ESTABLISHED状態のソケットであればtcp_rcv_established関数を呼び出す。TCP_LISTEN状態のソケットであればtcp_v4_hnd_req関数を呼び出す。それ以外の状態のソケットであればtcp_rcv_state_process関数を呼び出す。
tcp_v4_hdn_req関数、tcp_rcv_state_process関数にの処理に関しては後の章(コネクションの確立と切断)で説明する。ここではコネクション確立状態における受信処理tcp_rcv_established関数に関して説明する。
受信処理tcp_rcv_established関数は、パケットを受け取ると以下の順序で処理を行う。
ソケットのdata_ready()メソッド(TCP/IPではsock_def_readableという 関数が登録されている)を呼び出し、このソケットでrecv待ちに 入っているプロセスの起床を行う。(SIGIO発生要求があれば SIGIOシグナルを発生させる)
(NIS)HirokazuTakahashi
2000年12月09日 (土) 23時55分06秒 JST1
[PageInfo]
LastUpdate: 2008-08-27 14:18:56, ModifiedBy: hiromichi-m
[Permissions]
view:all, edit:login users, delete/config:members