RTLで設計されたTCP/IPなIPコアのデバッグをかねて,簡単なHTTPサーバを書き始めました.最終的には,FPGA開発において手軽にHTTPなデバッグポートが提供できるようにすること,です.たとえば,Webアプリケーションチックに,addressとlengthを与えるとDDR3上のイメージをダウンロードできる,とか,便利かもしれません.
…というのを念頭におきつつ,準備として,TCPでデータがやってきたらTestって返すという単純なサーバーの実装から.
なお,弊社のWebサーバーfreeoceanは,この記事の内容とは全然違った設計がされていて性能も段違いなのです.
e7TCP/IP IPコアの概要
TCP/IPのIPコアe7TCPIPは,次の図のように2本のTCP送受信用のUPLポートを備えています.プロトコル処理(アドレスの解決とか再送制御)とセッションの管理は,コアが内部でハンドリングしてくれますので,ユーザロジックでは,TCPのペイロードだけをUPLポートを介してやり取りします.
この,2本のUPLポートは,それぞれ異なるポート番号のパケットを受信できる状態で待機します.ネットワークプログラミング的に見れば,二つのソケットをオープンしてListenしている状態,に相当します.
今回実装するサーバー(のようなもの)について
今回実装するのは,TCPでクライアントから何かデータが届いたら(コアから有効なUPLパケットが出力されたら),HTTP/1.1なヘッダ付きのデータをそのクライアントに返す,という単純なものです.
コードはこんな感じ.SynthesijerでVHDLに変換します.
処理のカーネル部分はrun()メソッドです.受信パケットがくるまで待って(3行目のwhileループ)→ヘッダを用意して(14〜17行目)→ペイロードを用意して(21〜24行目)→UPLで送信(32-34行目)というシンプルなものです.
private void run(){ outport.kick = false; while(inport.ready == false){;} int ip_src = inport.data[0]; int ip_dest = inport.data[1]; int port_src_dest = inport.data[2]; int length = inport.data[3] & 0x0000FFFF; if(length == 0){ inport.done = true; inport.done = false; return; // should be fin, nothing to do. } // header for(int i = 0; i < resp.length; i++){ int v = resp.data[i]; outport.data[i+4] = v; } outport.data[8+4] = content_length_field; // data int offset = resp.length; for(int i = 0; i < content_words; i++){ int v = data[i]; outport.data[i+4+offset] = v; } outport.data[0] = ip_src; outport.data[1] = ip_dest; outport.data[2] = port_src_dest; outport.data[3] = (resp.length + content_words) << 2; outport.send_length = 4 + resp.length + content_words; inport.done = true; inport.done = false; outport.kick = true; outport.kick = false; }
レスポンス用のヘッダはHttpResponseHeaderのインスタンスから取り出していますが,実際には,これはROMになっています.
こんなコード でJavaコードにはROMなI/Fをみせつつ,実態は,こんな感じのHDLなROMコードと組み合わせて合成されます.
ROMコードは手で書いたわけではなくて,こんなJavaコードで生成しています.
コンテンツデータは,とりあえず,initメソッドでTestって表示するだけのHTMLを静的に作っています.
IPコアと組み合わせて合成すると,FPGAがtelnetを受け付けるようになるので,
と,リクエストに対してデータが帰ってくることを確認できます.まあ,リクエストのパースとかしてないので,何入力してもデータが帰ってくるのですが…;-)
当たり前ですが,Webブラウザ,たとえばSafariでアクセスするとTestという文字が表示されます.
次は
とりあえず,HTTPサーバー的なものの実装ができそうだということが確認できました.もちろん,与えられたパスに従ったコンテンツを出力する,というのが,次のステップですね.簡単なリクエストパーサを書いてみようと思います.
コメント