2017年6月11日

[c/c++]同じidでmsgsnd()してmsgrcv()すると、自分で読める

[2017/07/06]追加記事を書きました
  [c/c++]同じidでmsgsnd()してmsgrcv()しても、msgtypeを指定すればOK


Linuxで2つのプロセスを作っていて、片方がサーバのように待ち受け、片方の要求に対して応答するようなしくみを作っていた。
どういう方法がよいのかわからなかったので、メッセージキューというものが見つかったので、msgsnd()とmsgrcv()でやろうと考えた。


最初は、クライアント側からサーバ側に要求してサーバ側の標準出力に結果を出していたのだが、それだと面倒なので、結果をクライアントに返してもらうように変更した。

何も考えず、ftok()でkeyを作り、msgget()でidを取得し、それを使っていたのだ。
が・・・動いたり動かなかったりする。
特に複雑なことはしておらず、サーバ側はmsgrcv()で待ち、クライアントがmsgsnd()したものを受信したら、結果をmsgsnd()で返してまたmsgrcv()で待ち状態になる、というだけだ。


悪かったのはいつものように私で、サーバがmsgsnd()して結果を書込んでからmsgrcv()にさっさと移行してしまうため、クライアント側がmsgrcv()で受信する前に自分で読み取ることがあったのだ。
だから、うまく行ったり行かなかったりという不安定な動きになっていた。

msgrcv()するとキューから消えてしまうので、mtypeで見分けても、もう遅い。
こんなことだったら、共有メモリにした方がやりやすかったんじゃなかろうか。


今回は、ここはまだ重要なところではないので後から見直すとしても、取りあえずでよいので回避できればよい。
どうするかというと・・・

msgrecv();
受信後の処理();
msgsnd(結果);
sleep(1);

うん、1秒くらい置いておけば相手は読んでくれるからよいだろう。

あー、ださださだ...

2017年6月10日

[c/c++]3項演算子とifはそこまで変わらない

判断して代入するだけ、という処理はしばしば書くと思う。

2択の場合、私は三項演算子を使うことが多い。
ただ、3項演算子で書くと1行が長くなりすぎることがあり、そういうときは改行したりする。

そういうとき、改行するくらいだったらif文で書けばよいんじゃないの?

という声がよぎるのだ。

やることは同じなので、結果として同じバイナリになるのだったら、その時の気分だったりコーディング規約で書けばよいのだけど、もし高速になる要素があるのだったら推していくのもありだろう。

gccで確認しよう。


int main(int argc, char *argv[])
{
    int vol;
    if (argc == 1) {
        vol = 2;
    } else {
        vol = 1;
    }
    printf("vol = %d\n", vol);
    return 0;
}


int main(int argc, char *argv[])
{
    int vol = (argc == 1) ? 2 : 1;
    printf("vol = %d\n", vol);
    return 0;
}


これといった特徴はないコードだ。
argcを使ったのは、なんとなく最適化されなさそうだと思っただけだ。

結果を先に言うと、Bash on Windowsのgcc(gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609)では、最適化あり(-O1以上)にすると同じになった。
最適化するのであれば、どっちでもよいと思う。
何らかの理由で最適化しないのであれば、三項演算子の方が短くなった。



最適化無し(-O0)でコンパイルした結果。
右がif、左が三項演算子。

image

1と比較して一致しないならL2にジャンプして1を代入するという処理は同じだが、ifは直接-4(%rbp)に突っ込んでるのに対し、三項演算子は%eaxに突っ込んだ後で-4(%rbp)に代入している。
三項演算子のそれぞれで処理してレジスタに入れて、それを代入させる、ということだから、うん、確かにそういう動きですな。

2017年6月8日

[ios]NFCNDEFPayloadはベタのpayloadなのかな

iPhoneを持ってないし、今のところ買う予定もないのだけど、NFC関連のAPIがiOS11から載りそうだということなので、少し見ておく。
なお、いま(2017/06/08)はまだβ版なので、正式版になる頃には状況が変わっていると思う。

NFCが載ったiOSならどれでもいけるのかと思ったが、iPhone7以降ということで、iPhone6はダメらしい。
なんでだろう、ハード的にそうなってるのかな?


見ておく、といったものの、iOSの挙動を知らないし、Swiftも知らないので、雰囲気だけで読んでいきます。
(間違い多いと思うけど許してね、の別表現。)


https://developer.apple.com/documentation/corenfc

大きく4つに分かれている。

  • Reader Sessions
    • class NFCNDEFReaderSession
    • protocol NFCNDEFReaderSessionDelegate
    • protocol NFCReaderSessionDelegate
    • class NFCReaderSession
  • NFC Tags
    • protocol NFCTag
    • class NFCTagCommandConfiguration
  • NDEF Messages
    • class NFCNDEFMessage
    • class NFCNDEFPayload
    • enum NFCTypeNameFormat
  • Errors
    • struct NFCReaderError


classとprotocolというのが並んでいる。。。
Swiftのprotocolは、Javaのinterfaceみたいなものらしい。

全部羅列したら、何か分かるだろうか?

[Reader Sessions]
  class NFCNDEFReaderSession
    init()
    protocol NFCNDEFReaderSessionDelegate

  protocol NFCNDEFReaderSessionDelegate
    readerSession(didDetectNDEFs)
    readerSession(didInvalidateWithError)

  protocol NFCReaderSessionDelegate
    isReady
    begin()
    invalidate()

  protocol NFCReaderSessionProtocol
    isReady
    begin()
    invalidate()

  class NFCReaderSession
    delegate
    sessionQueue


[NFC Tags]
  protocol NFCTag
    isAvailable
    session
    type
    enum NFCtagType
      ISO15693

  class NFCTagCommandConfiguration
    maximumRetries
    retryInterval


[NDEF Messages]
  class NFCNDEFMessage
    record

  class NFCNDEFPayload
    identifier
    payload
    type
    typeNameFormat

  enum NFCTypeNameFormat
    absoluteURI
    empty
    media
    nfcExternal
    nfcWellKnown
    unchanged
    unknown


[Errors]
  struct NFCReaderError
    省略

わからんわな。

NDEFは、TNFまでは見分けてくれるけど、あとは自分で解析してね、というスタンスのようだ。
なお、NDEFのフォーマットというのはこういう感じだ。

image

まあ、ほぼそのままを渡してくれるので、あとはこれからURIだのTEXTだのSmartPosterだのを自分で解析するのだろう。
自由度が高いが、まあ単なるデータだからね。。。

BLEのペアリングだったり、WiFiのSSIDなんかもタグで読めるだろうけど、iOSってアプリからそういう設定ってできなさそうな気がするから、ありがたみは薄いのかな。
コピー・ペーストができるなら、貼り付けるだけで済むようにできそうだけど、なんとなくそれも許してなさそうな気がする。

2017年6月7日

[mbedTLS]マルチスレッドでは署名と検証は排他した方が良いのか?

全然そのつもりがなかったのだが、mbedTLSを使って作っていたライブラリをマルチスレッドで動かすことにした。
楕円曲線の署名して送信し、受信したら検証して別のデータをまた送信、というようなことを各スレッドで行うと思っておくれ。


ようやくベースができたので、手動でちょこちょこ通信させていたのだが、たまに検証に失敗することがある。
毎回ならロジックがどこかおかしいと思うのだが、たまに、なのだ。
まれに、というほどでもなく、比較的置きやすいのだが、少なくとも毎回ではない。

なんだ??


検証に失敗するからには、

  • 作った署名が間違っている
  • 署名の送信か受信が間違っている
  • 受信した署名までは正しいが検証で失敗している

のどれかなのだが、ログを出していてもどのスレッドが出しているのかうまく整理できず、何が悪いのかはっきりしない。。。
こういうときって、標準出力ではなく、せめてスレッドごとにログを吐くようにしておけばよいのだろうね。


mbedTLSのマルチスレッド動作については、ページがある。
Thread Safety and Multi Threading: concurrency issues - Knowledge Base - mbed TLS (Previously PolarSSL)

大ざっぱに読んで、MBEDTLS_THREADING_CとMBEDTLS_THREADING_PTHREADを有効にしたライブラリを作ればよいのだろう、と判断。
ただ、ecp.cにはTHREADINGのマクロがあるのだが、ecdsa.cの方にはない。
ヘッダを見ると、mbedtls_ecdsa_write_signature()は同じコンテキストだったらスレッドセーフじゃない、と書いてある。
ecp.cのmbedtls_ecp_mul()なんかもスレッドセーフじゃないというコメントが入っているが、こっちはmbedtls_mutex_lock()で排他しているのだ。

うーーん。。。。

中で呼んでいる関数のどこかで排他されているから大丈夫、というパターンかもしれないが、mbedtls_ecp_mul()なんかは「同じグループだとスレッド-セーフじゃない」といっているから、同じmbedtls_ecp_groupを使い回しているところが全体として危ないのかもしれん。
今回、mbedtls_ecp_groupは全員同じものを使っていいんじゃないの?と思い、開始時に設定したら解放せずに全員が同じものにアクセスするように作り込んでいたのだ。

その考え方自体が間違っているのかもしれんが、MBEDTLS_THREADING_Cなんて用意してあるくらいだから、そんなのしなくてもよいのかも。。。


わからんので、mbedtls_ecdsa_sign_det()やmbedtls_ecdsa_read_signature()は、mbedtls_mutex_lock/unlock()で囲むことにした。


そのおかげか、今のところ安定している。
でも、実はECDSAは直接関係なくて、その付近で使っている変数が問題だったり、あるいは単にタイミングが発生しにくくなっただけという可能性もある。


mbedtls_ecp_groupを共有していることの危険性が分かってないのよねぇ。
暗号化関係って、よくわからない計算をたくさんしているだけに見えてしまい、深く追いたくないのだ、そうもいっていられんのか。


2017/06/14

気になったので、mbedtls_ecp_keypair構造体の構成を見てみた。
mbedtls_ecp_groupではなくmbedtls_ecp_keypairなのは・・・ソースを見直すとkeypairの変数をグローバルで確保し、最初にloadして使い回していたからだ。

typedef struct
{
    mbedtls_ecp_group grp;      /*!<  Elliptic curve and base point     */
    mbedtls_mpi d;              /*!<  our secret value                  */
    mbedtls_ecp_point Q;        /*!<  our public value                  */
}
mbedtls_ecp_keypair;

あー、秘密鍵とか公開鍵をこの中で保持しているじゃないか!
こんな変数を使い回していたら、そりゃよろしくないですわな。。。
コメントにも「Members purposefully in the same order as struc mbedtls_ecdsa_context」となっているので、コンテキストが異なるスレッドからは使ってはいけない代物なのだ。


そういうわけで、毎回スタックでmbedtls_ecp_group_load()して使うようにした。
なんか、暗号化ライブラリって重たい処理をしていそうなので、使い回せるところは使い回した方がよいのではないかと考えてしまったのだ。
でも、それはそれでセキュリティ的によろしくないだろうから、考え直さないと。

[ios]Core NFC?

いつかなー、いつかなー、と思っていたiOSでのNFC APIだが、そろそろ使えるようだという話が出ている。

Apple adds support for NFC tags to iPhone 7 and Apple Watch • NFC World


APIはこちら。
まあ、実機を持ってないし、開発環境も無いので、見てみただけだ。

Core NFC | Apple Developer Documentation

Reading NFC NDEF tags is supported on iPhone 7 and iPhone 7 Plus.

だそうだ。


それはともかく、タイトルだけ見る限りはタグの検出とNDEFの読み出しができそうだ。

気になるのは「types 1 through 5」というところ。
えっ、いつの間にType5が出たの??

Type 5 Archives - NFC Forum | NFC Forum
あー、AndroidでいうところのNFC-Vか。


NFCは技術として好きなのだけど、NFC Forumが仕様書を会員以外には販売方式にしてから、どうにもやる気がなくなってしまった。
せめて、NDEFの仕様書とTypeの仕様書は公開してくれてもよいと思うのだが。。

2036年問題?

何気なく、2038年問題のことを調べていた。
正確にいえば、「2037年だっけ、2038年だっけ」を調べていたのだが、その途中で「2036年問題」というものを見つけた。


2036年問題とは - IT用語辞典 Weblio辞書

  • NTPは1900年1月1日を起点とした秒数で時間を表している
  • 範囲は、32桁の2進数
  • オーバーフローするのは、2036年2月6日0時54分54秒


あれ?
2038年問題の方を見てみよう。


2038年問題とは - IT用語辞典 Weblio辞書

  • UNIX環境では1970年1月1日0時0分0秒を起点とした秒数で時間を表している
  • 範囲は、31桁の2進数
  • オーバーフローするのは、2038年1月19日


ああ、符号付きかどうかの違いで70年近く差が出てくるのね。

マイナスになることもなさそうなのに、なぜ符号付きにしたのだろう?
当時の事情は知らないのだが、そういうコンピュータが多かったのかもしれん。


C言語だとtime_tで扱うのだけど、今は64bitになっているものが多いと思う。
もしかしたら、64bitのOSしか使っていないせいかも。
ただ、環境依存になることは仕方あるまい。

RTCなんかは割り切ってて、100年計測できるようになってるものが多かったように思うので、日付についてはアプリ管理だ。
昔はLinuxも32bitで扱ってて、どうせRTCチップ用にドライバ作るんだからということで、時計回りは別で扱うようになっていた。
便利なAPIは使えなくなってしまったのだけど、まあ、そういうのもありですな。


time_tの変数をポインタにして、uint32_tなんかでキャストし、またtime_tで直接ポインタから元に戻そうとすると変な値になってしまうから注意したまえ(2回くらいやらかした。。。)。

2017年6月6日

[cortex-m]SWVとRTTは別物だろうか

How to perform runtime error checking on Cortex-M devices


ARM Cortex-MにはSerial Wire Viewerというリアルタイムイベントを拾うことができる機能があるらしい。
最近は組込みから遠のいているものの、手元にあるのはCortex-Mが載ったマイコンかESP8266くらいしかないので、デバッグ手段は知っておきたいものだ。
Hard Faultなんかが拾えるような感じで書かれているので、それができるならありがたい。



CoreSight
Keilでは、Serial Wire Serialの略がSWVになっている。何でだ?
ともかく、SWOピンを使うようだ。
SWOだから、Outputだろう。


ARM Information Center
ARMのサイトも見たが、これといった情報はない。
SWOとなんか命令がセットになって使えるようなもののようだ。


KeilのページではULINKなどしか載っていなかったが、ARMのしくみならJ-Linkでも使えるはずだ。
SEGGER - The Embedded Experts - J-Link Debug Probes - Software - J-Link SWO Viewer
こちらは、SWO Viewerというアプリ。
コードを足してやらんといかんようだが、SWOの出力を拾えるようだ。
Keilとかだったら、printf()で書けるのかもしれん(見てない)。


そうなると、RTTとの違いが気になる。
RTTはSEGGERのJ-Linkでしか使えなかったと思うが、nRFシリーズではソースが入っていたし、手っ取り早く使える。
SEGGER - The Embedded Experts - J-Link Debug Probes - Real Time Transfer
これもSWOを使うようだ。


SWVとRTTの違いはどういうところにあるのか探していると、Atollicさんのブログがあった。
Using the SEGGER Real-time terminal (RTT) interface with Atollic TrueSTUDIO
ぱっと見て気付いたのは、双方向ということと、パフォーマンスが高い、あとはJ-Linkで使える、というところか(RTTのページにも書いてあるが。。。)。
J-Linkのみという制限はあるが、上記の特典が得られる、という見方がよいのかな。

キーボードなどからの入力は試したことがないので、やってみたいところだが、用途が思いつかない。。。
ときどきログを出力させたいとか、全部ログに出すと重たすぎるので、分割させたいとかか?

[c/c++]たぶん構造体メンバをvolatileにしても有効(弱気)

タイトルが弱気だが、致し方ない。


何がしたかったかというと、pthread_create()で動かしているスレッドでwhile()させてぐるぐる動かしている状態を、外部から止めたかったのだ。

スレッドで、whileで、変数監視となると、volatileになる。
普段はグローバル変数で監視させていたのだが、今回はスレッドをぽこぽこ作るようにしていたので、各スレッドが使う変数を構造体でまとめて初期値で与えつつ、そのままスレッドと共有する領域として使おうという計画だ。
おじさんはね、OSを使ったプログラムに慣れていないので、他に方法が思いつかなかったのだ。


その構造体の中に、ループを制御するための変数を持とうと思ったが、ちょっと迷った。
volatileって、構造体のメンバに指定しても反映してくれるのだろうか?


こういうときは、環境依存になってもよいから実験するに限る。


#include <stdio.h>

struct vol {
    int     abc;
    volatile int     def;
} volvol;


int main(void)
{
    while (volvol.def) {
        ;
    }
    return 0;
}

$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

こんな環境で試した。
なお、Ubuntuは16.04で、VirtualBox上で動かしている。
コンパイルはこのようにして、O2で最適化してアセンブラ出力させた。

$ gcc -O2 -o vol.S -S vol.c


まず、volatileありの場合。

	.file	"vol.c"
	.section	.text.unlikely,"ax",@progbits
.LCOLDB0:
	.section	.text.startup,"ax",@progbits
.LHOTB0:
	.p2align 4,,15
	.globl	main
	.type	main, @function
main:
.LFB23:
	.cfi_startproc
	.p2align 4,,10
	.p2align 3
.L2:
	movl	volvol+4(%rip), %eax
	testl	%eax, %eax
	jne	.L2
	rep ret
	.cfi_endproc
.LFE23:
	.size	main, .-main
	.section	.text.unlikely
.LCOLDE0:
	.section	.text.startup
.LHOTE0:
	.comm	volvol,8,8
	.ident	"GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
	.section	.note.GNU-stack,"",@progbits

ふーん。

次、volatile無しの場合。

	.file	"vol.c"
	.section	.text.unlikely,"ax",@progbits
.LCOLDB0:
	.section	.text.startup,"ax",@progbits
.LHOTB0:
	.p2align 4,,15
	.globl	main
	.type	main, @function
main:
.LFB23:
	.cfi_startproc
	movl	volvol+4(%rip), %eax
	.p2align 4,,10
	.p2align 3
.L2:
	testl	%eax, %eax
	jne	.L2
	rep ret
	.cfi_endproc
.LFE23:
	.size	main, .-main
	.section	.text.unlikely
.LCOLDE0:
	.section	.text.startup
.LHOTE0:
	.comm	volvol,8,8
	.ident	"GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
	.section	.note.GNU-stack,"",@progbits


差分は、ここ。
左がvolatileありで、右がvolatileなしだ。

image

L2ラベルでループしていて、volatileありはmovlがループ内に、volatile無しはmovlがループ外になった。

効いてる! 効いてるんだ!!


まあ、そもそもなんでvolatileが効かないかもしれないと思ったのか、という気もしてくる。
単に不安になっただけだ。
そういうことってあるだろう?


そういえば、gccとかって中間言語に吐き出してからリンカに掛けるとかだったから、アセンブラで安心するのは早いかもしれん。。。
いや、さすがにそこまでは疑わなくてもよいか。

2017年6月2日

[bc]スクリプト

たまにはBitcoinの記事も書いておかねば。
べ、別にネタに困ってるわけじゃないんだからね!


Bitcoinのブロックチェーンに載せるデータは、トランザクションが最小単位になる。
メッセージとしてはping/pongやgetdataなどいろいろとあるのだが、ブロックチェーンに載るものとしてはtxメッセージで送信するトランザクションが基本になるだろう。

トランザクションには、だいたいこういうデータが載っている。

    • トランザクションのバージョン
    • 送金元の情報
    • 送金先の情報
    • どのくらい待ってからマイニングできるようになるか


「送金元の情報」は、その前のトランザクションの「送金先の情報」とつながっている。
この意味に慣れるまで、私はけっこう時間がかかった。。。

銀行の送金だと、送金元が「いくら、誰誰に送金する」と指定して、送金先の人にその額が入る。
Bitcoinの場合、送金元が「いくらは誰誰に送金し、残りはこれこれに送金する」という記載の仕方をする。
例えば、誰かに0.1BTC送金する必要があったとしよう。
そして手元に1BTC使えるトランザクションを持っていたとする。
そうすると、

  • 0.1BTCを送金したい人に
  • 残りの0.9BTCを自分のお釣りに

という送金の仕方になる。

お釣りを、送金元と同じアドレスに指定することもできるのだが、セキュリティ的には推奨されない。
だから、だいたいは見た目として2つのアドレスに送金しているように見える。
初めてトランザクションを見たときには「なんで全部送らないといけないのよぉぉ」と思ったものだ。

そしてまた、トランザクションを作るときには手数料(FEE)がかかる。
先ほど0.1BTC + 0.9BTCのような書き方をしたが、実際にはこれにFEEが引かれて、0.89999BTCみたいな額になっていることだろう。

FEEの決め方はよくわかっていないが、トランザクションのバイト数が基準になっている。


で、スクリプトだ。

BitcoinにはEthereumほどの柔軟性はないにしても、スクリプトを書いて送金条件を作ることができる。
逆ポーランド記法というか、スタックにためながら演算していくのだ。


その演算は、大ざっぱに言えば、「前のトランザクションの送金先情報」と「それを送金元として使うトランザクションの送金元情報」がセットになって解くことができるスクリプトになっている。
私のイメージとしては、昔のウェスタンな取引で、お札をギザギザに破って取引相手に渡しておき、現場でそのギザギザがお互いに一致するかどうかで見分けるアレだ。


今のところ、この辺が使えるようである。
Script - Bitcoin Wiki

「今のところ」がつくのは、Bitcoinがトランザクションのバージョンによって使えるスクリプトが変わるからである。
例えば、NOP2やNOP3のような命令が、バージョン2ではOP_CLTVやらOP_CSVとして使えたりする。
Script - Bitcoin Wiki - Locktime


こういう、意味の使い方が変えられるという自由さが、仮想通貨のよいところだったり悪いところだったりするのだろう。

2017年6月1日

[c/c++]キャストで逃げる

コーディングするたびに発生して、毎回悩むのに答が出ない問題がいろいろある。

キャストで逃げるというのも、まだ私の中で解決していない。
たとえば、ポインタとサイズをセットにした構造体を作ったとしよう。

struct xxx {
  int len;
  uint8_t *ptr;
};

C言語だと、アドレスは分かってもサイズが分からないからね。


malloc()などでRAMを使う場合はこれでもよいのだが、const値のようにROMで持っているデータを使いたいとなると悩んでしまう。
ptrはconstが付いていないため、書き換え可能なように見えてしまうからだ。
構造体のインスタンスにconstを付けても、lenやptr自体は書き換えできないが、ptrが指す先はconstではないからね。
(最近もこういう話をどこかで書いたな。。。)


今回は、こうやって回避した。

struct const_xxx {
  int len;
  const uint8_t *ptr;
};

constになっている型をもう1つ用意したのだ。
これがあれば、RAMであっても書き換えるつもりがないことを表すこともできるし、大丈夫だ!


と思っていたのだが、また揺らぎだした。

これ、ポインタがプリミティブ型だからよいようなものの、構造体だったらどうだろうか?
その構造体の中にポインタが入っていて、それがconst無しだったら強制力がないだろう。

だったらもう、constにした構造体の中身は下の方に至るまで書き換えるなよ?とした方が潔くないだろうか。
証明するのは大変だが、テストコードで書き換え不可のアドレスを渡して不正メモリアクセスなどの例外が発生しないことを確認するくらいしかないか。

これにconstのアドレスを渡したい場合は、そのまま渡すとwarningが出るので、const外しキャストで逃げることになろう。
格好はよくないのだけど、他に方法が思いつかない。
warningのままにして気付かせるようにしておくのもありだが、warningをerror扱いにしたいこともあるし、何よりうっとうしい。
const_cast<>がないので検索もしづらいのだ。


うーん、いろいろめんどうだ。
何かC言語仕様の見落としがあるかなぁ。。。