前置き
この記事は旧サイトの2023.9.16投稿の記事内容のリポストです。
はじまり
Twitterでこんなツイートが流れてきました。
資料とコードをみてみると、 C言語で簡易的な TCP/IP プロトコルスタックを自作してみよう!という内容でした。TCP/IP って普段何気なく使ってはいるもののふわっとした知識しかなかったのでこれを機にちょっとやってみようかな、と。以降では、実施してみた感想と、そのあとに microps を VSCode DevContainer で動作するために行った環境構築、実施中に出会った環境構築不備?のエラー(※暫定対処しかできていない…)をまとめておきます。
資料
Klab Expert Camp (Google Drive) microps (Github)
感想(完走)
ネットワークのデバイスの管理からはじまり、Ether, ip, udp, tcp, arp と様々なプロトコルの実装で、普段何気なく使っている通信がこんな面倒なことをしてるんだなと改めて感じることが出来ました。特に最後の方のTCPは3wayハンドシェイクなど、ふわっと知ってはいましたが実際やると難しすぎて・・・。(シーケンス番号やら送信して受信しての流れが追い切れない(汗)。
TCP/IPプロトコル入門からは外れてしまうところですが、いわゆる連結リストやメモリの動的確保・解放、関数ポインタ、void * を用いた共通化など、なるほど実際こうやって使うんだというようなところも満載で、C言語の理解を深めるのにも良い教材と感じました。
正直理解を諦めて先に進んでしまったようなとこだと、シグナルやバリア同期など並行プログラミングとかLinuxのシグナルとかを知らないので厳しかった。またmicrps では util.c などに色々な便利関数群が作ってあって簡単にキューの操作やバイトオーダーの変換ができるようになっていました。ここもとりあえず util 頼りでした。
あとは本記事の最後に記載していますが、何故かVSCode で InteliSence がうまく効かずにとりあえず対処で済ませたりしたとこがあるのでそのあたりの原因も確認したいですね。
本来は5日間でこれをやりきっている方たちがいるようなのですが、1か月くらいかかりました。おともには前に興味がでて買ったはいいものの数ページ読んで積んでいた「これ1冊で丸わかり 完全図解ネットワークプロトコル入門」を横に携えてのぞみました。ただ踏み込んだとこだとやっぱり足りなかったですね。UDPのとことか。
総じていい内容でした。
環境構築(Day1以前)
最終的な環境はこちらhttps://github.com/AlaAlba/microps/tree/work/.devcontainer
以下の要件に沿って環境構築しました。
– Ubuntu 20.04 を推奨 – 実機or仮想環境どちらでもOK(WindowsはWSL2で動作確認済) – Dockerで構築する場合には –privileged または –cap-add=NET_ADMIN が必要 – 必要パッケージ(Ubuntuの場合) – build-essential – git – iproute2 – iputils-ping – netcat-openbsd
使ったことなかったのですが、これを機会にということで、VSCode Devcontainer を利用しています。 * Windows10 * Docker * VSCode DevContainer
microps を clone したフォルダに、 .devcontainer
フォルダを作成し、配下に devcontaienr.json
, docker-compose.yml
, Dockerfile
を作成。
(参考)Get started with development Containers in Visual Studio Code Visual Studio Codeで使えるリモート環境のdevcontainerが意外と便利そうだったのでまとめ Docker Compose な開発環境にちょい足し3分で作るVSCode devcontainer VSCode Devcontainer 放浪記 Add non-root user to a container 【Rootless】VSCodeのDocker環境をRoot以外のユーザで実行する | ぺんぎんや How to Set Docker Environment Variables {ARG and ENV}
注意点
docker-compose.yml
の devices
Tutorial で sudo ip tuntap add mode tap user $USER name tap0
というコマンドが出てきますが、本箇所を追加しないと、 open: No such file or directory
というエラーが表示されました。Docker Compose な開発環境にちょい足し3分で作るVSCode devcontainer networking – ip tuntap add gives “open: No such file or directory” – Ask Ubuntu によると、Docker は tun/tap デバイスにマッピングしないため、手動で行う必要があるそうです。
–device /dev/net/tun:/dev/net/tun
Dockerfile Userの設定
Tutorial で $USER
と指定している箇所があるが、devcontainer はデフォルトでは root ユーザーとなるらしく、また $USER
は環境変数に定義されていません。そのため、# Create the user
以降の箇所でユーザーを dev-user
として作成し、最後に ENV USER=$USERNAME
で環境変数を設定しています。
作業録
P22~
以下の手順でコミットが見つかりませんでした。
git checkout bdbf73f -b work
原因は、fork したときには main ブランチしかとってきていなかったことです。以下の手順で、 bdbf73f のコミットがされている別ブランチを取得する必要がありました。
# オリジナルのリポジトリを upstrem としてリモートリポジトリに追加
git remote add upstream https://github.com/pandax381/microps.git
# フェッチ
git fetch upstream
# ブランチをチェックすると remotes/upstream/* が追加されている
git checkout -a
# * master
# remotes/origin/HEAD -> origin/master
# remotes/origin/master
# remotes/upstream/book1.0
# remotes/upstream/kec3
# remotes/upstream/kec5
# remotes/upstream/master
# remotes/upstream/rebuild
VSCode で net.c によくわからないエラー
STEP1 では net.c
を新規追加するのですが、1行目のインクルードで、「コマンドラインエラー C/C++(1027) 指定されている言語モードは互換性がありません」というエラーが表示されていました。
よくわからず無視して進めていたんですが、このせいでコードの補完が全く効いていないという問題が発生してしまったため、解決方法を記載しておきます。
どうやら今開発環境は VSCode を利用しているのですが、 InteliSense が Makefile Tools によって効いているのが原因のようでした。
拡張機能は、ファイル内に Makefile が見つかるとアクティブになります${workspaceFolder}
よって、P41 の Makefile の修正を行えば解決します。今後の作業では先に Makefile を修正することを心がければよさそうです。
Makefile 使ったことないのでわかりませんでしたが、ここでビルド対象に含めないとソースファイルとして認識してくれないようです。
暫定対処しちゃったトコ(VSCodeの設定がオカシイ?)
microps を ドキュメント通りに進めるにあたり何故か make はできるんですが、VSCode上は Intelisence でエラー表記になるものがいくつか・・・。VSCodeのC言語用の設定、もしくはMakeFile用の設定がうまくいってない気がしますね・・・。とりあえずは以下の通りの定義追加などを行うとエラーもなくなり、補完も効くようになりました。しかし原因ははっきりしていません。
STEP2 : 識別子 “pthread_barrier_t” が定義されていませんC/C++(20)
#define _XOPEN_SOURCE 600 /* Or higher */
の定義をインクルード前で定義するとうまくいきましたが、オリジナルの microps ではそんな定義はされていないので、なぜ intelisence がオカシイのかがわかりません・・・。なお、VSCode上、問題として表示されているが、このままでも make は可能でした。c – unknown type name “pthread_barrier_t” – Stack Overflow
STEP12 : ifreq でエラー
こっちは Intelisence で使用する言語標準のバージョンを変更すれば解消しました。 デフォルトではC**になっているので gnu23 などに変更。
STEP14, 16 : timercmp や timersub がintelisenceが効かない
sys/time.h
みるとコンパイルでオフになってたので __USE_MISC
を追加したら一応効くようになりました。謎です。
#ifndef __USE_MISC
#define __USE_MISC /* TODO: 暫定 timercmp用 intelisenceが効かない */
#endif
#include <sys/time.h>
STEP26 timercmp
これも同じように VSCode の Intelisence がエラー表示に。make はそのままでも通りました。暫定対処としては STEP14, 16 と同じように上記のインクルードと定義を追加すればエラー表記も取れました。ただこちらに関しては、 tcp.c はそもそも元々は sys/time.h すらインクルードされておらず、なぜこれで make 通るんだろう?ってなりました。
投稿日:2023年9月16日