2017/05/28

[c/c++]lmdb

以前、Caffeを見ていたときにlmdbのデータを見る方法を調べたことがある。
http://hiro99ma.blogspot.com/2015/10/caffelmdb.html

このときは、mdb_dumpというツールでデータを見るだけだった。


そして、Cで書かれているKey-Value StoreなDBがないか探していると、lightning memory-mapped databaseなるものが出てきた。
OpenLDAPプロジェクトで作ってるようなのだが、これがlmdbだったのだ。

Symas Lightning Memory-mapped Database | Symas Corporation

世の中、狭いねぇ。


github(ぎっとはぶ、と読むのだね。私は、じっとはぶ、と読んでて怪訝な顔をされたよ)はこちら。
https://github.com/LMDB/lmdb


makeすると、ライブラリなどが生成されていた。
単独でビルドできるか、別の場所に「lmdb.h, liblmdb.a, mtest.c」だけをコピーした。

$ gcc -o tst mtest.c -L. -llmdb -pthread

うん、ビルドできた。

$ ./tst

あ、あれ、死んでしまう。。。
なんだ、dbを置くディレクトリは自分で作らんといかんのか。

$ mkdir testdb
$ ./tst

結果は分からないが、動いた。



lmdbを見つけるより前に、FineDBというものを見つけていた。
FineDB

これがlmdbをベースにしている、と書いていて、そういえばlmdbって記事にしたことあるな、という経緯でたどり着いたのだった。


FineDBはまだ動かしていないが、フォルダ構成がserver/cliとなっていて、これはこれで面白そうだ。
ただ、4年前が最後のcommitなので、lmdbを参照にしている部分は古いのかもね。

2017/05/27

[c/c++]leveldbをcで使いたかったが、libstdc++が必要だった

いつもsqliteを使っていたので、たまには違うものを使っておこうと思い、leveldbを使ってみることにした。

google/leveldb: LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.


configureなどがないので、makeして、includeディレクトリと、out-staticに入っていたlibleveldb.aを別の場所にコピーして、emnl/leveldb-c-exampleからleveldb_example.cを持ってきた。

$ gcc -I./include -o tst leveldb_example.c -L. -lleveldb -pthread

・・・大量にリンクエラーが出てきた。
deleteがどうのこうのと出ているので、C++のライブラリがいるようだ。
まあ、もとがC++だから、仕方ないか。。。


しかし、snappyとかいうエラーも出ている。
データを圧縮するライブラリらしいが、必須なのか?

Makefileを見ていくと、どうやらbuild_detect_platformというスクリプトで環境をチェックして、設定をbuild_config.mkに作り、それをMakefileが読込んでいるようだ。
どうやら、私が使っている環境ではsnappyをapt-getか何かでインストール済みのようだ(実を言えば、leveldbもインストール済みだった)。
今回は最小構成にしたいので、スクリプトでsnappy検出のところをコメントアウトさせた。


これでもlibstdc++.aみたいなものはいるので、あきらめよう。

$ gcc -I./include -c leveldb_example.c
$ gcc -o tst leveldb_example.o -L. -lleveldb -pthread -lstdc++

動くようだ。


サンプルが、leveldb_put()するときに"value"という文字を書き込んでいるのだが、きっちり5byte分しか書込んでいないので、その後でleveldb_get()したあとにprintf()したときの文字が化けて出力されることがあるようなので、気になる人は\0まで書込むなり、get後に\0を足すなりするとよかろう。

Cだけで書かれたNoSQLというかKVSのライブラリがあると、小さそうでよいのだけどね。

2017/05/26

[linux]msgsnd()のサイズを計算したい

まだやっている、Linuxのメッセージキューの調査。

前回で終わりの予定だったが、msgsnd()のmsgszを自動で計算したくなったのだ。
mtext[SZ_BUF]みたいにサイズが決まっているならやりやすいけど、メッセージキューってデータ構造を問わないので、せっかくなら使うデータをずらずら並べたいところだ。
そうすると、msgszがよくわからなくなってしまう。


試しに、msgszを8192にしたまま、構造体のサイズを小さくしてみた。
うん、やっぱりcoreを吐いてしまう。
msgrcv()だけが死ぬときもあれば、msgsnd()が死んでしまうこともある。
アラインメントによっては、死なないこともありそうだから、サイズはやはり気をつけておきたい。


あれこれ考えたが、これくらいしか思いつかない。

  • 構造体のsizeofから、mtypeの次のメンバーをoffsetof()した値を引く
  • mtypeの次のメンバーを構造体にしてしまう

後者の方がスマートかな?

2017/05/25

[linux]msgsnd()のサイズ確認

前々回の記事だが、タイトルは間違っていないものの、検討結果が間違っていた。
修正したので、以前読まれた方は申し訳ないが、一番下だけでも再確認していただきたい。

[linux]メッセージキューのmsgszは8192を超えてはいかん

msgsnd()のサイズ指定を構造体全体のsizeofでやっていたのだけど、指定するのはmtextの部分だけのようだ、ということだ。



が、すっきりしないので検証を行った。
Xubuntu16.04だ。

https://gist.github.com/hirokuma/5916e918f40bbf82dc5723e42789007c

まず、構造体としてはmtextを8192より256くらい多めに確保する。
送信側はmtextをすべて0x77で初期化し、受信側は0xccで初期化しておく。
そしてmsgsnd()では8192を指定し、受信側のmtextが0x77以外になるポイントを探す。


結果としては、8192、と出力された。
0から始まるので、0~8191までの8192バイトは0x77であることが確認できた。

sizeof(構造体) - sizeof(long)としているサイトがあったので、8192がどこからどこまでなのかが気になっていたのだ。
もしsizeof(long)が開始地点だったら、8188バイトまでしかコピーされていなかったはずだ。
一応offsetof()で調べたが、mtextは8バイト目だった。


よし、これでもう間違えないぞ。

[clang]BUFSIZ

マクロにBUFSIZというものがあったのだが、なんだろうか?
stdio.hに入っていることは分かったのだが・・・。



これは、ファイルが使用するI/Oバッファサイズに関係するようだ。
Man page of SETBUF
setbuf()がBUFSIZを使い、setbuffer()はそのサイズ指定可能版ということか。


printfさせると、BUFSIZは8192だった。
環境や時代で変わる値だと思うが、8KBまではバッファリングされることになる。


Man pageの説明を読むと、意識していないことが書かれていた。

  • バッファリングの種類は3種類ある
    • unbuffered
      • 出力をすぐ書込む
    • block buffered
      • 文字の読み書きはブロック単位で行われる
      • 吐き出すにはfflushなどを使う
    • line buffered
      • 新しい行が出力されるか、新しい行が入力されるまでためられる
  • ファイルはすべてblock buffered
    • 初めて入出力するときにmallocが呼ばれる
  • stderrはunbuffered


printf()とfprintf(stderr)を混ぜていると、出力されるタイミングが違うなあ、と思っていたのだ。
出力先が違うからだと思っていたが、バッファリングの種類が違っていたからなのか。


引数がFILE*だから、システムコールレベルではなく、stdioとしてサポートしていることになるのだな。
open()した場合は、OSの動作を見ておかねばなるまい。

[linux]メッセージキューのmsgszは8192を超えてはいかん

※2017/05/25 22:25 修正あり

Linuxのメッセージキューは、まずはサンプルを動かすことにした。
いつものように、LinuxといいつつWindows10のBash on Ubuntu on Windows(以下 BoW)だ。

が・・・コンパイルは通るものの、msgget()でエラーになる。

Function not implemented


嫌な予感は的中した。
System V IPC is missing · Issue #1016 · Microsoft/BashOnWindows

Creators Updateでセマフォと共有メモリは対応したけど、メッセージキューはbacklogと書いてあるから、まだ残ってるという意味なのかな。


まあ、何でもかんでも期待しちゃいかんだろう。


VMに入っているUbuntu環境に持っていくと、進んだ。

が、msgsnd()でInvalid argumentが出てしまう。
Man page of MSGOP
msgsnd()がEINVALを返すのは、以下のどれか。

  1. msqid が不適切な値
  2. mtype が正の値でない
  3. msgsz が不適切な値 (0 以下か、システムで決まる値 MSGMAX よりも大きい値)

msqidはチェックしているし、mtypeも正の値を代入している。
ということは、3番のmsgszだ。

サンプルでは、こういう構造体になっていた。

struct {
    long mtype
    char mtext[BUFSIZ];
};

このBUFSIZは、8192だった。
だから、sizeofすると、たぶん8196・・・違った、8200だった。
8byteアラインなのね。


ではMSGMAXは?
これはマクロ値にはなっていないようだったが、Man pageの下の方に書いてあった。

MSGMAX

メッセージのテキストの最大サイズ: 8192 バイト (Linux では、この制限値は /proc/sys/kernel/msgmax 経由で読み出したり変更したりできる)。

うーん、ここだけ読むとメッセージのテキストの最大サイズだから使ってもよさそうなのだけど、msgszのが超えたらいかんと書いてある方が強いのだろう。


というわけで、うちの環境ではmtextが8184までOKで、8185からInvalid argumentになった。

sizeofはマクロに入れられないので、

struct {
  long mtype;
  char mtext[SZ_BUF];
};

#if 8 + SZ_BUF > 8182
#error !!!
#endif

みたいにして判定させるのが良いかも。


※追記

あれからいくつか見てみたが、msgsnd()に指定するサイズとして、sizeof(構造体)ではなく、sizeof(構造体) - sizeof(long)、としているサイトが見られた。
ま、まさか・・・。

もう一度説明を見直すと、msgsnd()のサイズとして指定するのは、struct msgbufではなく、mtextに相当するサイズ(msgsz)と書いてあるではないか!

私はmsgsnd()で構造体のサイズを指定していたのだが、それではダメだ。
そして、アラインメントもあるので、sizeof(long)を引くのも正しくなさそうな感じがする。
ここは、mtextに相当するサイズをマクロで指定するのがよいのかもしれん。


ふっ、まだまだ私も青いのぅ。。。
タイトルは間違っていないものの、動作検証をしていないから、後日やろう。

2017/05/24

[c/c++][linux]プロセス間でのメッセージキューに似たものはあるのか?

久々に、Linuxでネットワーク関係のアプリを書こうとしている。

やりたいのは、裏で通信してくれるアプリと、そのアプリに指示を出すアプリだ。
うまく作れば1つのアプリにまとめてもよさそうだが、いかんせん、コンソールから指示を入力させたりする実装をしたくないので、別アプリにして引数で指示を与えようと考えたのだ。
これもRPCの一種になるのかな?


そこまで考えて、悩むことになった。
どうやって指示アプリと通信アプリを接続すればよいのだろうか?
確かローカル環境では、socketpairでファイルみたいなのを作ってやっていたような気がする。。
まあ、今回は指示を出すだけなので、pairは作らなくてよいか。


指示を出すだけなので排他処理はいらないように見えるが、裏で通信していて、受信したメッセージによっては送信を行うことがある。
その送信も、指示するのと同じ経路でやってしまおうと考えている。
つまり、送信処理をキューでためられるようにして、そのキューには指示アプリか受信メッセージが追加を行う。
それぞれプロセスが違うので、ここに排他処理を入れようというわけだ。


なんとなく、共有メモリを作って、セマフォで排他するんじゃなかろうか、と思ったのだが、メッセージキューがあるらしい。
msegrcv, msgsndには排他がいるとか書いていないから、排他は不要なのかな?


しかし、メッセージキューに関して検索しても、あまり新しい記事が出てこない。
実はもっと便利なライブラリがあったりするのでは?と探すが、うまく探し出せない。
関連する語彙がわからん。。。


わからんので、ここら辺を見ながら作ってみよう。
IPC: Message Queues | Shinta's Site

[c/c++]accept数を制限したい

珍しくsocketで作っている。
serverという程のものではないのだが、socketをいくつか受け入れるしくみを作ろうとしている。

Man page of LISTEN

socket()して、bind()して、listen()して、あとはaccept()でやってくるのを待つ。
教科書通りにやると、accept()で処理がブロックされて、clientからのconnect()を待つことになる。

 

今回は、同時にN個まで接続できる、というようなことをやりたい。

socketって、同じポートで接続できないんじゃなかったっけ?と思ったが、connect()する方が適当にポート番号を振って接続しに来るためか、あまり気にしなくてよかった。
まあ、次々accept()したいから、スレッド起動させたりはせんといかんが、そのくらいのようだ。

では、あとは数を制限するだけだ。
・・・・あれ、どうやって?


今回も、Windows10のBash on Ubuntu on Windowsでやっている。

まずは、一番それっぽいように見えた、listen()のbacklogを変更した。
接続キューの上限みたいだから、それでいけると思ったのだが・・・ダメだ。
よく読むと「保留中の接続のキューの最大長」とのことだ。
だから、手でconnectするアプリを次々起動させるようなことでは、保留させる必要がないということだろう。

 

linux - Is it possible to unlisten on a socket? - Stack Overflow
これを読むと、accept()してすぐclose()!らしい。

int delsock = accept(sock, NULL, NULL);
close(delsock);

まあ、確かにやりたいことは満たすのだけど、connect()でエラーが返るわけでは無いので、ちょっとなぁ。

 

しかし、connect()のエラー値を見ても、あまりふさわしいのがないな。
ECONNREFUSEDが近いけど、ちょっと意味が違う。
一時的にリソースが使えない、みたいなのはなさそうだから、あんまりがんばっても仕方ないのか。

2017/05/23

[win]WinMerge

Windows10で、ファイルの比較をするのにWinMergeを使っている。
version 2.14.0.99+-jp-99となっているから、日本語版なのかな。

image

 

シェル連携させていて、Explorerのファイルを選択してコンテキストメニューから「比較」とすると、比較した画面が表示されるので便利だ。

image

 

何気なくファイルを選択してしまうと、左右のどちらにどのファイルがいるのかわからなくなってしまうのだが、選択の仕方を意識的に行うだけで、どちらにどのファイルが来るのか確定できそうな気配だ。

「気配」としたのは、今のところ私の環境はそうなっているけど、何でそうなるのか知らないからで、他の環境だとそうならないかもしれん。

 

私の環境では、2ファイルを選択する場合、ExplorerからCtrlキーを押したままファイル選択を1つずつ行うと、比較ウィンドウの右側に1番目に選んだファイルが、左側に2番目に選んだファイルが出てくるようだった。
ファイルがソートされている順に左→右と出したいのであれば、Explorerでは並んだファイルの下からCtrlキーでクリックしていくと期待通りに出てくれている。

 

技というほどではないし、確定しているものでも無いけど、私の場合はこれでずいぶんと手間が省けるようになった。

2017/05/21

Diffie-Hellmanの25519や448とは?

前回、まったく内容を理解しないまま、noise-cのサンプルアプリだけ動かした。
あとは、これをプロジェクトに組み込めばよい・・・と思っていたのだが、そうではなかった。
まだわかっていないが、サンプルも引数で設定が変更できたように、何か使用方法を決めるというもののようだった。

 

たとえば、Noise_NN_25519_AESGCM_SHA256、などという名前が、何か意味を持っているらしい。

Prefix : Noise
Pattern : NN
Diffie-Hellman : 25519
Cipher : AESGCM
Hash : SHA256

ということのようだ。
もはや呪文ですな。。。

 

noise-cがサポートしているアルゴリズムは、ドキュメントに書かれている。
http://rweather.github.io/noise-c/index.html#algorithms

これが仕様を満たしているのかどうか、満たしていなかったら改造できるのかどうか、改造できなかったら他のライブラリがあるのかどうか、その辺を見ていくことになりそうだ。
うう、つらい・・・。

つらいのだが、誰か調べてくれるわけでもないので、基礎知識に相当するものくらいは記事にしてもよかろう。


知りたいのは、Diffie-Hellmanだ。
サンプルのechoでも、25519と448という数字しか出てきていない。
そもそも、Diffie-Hellmanって鍵交換とかそういうはなしじゃなかっただろうか?
それの数字って、何なのだろう。

 

RFC 7748 - Elliptic Curves for Security
検索すると、すぐに出てきた。
RFCで推奨している楕円曲線の種類が、25519と448という名前のようだ。
RFC 7748だけじゃなくて、8031や8037などにも出てくるな。

2^255 - 19をつなげて、25519。
448はちょっと違って、2^448 - 2^224 - 1となっている。
そういえば、前調べたChaCha20-Poly1305も、2^130 - 5だったからそういう名前だった。


Diffie-Hellmanは、安全に鍵を交換するための方式だ。
鍵といっても物理的な鍵ではなく、データとしての鍵だ。
検索すると、たくさん出てくる。

また、CipherやHashも暗号関係の技術だ。
これらをどう組み合わせてもよいようにできているのだろう。

だから・・・noise-cが対応していないパラメータを使うようになっているという可能性もあるということだ。
嫌な予感はするのだが、これ以上は触れるのを止めておこう。

[c/c++]noise-c ?

仕様書で「プロトコルはnoise-cで」みたいなことが書かれていた。

noise-c ???

どうやら、Noiseプロトコル、というものがあるらしく、そのC言語実装がnoise-cだそうな。
rweather/noise-c: Noise-C, a plain C implementation of the Noise protocol

プロトコルに興味は無いのだが、githubに上がってるくらいだから、ブログのネタにしても悪くはなかろう。


プロトコル仕様は、これらしい。

The Noise Protocol Framework

いやー、見る気にならんわー。
最初の方に"crypto"と出てくるので、何か暗号化するようなプロトコルなのだろう。

こういうのって、作っている人は改良しながらやっていくから中身が分かるのだろうけど、外側から見ている人、特に私みたいに成果だけ使おうとしている人にとっては、なかなかつらい。

私もgithubにときどき上げているが、使いやすくがんばっているわけではないし、そもそも「誰にでも使えるように」などと考えているわけではないから、同類だ。
それに、ドキュメントを整備しているわけではないから、同類とすることすらためらわれるレベルである。。。

 

まあ、いいのだ。
使おうと思う人が増えると、自然とドキュメントも整備したくなってくるものだから、それだけの違いなのである。


話を戻そう。

noise-cの使い方はまだわからないが、examplesはある。
Noise-C: Using Noise-C: Client/Server Echo Example

ただ、これを読んだまま実行してもなんだかわからなかったので、手順を残しておこう。
動かしたのは、bash on ubuntu on windows(16.04)だ。

 

 

githubから落とす

cloneでも何でもよいので、持ってこよう。

 

makeする

autogen.shがあるから、まずはそれを実行するとよかろう。
Build手順が載っているので、その順番でよいのではなかろうか。
Noise-C: Main Page

 

exam:key生成

いま、noise-cのディレクトリにいるとしよう。

$ cd examples/echo
$ mkdir keys
$ cd keys
$ ../echo-keygen/echo-keygen 25519 client_key_25519 client_key_25519.pub
$ ../echo-keygen/echo-keygen 25519 server_key_25519 server_key_25519.pub
$ ../echo-keygen/echo-keygen 448 client_key_448 client_key_448.pub
$ ../echo-keygen/echo-keygen 448 server_key_448 server_key_448.pub

パスをちゃんと書けよ!と思った。

実際は、*.pubの方を公開するのだけど、今回は同じPC内で実行するから、面倒を省くために keys/に全部置いているだけだ。
psk(pre-shared key)もいるらしいが、読んでもよくわからんので、こういうスクリプトを作った。

#!/bin/bash
rm -rf keys
mkdir keys
./echo-keygen/echo-keygen 25519 keys/client_key_25519 keys/client_key_25519.pub
./echo-keygen/echo-keygen 25519 keys/server_key_25519 keys/server_key_25519.pub
./echo-keygen/echo-keygen 448 keys/client_key_448 keys/client_key_448.pub
./echo-keygen/echo-keygen 448 keys/server_key_448 keys/server_key_448.pub

echo -en '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f' > keys/psk.bin
base64 keys/psk.bin > keys/psk

 

exam:server起動

待ち受ける方。

$ cd examples/echo/echo-server
$ ./echo-server --key-dir=../keys 7000

これで、待ち状態になった。

 

exam:client起動

serverに接続をお願いする方。

$ cd examples/echo/echo-client
$ ./echo-client Noise_NN_25519_AESGCM_SHA256 localhost 7000
Noise_NN_25519_AESGCM_SHA256 handshake complete.  Enter text to be echoed ...

これで待ち状態になった。
なにかテキストを打ち込むと、そのまま返ってきた。

hiro99ma
Received: hiro99ma

うーん。。。動いているような気はするが、そもそもなんだかわかっていないので、そこから先に進めないな。
こうやって、詳細を調べていく間に世の中が進んでいくのだけど、まあ仕方ないわね。。。


examplesには続きがあった。
上記の動かし方は、static keyが不要な動かし方らしい。
確かに、作ったkeyを指定してない。

$ ./echo-client --client-private-key=../keys/client_key_448 \
            --server-public-key=../keys/server_key_448.pub \
            Noise_KK_448_ChaChaPoly_BLAKE2b hostname 7000

これを実行すると、echo-server側にエラーが表示される。

set client public key: Unknown identifier

ソースでいえば、ここのはず。
コメントからすると、client用のpubkeyを設定しているのだろう。

 

・・・ここのif文って、どっちもNOISE_DH_CURVE25519しかチェックしてないじゃないか。。。
NOISE_DH_CURVE448に変更すると動いた。

修正されたので、もう大丈夫だ。

2017/05/19

[win]Bash on Ubuntu on Windows起動

2017年4月のCreators Updateを当てたWindows10を使っている。
Bash on Ubuntu on Windows(な、長い。。。)の安定度が増したので、非常にありがたい。
デフォルトがこっちになって、コマンドプロンプトエミュレーション機能、みたいな形になっても困らないくらいだ。

起動するときは、メニューからショートカット選択している。
プロパティは、こう。

image

テキストエディタで編集しているディレクトリで開いてくれるとありがたいのだが、このbash.exeは特殊なためか、私が使っているEmEditorでは起動に失敗してしまう。

image


話が少し変わるが、最近テキストエディタとしてVisual Studio Codeを使うようになってきた。
自分で書いたくらいのC言語だったらテキストエディタでも追えるのだが、あまり使わない言語だったり大きいプロジェクトだったりすると関数を探すだけで疲れてしまう。

Windows上でVisual Studio Codeを起動しているのだが、Ctrl+@で「端末の切り替え」というキーに割り当てられているようだった。
なんとなく押すと、PowerShellが起動した。
「もしかしたら、bashが起動できるのでは?」と見てみると、できるようになっていた。
VSCodeをフォルダで開いているためか、bashもそのディレクトリで起動している。

 

さすがMicrosoft製だけあって、自分のところからは起動できるのか、と設定を見てみると、こういうのが追加されていた。

"terminal.integrated.shell.windows": "C:\\WINDOWS\\Sysnative\\bash.exe"

\WINDOWS\Sysnative?

image

ないよなぁ。。。

が、このパスをEmEditorに指定すると、bashが起動した。
へー。
もう試す環境が無いのだが、Anniversary Updateでも使えたのかもしれん。


おまけ

VSCode ver.1.12.2を使ってるけど、検索のデフォルト設定方法がわからん。
起動すると「大文字小文字の区別無し」「単語検索ではない」になっているのだけど、私は通常がその逆なので、毎回設定し直さないといけない。
設定方法があったら教えてくだされ。

 

大文字小文字を区別しなかったら、思ってもないものが検索されて困りそうだけど、他のエディタでもデフォルトがそうなっているから、少数派なのか。。。

2017/05/18

[c/c++]leveldb ?

ちょっとしたデータを読み書きして保持するとき、SQLiteと使うことが多かった。
別に検索したいとか、そういう要望があるわけではなく、他にそういうものはないのだろうと思い込んでいたのだ。

 

最近、またそういうデータを保持するしくみがいるので、どうしたものか悩んでいたら、leveldbというものがあることを教えてもらった。

グーグルがNoSQL軽量ライブラリ「LevelDB」をオープンソース化。SQLiteとの比較ベンチマークも公開 - Publickey

NoSQLですか。。。
まずはその用語からですな。


NoSQL - Wikipedia

"RDBMS以外のデータベース管理システム"くらいの言葉らしい。
リレーショナルデータベースマネージメントシステム、かな。
テーブル書いて、線でつなげていた気がする。

 

leveldbは、リレーショナルじゃなくて、キーバリュー型。
キーとそれに対するバリューをストアするので、キーバリューストアとか、KVSとか呼ばれるようだ。
そういえばAndroidのプリファレンスもそのくらいの機能しか使わなかったな。


google/leveldb - github

C++か。。。
c.hという、Cのインターフェースがあるので、ライブラリを作ってしまえばCからもアクセスできそうだ。

ただ、APIが思ったよりも多いので、ROMが多少心配だ。
また、できればファイルシステムを使わないようなところでも使えるとよいのだが・・・さすがに無理か。

2017/05/17

[c/c++]またMakefileの名前一致で失敗していた

以前、こういう記事を書いた。
hiro99ma blog: [c/c++]Makefileのdependは名前一致なのか

依存ファイルのオブジェクトファイル部分に相対のパス名が入っていると、うまくいかないようだった、という話だ。
相対というのは、

obj/./test.o

みたいに、間違ってないけど不要な相対パスなのかもしれん。
そこまでは調べていないのだ。

 

そのあと、依存ファイルの作り方を変更することで対応できそうだったという記事を書いた。
hiro99ma blog: [c/c++][make]dependの解決

そのMakefileを使っていたのだが、またうまくいっていなかった。
オブジェクトファイル名をソースファイル名から作っているところで、単にフォルダ名と拡張子だけを変更していたのだが、ソースファイルをさらに別ディレクトリを作っているとダメだったのだ。

 

こんなディレクトリ構成になっている。

_build/
   hello.o
   hello2.o

src/
  hello.c
  hello2/
    hello2.c

だが、ソースファイルをそのままオブジェクト名にしてしまうと、

_build/hello.o
_build/hello2/hello2.o

になっていたのだ。
まあ、単なる考慮漏れだ。

 

あれこれ考えたが、このMakefileはオブジェクトファイルを同じディレクトリに放り込むので、$(notdir)でパスを取り除けばよかろう、という結論に至った。
https://github.com/hirokuma/makefile_hello

オブジェクトファイルを同じディレクトリに置くことの弱点は、同じ名前のソースファイルがあるとダメだ、ということだろう。
一人でやっていると起きないけど、複数人でやっているとやらないとも限らない。
関数名はファイル名に関連したプレフィクスを付けるルールにしておけば対応できると思うが、名前が長くなるのが悩みどころだ。

2017/05/15

[ble]BLE NanoでnRF Snifferを動かす

nRF Snifferという、nRF51 DKなどで動かせるスニファがある。
ファームウェアもあるし、COMポート経由でWindowsとアクセスするようだから、別にnRF51 DKじゃなくても動かせそうな気がする。

 

対応しているハードウェアは、こうなっていた。
nRF-Sniffer-UG

• nRF51822 Evaluation Kit (PCA10001) and a mini USB cable
• nRF51422 Evaluation Kit (PCA10003) v3.0.0 or later and a mini USB cable
• nRF51822 Development Kit dongle (PCA10000)
• nRF51-DK (PCA10028) v1.0.0 or later and a micro USB cable
• nRF51 Dongle (PCA10031)

nRF51822とnRF51422が混ざっているが、使うのはBLEだけだからどっちでもよいのだろう。


nRFgo Studioでファームを焼く。
ちゃんと動いているかどうかは、PCA10001かPCA10003ならAdvertisingの検出でLED1がトグルするらしい。

PCA10001の図面を見ると、LED1はP0.19につながっている。
BLE nanoのP0.19もLEDにつながっている。
が、PCA10001はHで点灯、BLE nanoはLで点灯になっている。。。

あ、これは気にしなくていいか。
逆になっているだけだ。
AdvertisingするPeripheralを動かすと・・・点滅した!


次はUARTだ。

nRF51 DKやPCA10001はUSBでPCとつなぐので、ぱっと見てnRF51のどのポートかわからん。。。
nRF51 DKのUsers Guideに「4.2 Virtual COM port」という章があり、以下の表が載っていた。

image2

P0.09がTXD、P0.11がRXD、でよいのか?
それなら、BLE nanoもそうなっている。

あとは、問題になるとすれば通信速度だろうか?
よくわからんので、Snifferに入っていたexeファイルを実行した。
・・・とりあえず、ダメなようだ。

AppDataの下にログが入っているので確認すると、

Cannot configure port, some setting was wrong

などといわれている。
エラーは87番になっていて、検索すると

ERROR_INVALID_PARAMETER
87 (0x57)
The parameter is incorrect.

らしい。
Prolificのではダメなのかも。

何も考えず、BLE nano用のUSB-I/Fに挿してからexeを起動させると動いた。
考えすぎだ。。。


操作できるようなコンソール画面が出てきたものの、Advertisingしている機器の一覧が表示されない。

ログファイルを見てみると、Firmware versionは取得できているが、Invalid packetというエラーがたくさん出ている。
ここまでくると、もうよくわからんな。。。

 

ロジアナでUARTを計測した。
何か送信し続けているようなので、TXDを見てみる。

image3

これは10MHzサンプリングだから、まあ足りてないことはないだろう。
1bitが2.1usくらいだから、1/(2.1*10^-6)=476190.4762。
465kbpsくらいか?
460kbpsでよいかもしれん。

 

うちにあるBLE NanoのUSB I/F(MK20)がその速度に対応できないだけじゃなかろうか。
以前購入した、aitendoのUSB-UART変換モジュールをつなげた。
ああ、動くじゃないか。。。
CTS/RTSがないので、そこはGNDに落とさないといかんようだ。

 

image9

 

Wiresharkも、1.12.13をインストールし、スニファアプリが動いている状態で起動させ、Users Guide PDFのTroubeleshootingを読みながらpipe(\\.\pipe\wireshark_nordic_ble)を設定すれば、アタッチしてBLEパケットを読み取ることができた。
(うちはWireshark2も使いたいのだが、そっちをインストールするとスニファがレジストリを見てしまうせいか、2の方を起動しようとしてしまうのだ。)

あまり深く触っていないが、ここまで動けば他も動くんじゃなかろうか。

 

スニファのHEXファイルも、mbedっぽくD&Dして書込めば済んだような気がする。
USB-I/Fが誤算だったが、今は新しいタイプになっているようなので、もしかしたらそっちだと普通にいけるのかもしれない。

2017/05/14

[win10]MS17-010 の適用

なんだか世間では、ランサムウェアのWannaCryptなるものが流行っているらしい。
あらやだわ、ということで、うちのWindows10(Creators Update後)がちゃんと対策されているかどうか確認したい。

 

ランサムウェア WannaCrypt 攻撃に関するお客様ガイダンス

  • MS17-010をインストール
  • マルウェア対策製品を最新にしておく
  • SMBv1を無効にしておくと、さらに安心かも

 

対策製品を最新にしておくのは、このPCはWindows Defenderしか使っていないので、Windows Updateしておけばよいだろう。

SMBv1はここで無効にできる。

image

が、さて、これを無効にしても大丈夫だったっけ?
Sambaで使われていなければ大丈夫な気がするが、はてさて。

ファイル共有で利用されている SMB のバージョンを確認する方法 | Hebikuzure's Tech Memo
DEPENDENCIESは「MRxSmb20」になっていたから、SMBv2を使っているのか?
でも、このSMB 1.0のサポートにはチェックが入っているのだが。。。

とりあえずチェックを外して、アクセスできなかったら戻そう。
再起動がいるようなので、後で確認する。


そして、対策であるMS17-010だ。

マイクロソフト セキュリティ情報 MS17-010

緊急なのは分かるのだが、Windows10だけでこんだけ書いてあるのだ。

image

どれだよ!
まあ、半分は32bit/64bitの違いなので、3つしかないとはいえ、どれが自分用なのかわからん。

Versionは、Windowsのバージョンだろうとは思うが、今使っているPCはこうなっている。

image

そう、該当するバージョンがないのだ。。。
だから、既に対応されていると考えることもできるし、この記事が2017年3月15日だから、まだこのバージョンは正式になっていなかったと考えることもできてしまう(うちがv.1703にしたのは2017/4/18のようだ)。

とりあえず、一番上のバージョン無しを試してみたが、これはインストールできなかった。
バージョンはこういう関係のようだ。

  • バージョン無し: 2015年7月にリリースされた初期バージョン
  • 1511: 2015年11月
  • 1607: Anniversary Update
  • 1703: Creators Update


PSA: Massive ransomware campaign (WCry) is currently being conducted. SMB v1 (MS17-010) is the primary attack surface. All desktop and server versions of Windows from Vista to 10 are affected. Make sure your machines are patched to avoid infection. : pcma
こちらでは、1703ではKB4016871で対応されている、と書かれている。
うん、そのKBならうちのPCもインストールされている。

 

2017年 5月マイクロソフトセキュリティ更新プログラムに関する注意喚起(JPCERT)
ここで「リモートからの攻撃によって任意のコードが実行される恐れがあります」と書いてあるので、2017年5月のアップデートが入っていれば大丈夫なのかな。

 
大丈夫かどうかって、実際に攻撃を受けるまでわからないから怖いのだな。。。
 

2017/05/13

[ble]BLE NanoとJ-Link LITEをつなぐ

過去の私もやっているが、やはりBLE NanoとJ-Link LITEをつなぎたい。

hiro99ma blog: [ble]BLE nanoを使う

1.27mmのところをどうするかだけが問題なのだが、前回もかなり無理やりつなげている。
そろそろ、何か治具を作った方が良いんじゃなかろうか。

 

1.27mm--2.54mm変換基板が余っているので、ぜいたくに使うことにした。

image

 

内側はこうなっている。
4本が上の方に集まっていてよかった。

image

 

BLE Nanoに挿す方は、前回と同じだ。

image

 

簡素な作りだが、動けばよかろうなのだ。

2017/05/12

[ble]BLE NanoとUSB-IFでKeilにつなぐ

過去の私は、BLE Nano(ノーマル)に、USB-I/FだけでKeilを使ったデバッグができていたらしい。
hiro99ma blog: [ble]BLE nanoを使う

が、疲れていたのか、酒飲みながらだったのか知らないが、どうやってつなげていたのか書いていない。
私のばか。。。


まず、USB-I/FをDAPLINKにしなくてはならないだろう。
これは、上記リンク先だったり、数日前の記事だったり、その辺を読んでUSB-I/Fのファームウェアを書き換えればよいだろう。

 

USB-I/Fをつないでない状態で、nRF5 SDKのKeilプロジェクトサンプルを立ち上げる。
ちょっと古いが、nRF5 SDK v11.0.0を使うことにする。
PCA10028用プロジェクトを開き、デバッグ設定を"CMSIS-DAP"にして見てみる。
   examples\ble_peripheral\ble_app_hrs\pca10028\s130\arm5_no_packs

image

まあ、未接続だからな。
では、つないで、開き直してみよう。

image

あ、見えてる。
では、とKeilツールバーにある「d」っぽいアイコンをクリック。
・・・失敗した。

Build Outputに「No Algorithm found」と出ているので、先ほどのDebug設定の反対側のタブを開いてみた。

image

ああ、ないね。
nRF51xxxがそれっぽいので、Addした。

image

これで「d」をクリックすると、デバッガが起動してmainで止まってくれた。


そういうわけで、前回は特に書くことがなかったので、書かなかっただけと思われる。

[clang]uint64_tのprintf

最近、64bit型を使うことが増えてきた。
その場合は、uint64_tにしている。

デバッグで値を標準出力に出したい場合、printf()を使っている。
そのとき、"%d"なんか使うと、warningが出てしまう。

今使っている環境では、

printf("%llu\n", (unsigned long long)value);

などとしている。

 

これでも困りはしないのだが、キャストが長すぎる。
確か、uintXX_t系の書式が定義されていたはずだ。。。


困ったときは、オライリーのCクイックリファレンスだ。
さすがにここは、古い本には載っていない。

目次で見つけたのは、「第18章 標準ライブラリ関数」のprintfだ。
持っている本では、p.520の表18-9に載っていた。stdint.hで定義されているらしい。
ふむふむ、uint64_tで16進数だったら「PRIx64」でよいようだ。

#include <stdio.h>
#include <stdint.h>


int main(int argc, char *argv[])
{
    uint64_t val = 0x123456789abcdef0ULL;

    printf("val = %" PRIx64 "\n", val);
    return 0;
}

しかし・・・コンパイルエラーが出る。。。

 

なぜだ。。。
他のページを見直すと、「16.3 標準ヘッダの内容」にも同じような内容が書かれていた。
しかし、p.287を見ると「<inttypes.h>」となっている。

#include <stdio.h> #include <inttypes.h> int main(int argc, char *argv[]) { uint64_t val = 0x123456789abcdef0ULL; printf("val = %" PRIx64 "\n", val); return 0; }

コンパイルが通るではないか!

というわけで、p.520の表18-9は、stdint.hにあるのは整数型の型だけで、変換して石マクロはinttypes.hにあるのを覚えておきましょう。


ちなみに、今回使った「PRIx64」がどういうマクロなのか、printf("%s\n", PRIx64)で見てみました。

lx

えー、そうなの。。。

ちなみに、

PRIu64 : "lu"
PRIi64 : "li"

でした(Bash on Windows)。

2017/05/08

BLE-Nano+USBでHEXファイルが焼けない (2)

昨日の続きだ。
久しぶりにBLE-Nanoを出してみたが、HEXファイルがうまく焼けなかったので、なんとかしたい。

 

まず、MK20の方から。
うちにあるのは、こちら。

image

こちらの写真と見比べると、MK20 USB V1.0だということがわかる。
そのファームウェアは、こちら。
BLENano/USB-IF/MK20-USB/board_v1.0 at master · RedBearLab/BLENano

これをダウンロードして、MK20はRSTボタンを押したままUSBポートに挿し、Windowsが認識するのを待つ。
そうすると「BOOTLOADER」というラベル名のドライブとして見えるので、ダウンロードしたファイルをD&Dで書込む。
LEDが高速点滅したら終わりらしいので、USBポートから外す。

 

もう一度USBポートに挿すと、「DAPLINK」というラベル名のドライブとして見えた。
では、何か焼いてみよう。

RedBearLab BLE Nano | mbed
ここに、LED点滅のHEXがあるから、それをドライブにD&Dしてみる。。。

image

あれ、点滅しない??
何か間違っているのか・・・。

あ、LEDはこっちじゃなくて、BLE-Nanoにも載ってるんだ。

image

こちらは無事に点滅していた。

 

・・・もしかしたら、昨日焼けないと思っていたのは、単に見ているLEDが違っていただけかも、と思ったが、いやいや、HEXファイルをドライブにD&DしたらUSBから取り外された動作をしていたので、それ以前の問題だったのだ。

 

そんなわけで、Windows10でうまくいかなかった人は、firmwareを書き換えてみるとよいかもしれん。

BLE-Nano+USBでHEXファイルが焼けない (1)

机の片付けをしていると、TIのBLEドングルが見つかった。
懐かしいのでノートPC(Windows10)に挿してみたところ、ドライバが認識されなかった。。。
デスクトップPCのWindows10は認識した。

ノートPCは何も設定していなかったので、おそらく今回が初回の接続だったはずで、Creators Update。
デスクトップPCは以前から使用できていて、Anniversary Updateだ。

どの違いが影響しているか分からないので、これはデスクトップPCにCreators Updateがインストールされたときに確認しよう。


ついでに、近くにあったBLE-Nanoも使ってみることにした。
mbedにできるMK20-USBもあるので、挿してHEXファイルをドライブに置いてみた。

しかし・・・焼けない。
途中でUSBを抜いたような音がして、また接続される。
これは、デスクトップPCもノートPCも同じ動作だった。
少なくとも、以前はデスクトップPCでは使えていた形跡があるのだが。。。

DAPLink firmwareなら'DAPLink'、CMSIS-DAP firmwareなら'MBED'というラベル名になるらしい。
そして、うちではMBEDという名前だったから、CMSIS-DAP firmwareが焼かれていたのだろう。

 

RedBearLab BLE Nano | mbed
こっちでは、firmwareとして20140912という日付だから、githubにある方が新しいな。

実は、なんとなくMK20のボタンを押したままUSBに挿してしまい、何か焼くモードになったので、mbedのサイトにある方を焼いてしまったのだ。

 

次回は、githubにある方を焼いてから試すとしよう。
今日やってしまえばよいのだが、もう眠たいのだ。。。

2017/05/07

[bc]segwitのTXID

連休にもかかわらず、書けるような記事が何もない。。。
これではまずいので、困ったときのBitcoinネタを出そう。

 

ビットコイン分裂騒動は「レイヤー2」への反動か | TechCrunch Japan

SegWitを前提としないLightning Network実装は理論的には可能だが、開発者にとって「やりたくない仕事」なのだそうだ

あははは、うまい表現だ。
最初に「segwitなしでLN(LightNing)」という話を聞いたときは、おお!そんなことが!、と思ったけど、どうやって実現するのかを読んでいく途中で「あー、私にはむりー」となってしまった。
(2017/05/10:Lightning Network、の方がふさわしいな。)

 

基本的に、Bitcoinのやりとりは、誰も信用しない、というところを重視していると思っている。
trustless、というやつだ。
現金をBitcoinに替えたりする場合は知らんが、Bitcoinの中だけでもそうなるように苦慮している。
ときどき「そこまでするの??」というような内容もあるのだけど、理論的にツッコミできないので、そういうものかとあきらめている。

雰囲気としては、Bitcoinは秘密鍵とデジタル署名で成り立っている。
もちろん、ブロックチェーンというだけに、ブロックのもつ役割は大きいのだけど、ブロックは何からできているかというとBitcoinの価値を移動させるトランザクションで、トランザクションは秘密鍵でデジタル署名することになっているのだ。

 

トランザクションは、それぞれを識別するIDが付いている。
これが「トランザクションID」(TXID)というやつだ。
どこか中央のサーバがあれば、そこが一意になる値を付ければよいのだが、Bitcoinでは中央がいないので、一意になるような値をがんばって付けなくてはならない。
連番にしてしまうと、ネットワークの転送時間などもあって、同時に同じ番号を付けられてしまうこともあるだろう。
だからだと思うが、トランザクションIDはトランザクションの中身を使って算出するようになっている。
ハッシュ値、というやつですな。

 

そのトランザクションIDの計算をする方法が、非segwitとsegwitで異なる。
非segwitの場合は、トランザクションの中身だけで計算できた・・・と思う。
しかしsegwitの場合、従来の計算方法を使ったIDの算出方法と、新しい計算でのID算出方法がある。
そして、非segwitのトランザクションIDと同じ位置にいるのは、新しい計算でのIDの方である。

 

新しい計算方法の特徴は、

  • そのトランザクションのINPUTがいくらのBitcoin量(amount)だったかを計算に含める
  • そのトランザクションのデジタル署名は計算に含めない

だと思う。
前者は、確かトランザクション展性という脆弱性に対応するため(だったと思う)。
最初の記事に出てくる「レイヤー2」にとっては、後者の方が欲しい。

2017/05/10追記
この計算方法は、署名についてだった。。。
TXIDについてはトランザクションの中身だけで計算できるが、計算に含める部位と演算方法が違う。
その部位に署名(witness)が入らないため、TXIDは署名をする前に計算できる。

なお、WTXIDというものもあり、これは従来と同じ計算方法のため、署名もひっくるめてハッシュ計算している。

記事を読んでいると「チャネル」という言葉がしばしば出てくると思う。
これは「私とあなただけがやりとりする口座」みたいな意味だ。
テレビやラジオのチャンネルよりも、Amazonなどのログインアカウントみたいな意味合いの方が強いかな。

Bitcoinで口座に相当するものといえばBitcoinアドレスになるが、ここは「私とあなた」なので、2-of-2のmultisigアカウントを作ることになる。
Bitcoinのアカウントを作るだけなら何とでもできるが、それをBlockchain上に見えるようにするには、既にあるトランザクションからそのアカウントに送金してもらうことになる。
だから、レイヤー2のアカウントを作る=そこに入金する、ということになる。

が、2-of-2のmultisigに入金するということは、2人ともデジタル署名をしないとお金を取り出せないということでもある。
もし相手が偽物だったり、入金した後に逃げられて取り戻せなくなったりするのでは・・・・という心配が残る。
これが、「trustless」が重視される理由だ。
相手が悪いことをしても、少なくとも自分は損をしない、下手をしたら悪いことをした人が損をする、というくらいのことを、計算上で実現させるようにしている。
計算上というか、Bitcoinの支払いスクリプトで、そうなるようにがんばっているのだ。

相手から署名してもらわなくてもTXIDが計算できるということは、multisigへ入金したとして、そこから自分に取り戻すトランザクションを署名無しで作ることができるという意味でもある。
そこまで保険を掛けておけば、取り戻すトランザクションが手元にあるので、相手が逃げるかどうかはわからないけどチャネルを開いても少なくとも損はしない、という安心感が得られる。

 

こういう、異常系というか純正常系というか、そういう部分がレイヤー2の大半を占めるので、けっこう大変なのだよ。。。

2017/05/02

[golang]値を複数返す関数があるが、片方しかいらない

久々にgoで書かれたソースを見ている。
相変わらずわからんが、動かすことはできるので、fmt.Printf()を埋め込んで動きを見ている。

 

A1という関数を使っている箇所があり、それと似たA2という関数を使った場合の違いを見ようとした。
そのA2という関数は、値を2つ返すようになっているのだが、私は1つしか使わない。
まあよかろう、と適当な変数に代入させたのだが、エラーになってしまった。
どうも、未使用の変数があるとエラー扱いになるようなのだ。

じゃあもう片方も無理やり使ってやればよいのだろうが、使い道が思いつかない。。。
試しに、いる戻り値しか取得しないようにしたがエラーになるし、コンマだけで数をごまかそうとしてもエラーになった。
うーん。。。

 

未使用の変数/インポートに対するエラーを抑止できますか?
変数として「_」を使えばよいということか?
試しにやってみると、エラーが消えた。
Pythonもそういえば、「_」を使って回避できたような気がする(deleteで消した方がよいかもしれんが)。

2017/05/01

「ChaCha20 and Poly1305」は「ChaCha20-Poly1305」でよい気がしてきた

数学が専門ではないと逃げようとしたが、理論的な導出はわからないだろうし、導かれた結果が正しいかどうかは分からないかもしれないが、結果を利用するのは常套手段でなくてはならない。

前回、ChaCah20が出てくるRFCで、私が知りたかったのは「RFC-7539」、TLS/SSLに出てくるRFCは「RFC-7905」で、数字が違うのだから、きっと中身も違うはずだ、と何も考えずに結論してしまった。

 

しかし、そうなのだろうか?
RFCの番号が違うとか、RFC-7539の中に「7905」という数字が出てこないとか、そんな見た目だけのことで思考を止めてはいけないのではなかろうか、と考え始めた。

内容は分からないにしても、思考停止するのはよくないだろう。
せめて、自分なりに調べてみて、わからなければあきらめる、くらいのことをしてもよいはずだ。


RFC 7905 - ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS)

一番簡単なところから始める。
さっきは、RFC-7539の中に「7905がない」というだけで済ませてしまったが、その逆を考えてなかったのだ。

果たして、RFC-7905の中には、RFC-7539への参照が書かれていた。
無関係ではないのだ。
しかも、文中で4回も参照されている。

RFC-7905を眺めたが、ここにはアルゴリズムのことは書かれておらず、TLSの暗号suiteとしてのChaCha20 and Poly1305のことが書かれているだけのようだ。
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256など、どの組み合わせを使うかということだけが書かれているのか。

では、方向性は間違ってなかったのかも。


AEAD_CHACHA20_POLY1305の要求がどうのこうの書かれているが、そういうのはここを読んでいくのがよさそうだ。

新しいTLSの暗号方式ChaCha20-Poly1305 - ぼちぼち日記

上の方しか読んでなかったけど、ちゃんとChaCha20の説明とPoly1305の説明が出ているじゃないか。。。

ChaCha20-Poly1305は「認証付き暗号」という種類で、認証付き暗号はAEADという略称らしい。
Poly1305は16byteのMAC値を生成するようで、計算したときも16byte増えていたから、暗号化した結果にMACを付けることを認証付き暗号と呼ぶのだろうか。

 

アルゴリズムは分かっていないが、なんとなく雰囲気は分かった気がするので、ChaCha20関連はこれで終わりにしよう。