2017年4月7日

[bc][slack]botを作ってみる

朝起きると、hiro99maは一匹の巨大な毒虫に・・・なってはいなかったが、なぜかslackのbotを作ってみたくなっていた。

仕事の連絡手段としてslackを使っているのだが、左上に「Apps」という項目があることに気付いた。
どうやら、プラグインのようなものと連携して、挙動を追加できるらしい。

ほほう!

そういえば、botというやつで何かできた記憶がある、と思い出し「slack bot」で検索しようとしたら、候補に「python」が出てきた。
pythonなら多少は使えるので、せっかくだから何か作ってみよう。

何がよいか・・・。
ああ、最近、仕事に関係しないbitcoinネタを書いているので、それにしてみよう。


PythonでSlackbotを作る(1) – ビットログ

一番上に出てきたので、これを参照した。
さすが一番上だけあって、読んでできた。

第1回で、botを使えるようにするまでできた。
API Tokenの取得などだ。
なお、私はpython2を使った。
素直に書いてあるbotの実装も試しておこう。

第2回を読めば、だいたいやりたいことがわかる。
私の場合は、こちらからBitcoinのTXIDを伝えて、blockexplorer.com(リンク先はtestnet用)みたいなサイトから情報を取ってきて、テキストで吐き出そうと思ったので、このくらいでよいのだ。


作ったのは、こちら。
https://github.com/hirokuma/slackbot_bitcoin_txid

API Tokenは自分で埋めておくれ。
あと、testnet用にしているので、必要に応じて修正しよう。
難しいことはやってないので、pythonがわかる人なら変更もすぐできるんじゃなかろうか。

 

困ったのは、むしろtestnetの挙動だった。
なんか、ちょうど作っている最中、攻撃が行われていたようなのだ。
やーねー、もう。

2017年4月6日

[bc]アドレスを作るまでの計算

前回は、Bitcoinのアドレス、と一言にいってもいろいろ種類がありますよ、ということを書いた。
そして、先頭の文字を見ると、だいたいどういう種類かや、お金に関わる方のBitcoinブロックチェーン(mainnet)なのか、お金が関わらない方のBitcoinブロックチェーン(testnet)なのかわかる、というところまで説明した。

 

わざわざ「Bitcoinのブロックチェーン」と書いているように、ブロックチェーンにもいろいろ種類がある。
というよりも、それぞれ別のブロックチェーンのネットワークを作っている。
例えば、mainnetとtestnetは、ブロックチェーンの構造としては同じだが、TCP/IPのポート番号が異なる。
Ethereumという、こちらも有名なブロックチェーンを使った仮想通貨があるが、これはこれで別のブロックチェーンだ。

「ブロックチェーン」という1つのものをみんなが使っているわけではなく、めいめいが自分が好きなようにブロックチェーンを作っているのである。


では、話を戻そう。

Bitcoinアドレスは、似たような文字列でできているように見えるが、そもそもどうやってアドレスを作っているのか、という話をしたい。

http://chimera.labs.oreilly.com/books/1234000001802/ch04.html
ここに全部書いてあるので、読むとわかる。

・・・ではあんまりなので、大雑把に説明しよう。
なお、私はtestnetでしかやってないので、説明もtestnetだ。

 

Pythonでの実装例がExample4-4に載っているので、それを見ていこう。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#_implementing_keys_and_addresses_in_python

まず、32byteの乱数を用意する。
16進数32個分だ。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#ec_math
Example4-6の、

byte_array = os.urandom(32)

がそれにあたる。
この値を「秘密鍵(private key)」と呼ぶ。

 

秘密鍵は単なる大きい値というだけで、この次に楕円曲線暗号というものが出てくる。
楕円、ではなく、楕円曲線、だ。
金魚鉢のような、オバQのO次郎を横向きにしたような、そんな形だ(Figure 4-2)。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#pubkey

楕円曲線にもいろいろ種類があるのだが、とにかくBitcoinで使用する楕円曲線上の点Gに、楕円曲線座標系での乗算を行うことで「公開鍵(public key)」が求められる(Figure 4-4)。
もちろん、点Gに掛けるのは秘密鍵だ。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#ecc_illustrated
この図では、G→-2G→+2G→-4G→+4G→-8G→+8G、という演算が行われている。
もし秘密鍵が「8」だったら、この8Gが公開鍵の座標になる。
なんで接線方向に移動したりX軸に直角に移動したりするの?と問われても、私にはわからん。。。

公開鍵は座標なので、(x, y)の形式になる。
ノーマル形式の公開鍵は、このxとyを連結した値になる。
秘密鍵が32byteだからか、xも32byte、yも32byteにするようで、連結すると64byteになる。
それだけだとなんだかわからないので、「0x04」を頭につけて「ノーマル形式の公開鍵」という表現の仕方をすることになっている。
だから、65byteだ。

ただ、楕円曲線を見るとわかるように、X軸に対して線対称だ。
では、X座標とそれに対応するY座標の正負情報だけで公開鍵を表して短くしよう、という説明がFigure 4-7だ。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#pubkey_compression
x座標からy座標を求める演算はy2 mod p = (x3 + 7) mod pになるため、y2を解くと±の結果になるから、どっちなのよ、ということを示すために、ノーマル形式の「0x04」に対して「0x02」 or 「0x03」という値を頭につけて、33byte形式にしたのが「圧縮された公開鍵」と呼ばれるようになっている。
今では、「0x04」の公開鍵はデータが大きくなるのでほぼ使われていないと思う。

 

公開鍵に、SHA256というハッシュ計算をすると、32byteになる。
それにRIPEMD160というハッシュ計算をすると、20byteになる。
理由は知らんが、Bitcoinではハッシュ計算を2回連続して行うことが多い。
ともかく、公開鍵をSHA256→RIPEMD160、という計算で出てきた20byteの値を公開鍵ハッシュ(Public Key Hash)と呼ぶ。
通称、PubKeyHash。
略称、PKH。

 

PKHに、前回出てきたmainnet/testnetのプレフィクスをつけ、CRCをサフィックスにつけ、それをBase58Checkというエンコード方式で演算すると、Bitcoinアドレスが出てくる。
Base64という、メール添付するときのエンコード形式から、目で見て見分けにくい文字を減らして58文字にしたのがBase58らしい。
Base58はハッシュではなくエンコード/デコードなので、今回で言えばBitcoinアドレスから公開鍵ハッシュまで戻すことはできる。
http://lenschulwitz.com/base58

 

公開鍵を公開鍵ハッシュにした値からアドレスを求めるので、このアドレス方式はPublic to Public Key Hash→P2PKHと呼ばれる(のだったと思う)。

このようにして、秘密鍵、公開鍵、公開鍵ハッシュ、Bitcoinアドレス(P2PKH)が得られる。
お疲れ様でした。

[c/c++][make]dependの解決

以前、こんな記事を書いた。

hiro99ma blog: [c/c++]Makefileのdependは名前一致なのか

ソースファイルの依存関係をMakefileに反映させるためにgcc -MMを使ったが、./のように関連とディレクトリを含むような書き方にするとダメだった、という話だ。

 

そして、同じ問題にまた遭遇してしまったのだが、対処するのにかなり時間がかかってしまった。
悔しいので、それっぽいものをgithubに上げることにする。

https://github.com/hirokuma/makefile_hello

 

 

しかし、dependだけではなく、makefileは書くのが難しいな。
今回だって、難しいことがしたかったわけではなく、ディレクトリをsrc, include, objectsに分けただけだったのだ。
Eclipseでプロジェクトを作るとうまいことやってくれるが、あれは偉大なのだな。
まあ、あれはあれで、うまくいかなかったら解決に時間がかかるのだが。。。

2017年4月5日

RFC 6979を使った結果がライブラリによって違った→私の間違いだった

2017/04/05更新:mbedTLSに問題がなかったので更新

突然のRFCだ。
ESP8266のこともやりたいのだけど、仕事の調査もあるのでね。。。
せっかくなので、書いても問題なさそうなところは使おう。


RFC 6979という、楕円曲線を使った署名についてのRFCがある。

RFC 6979 - Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)

私の把握では、

  • 楕円曲線暗号の署名の乱数って、面倒よね
  • そもそも、乱数が乱数かどうかなんてあやしいし
  • 別の署名で同じ乱数が使われたりすると、目も当てられないわ
  • じゃあ、いっそのこと、データによって乱数の値が変わるような計算式を作ってしまわない?
  • さんせいさんせい!!

というところだ。
RFC 6979に基づいた署名計算を行うと、乱数要素がなくなるので、毎回同じ署名結果が得られる。


それはよいのだが、この決定性署名(Deterministic Signature)を持つ暗号化ライブラリを使ったのだが、結果は乱数を使っていないので同じ結果になるものの、ライブラリによって得られる署名が異なることがあった。

やむなくRFC 6979を見てみたが、うん、全然わからん。。。
ただ、3.2章が「Generation of k」で、3.3章が「Alternate Description of the Generation of k」となっている。

Alternate Description ?
別の説明、ってなんだ?
3.2章で使った用語とは別の言葉(X9.62の用語か)で説明しているだけだとは思う。

たぶん、kは、ここの手順3の整数kだと思う。
「セキュリティ」のところにもそう書かれていた。
https://ja.wikipedia.org/wiki/%E6%A5%95%E5%86%86%E6%9B%B2%E7%B7%9ADSA#.E7.BD.B2.E5.90.8D.E7.94.9F.E6.88.90

 

一致しているライブラリは、先にnonceを求めてから署名を行っている。
nonceは、たぶんkのことだろう。乱数っぽいし。
困ったことに、一致していないライブラリは違う計算方法で、直接比較ができない。

mbedTLSなのだが、うーん、どうしたものか。。。
https://github.com/ARMmbed/mbedtls/blob/development/library/ecdsa.c#L72
nonceを作らず、f_rngでうまいことやるようなのだが、乱数っぽい値はtに入るようだし、kはkeypairとかから設定されているし、なんだかよくわからんのだ。


2017/04/05

この問題はけっこう大きいので、引き続き調査を行う。
まあ、違う実装を使えばよいと言えばよいのだけど、それでは負けた気がしてしまう。。。
mbedTLSは負けないのだ!

間違われないように書いておくが、署名が間違っているわけではないのだ。
verifyは成功する。
単に、署名が一致しないだけなのだが、それがあり得るのかどうかだけが気になっているのだ。

 

mbedTLSの実装でDeterministicっぽいことをしているのはここだと思う。
https://github.com/ARMmbed/mbedtls/blob/development/library/ecdsa.c#L178-L182

よくわかってないが、HMAC_DRBGという言葉が出てくるので、RFC6979の3.3章のような実装なのだろうか。
この辺で設定したrng_ctxを使ってECDSAの署名に使う乱数を作っているのだろうと思う。
呼び出すのは、mbedtls_hmac_drbg_random()。
これを使っているのが、L97のgen_keyapir()と、L121のfill_random()。
RFCと実装が一致しているのかを確認するのは、私にはちょっと難しい。。

でも、mbedTLSもちゃんとtestsuitesでRFC 6979に載っているデータのパターンはOKなのだよ。。。
だから、間違えているとは考えにくい。
例えば、RFCのA.2.3は、この辺がテストデータになっている。

 

全部正しいのに結果が違うということがあり得るとしたら、エンディアンじゃなかろうか?
RFC 6979にはbig-endianと書かれているけど、与えているハッシュ値がlittle-endianになっているからとか。
しかし、いろいろひっくり返したものの、署名は一致しなかった。

なんでだ??
そんなことあり得るのか???

 

わからなくなって、変更したところを元に戻し、自分のmbedTLSを使った処理を見直してみた。
あれ・・・署名計算だけしか見てなかったから気付かなかったけど、そもそもの署名計算に与えている値を間違えている・・・?
pythonで作ったのと同じパラメータになるように修正して・・・

あーーー、一致したーーーー
疑ってごめん、mbedTLS。
やっぱり私が間違っていたよ。。。

2017年4月4日

[esp8266][rtos]ほどよいMQTT client

せっかくESP8266でSmartConfigすれば外部からWiFi APの設定ができることが分かったので、なにか動くアプリを作りたい。
ただ、今はセンサも何もつないでいないので、定期的にどこかに送信する、程度のことができれば良い。

であれば、MQTT brokerに向かってpublishするだけ、というのが簡単そうな気がする。
ほどよいMQTT client APIがなにかあるだろう。


Pythonではpahoを使っていたが、そのC版をESP8266のRTOS版に移植したものがあった。
baoshi/ESP-RTOS-Paho: Port of Eclipse Paho C client on ESP8266

よさそうなのだけど、ちょっと大きいなぁ。
メモリに制限があるから大きなpublishをすることもないし、QoSも0しか使わないだろうから(publishにQoSあったっけ?)、v3.1くらいの内容であれば自分で実装してもよいかもしれない。

でも、既にできているプロジェクトを取り込むのも勉強になるし。
うーーーーむ。。。

 

そうか、両方やればいいんだ。
自分で作ると柔軟性も拡張性もないがサイズが小さなライブラリができるだろうから、それはそれで使い道があるかもしれない。
その後でPahoを移植したライブラリを組み込めば、あれこれできるようになるので、それもよいことだ。

むかし仕事で作った実装を見るのはさすがに反則だから、ちまちまやっていこう。

2017年4月3日

[bc]segwitのこと

Bitcoinで、segwitというのがある。
segwitは"Segregated Witness"の略なのだが、まあ語源はどうでもよい。
Bitcoinがハードフォークするとかしないとか話が出ているが、そういうのもどうでもよい。
私はsegwitの話をしたいだけだ。


取引の内容を表す「トランザクション」は単なるバイナリデータなのだが、いくつかの部分に分かれている。
部分の正式名称は、こんな感じだったと思う。

  • version
  • [marker]
  • [flag]
  • txin
  • txout
  • [witness]
  • locktime

カギ括弧を付けているものが、segwitで追加された部分だ。

 

そして、話が面倒なことに、作り方によってトランザクションに入れ込むデータが変わってくる。
ここではscriptPubKeyと書いたが、これはたぶんP2PKH向けの名前で、locking scriptという呼び方の方が正しいかも。
txout(txは"transaction"の略で、inが入力、outが出力)に書くスクリプトの部分だ。

  • segwitではないscriptPubKey
  • segwitで、データがちょっと長めのscriptPubKey
  • segwitで、データがちょっと短めのscriptPubKey

「ちょっと長め」ってなんだよ、となるが、これはsegwit対応していないウォレットアプリからでも送金先として指定できるタイプである。
見た目はP2SHなのだけど、中身はsegwit向けというやつだ。
通常がP2PKHとしたら、そのちょっと長めバージョンはP2WPKH nested in BIP16と呼ばれる。
データだけじゃなくて、名前も長い。。。

 

「ちょっと短め」ってなんだよ、ともなるが、これはsegwitに対応したウォレットじゃないと送金先に指定できない。
こっちは単にP2WPKHと呼ばれている。
nested inしている方のscriptPubKey(0xA914{20-byte-script-hash}87=23byte)に比べると、1byte小さい(0x0014{20-byte-key-hash}=22byte)ことがわかる。

これだけだと大差ないのだが、このトランザクションをInputとするトランザクションを作ると差が出やすい。
witnessに「<signature> <pubkey>」を置くのはどちらも同じなのだが、nested inの方はscriptSigに23byteのデータを置くことになっている。

 

ただ、ふつうのP2PKHと比べると、ちょっと短めの方でsegwitのトランザクションを作ったとしても、そっちの方がわずかにサイズが大きい。
nested inになれば、なおさらだ。
大ざっぱにsegwitのP2WPKHトランザクションを作ろうとすると、

  • ふつうのP2PKHみたいな構造を作る
  • [marker]と[flag]を追加する(+2byte)
  • scriptSigに置いていた<signature>と<pubkey>をsegwitに移動
  • nested in BIP16なら、scriptSigに代わりのデータを置く(+23byte ?)

というところか。
lengthの付け方がどうだったか忘れたので、1,2byteくらいは違うかも。
あと、署名の計算方法も変わるのだけど、サイズはほぼ同じだからいいや(サイズの範囲は非segwitと同じ)。

 

じゃあsegwitの何がうれしいかというと、トランザクション展性を抜きにすれば、ブロックに入れるときのデータ量が減らせる、ということだろう。
witnessの部分、P2WPKHなら<signature>と<pubkey>を取り外すらしい。<marker>と<flag>もかな?
これだけで110byteくらいあるから、トランザクションは大きくなるけどブロックに入れるサイズはだいたい小さくなる。
MultiSigみたいに署名が複数あると、効果が大きい。

 

ただ、segwitのトランザクションを作るには、INPUTのところがsegwitになってないとダメだ。
だからP2PKHアドレスの場合は、一度P2WPKHのアドレスを作ってそこに送金し、その次からがsegwitのトランザクションを作ることになる。

nested inだとscriptSigもブロックに入れないといけないので、もったいない。
そうなると、ウォレットアプリも対応しないとなぁ、となってくる。
署名の計算も、前のトランザクションを一部使うことになり、その検証も同じようなことになるので、P2PKHなどよりも面倒だ。


今回書いた内容も、BIPを見れば分かる範囲なのだが、私がsegwitのことを調べ始めたときは、

  • 署名を分離してcoinbaseに置く
  • サイズが小さくなる

くらいで、技術的なところは結局BIPを読むしかなかった。
そしてBIPがわかりづらいのよね。。。英語だし。。。

 

今ではsegwitに対応したBitcoinライブラリもあると思うので、これから始める人はそれを読んでいった方がよいのかも。

2017年4月2日

[esp8266]ESP-TOUCHのしくみ (3)

"android udp tethering"などのキーワードで検索すると、port forwardingのことがよく出てきた。
adb forwardコマンドでできると書いてあるので、何も考えずにやってみたが、やはりダメ。

 

android - UDP packets between WiFi-tethered device and WiFi tether provider? - Stack Overflow
単にばらまきたいだけだったのだが、そういえば作りとしては"234.xx.xx.xx"に送信しようとしていた。。。
Androidが取得しているIPアドレスは、"10.xx.xx.xx"みたいな番号なので、マスクで止められたのだろうか?
いや、それだったら、うまくいっているときは"192.168.xx.xx"みたいな番号だから、違うといえば違う。

 

えーっと、IPアドレスのクラスCは、192.0.0.X~223.255.255.Xまでらしい(入社時に購入した古い本より)。
じゃあ、234.xx.xx.xxはクラスCじゃないやん。
その次のクラスDは、224.0.0.0~239.255.255.255とのこと。
この中には入っている。
そして、クラスDはIPマルチキャスト用らしい。

 

5. IPマルチキャスト | TECHSCORE(テックスコア)
MulticastSocketというクラスがあるそうだ。
MulticastSocket | Android Developers
sending and receiving、と書いてあるけど、SmartConfigアプリには使われていないのだよなぁ。
とりあえず置き換えてみよう。
ちっ、DatagramSocketはSocketExceptionなのに、MulticastSocketはIOExceptionなのか。
そして、変更したが動かない。。。

 

http://stackoverflow.com/questions/6550618/multicast-support-on-android-in-hotspot-tethering-mode
setNetworkInterface()で送信対象のインターフェースを指定せよ、という回答が出てきた。
はいはい、やればいいんでしょう、やれば。。。

あ、送信された!

 

じゃあ、あとはBSSIDを取得するだけか。
http://stackoverflow.com/questions/33159224/getting-mac-address-in-android-6-0
うーん、取得はできたが、設定画面に表示されているWiFi MACアドレスと違う。。。
が、動かすと、ESP8266と通信できて、Nexus5のIPアドレス取得はできていないが、自分のIPアドレスはとれているから、うまくいったんじゃなかろうか。

 

使う人はいないと思うが、githubに上げておこう。
AndroidManifestなんかは、ほぼimportしたままになっているので、うまいことやっておくれ。
https://github.com/hirokuma/Esp8266SmartConfigTether

[esp8266]ESP-TOUCHのしくみ (2)

AndroidをテザリングさせてSmartConfigするとうまくいかない件。
ESP8266をSniffer modeにしようかと思ったが、たぶんAndroidからパケットが出てないか、変なパケットが出ているのだろうから、そっちを見ることにした。

困ったときのWiresharkなのだが、Windowsではいろいろ制約があってやりづらい。
VirtualBoxで動かしているLinuxで動かそうと思ったが、NATだと結局Windowsを経由するだろうから、USBドングルのWiFiモジュールを使うことにした。

 

が、ここで問題が。。。
Ubuntuのあるところから、rt8192cuのドライバは修正版を使わないとLinux自体死んでしまうようになっているのだ。
https://github.com/pvaret/rtl8192cu-fixes
別のPC(Native Linux)ではこの手順通りにやればうまくいったのだが、VirtualBoxでやっているためかうまくいかない。。。
dkms installのところで「/usr/src/8192cu/1.10がない」と怒られるのだ。
実際に、ない。
いろいろ試したが、普通にmake & sudo make installし、depmod -aして、blacklistファイルをコピーすればよかった。
困らせやがって。

 

動かしてみると、WiFiのAPに接続しているときはパケットが飛んでいるが、テザリングの時は出ていなかった。
出ていない画像は載せられないので、出ていたときの画像だけ載せよう。

image

AndroidのテザリングとUDPについて調べるべきなのか。。。

[esp8266]ESP-TOUCHのしくみ (1)

ESP8266のESP-TOUCHというか、SmartConfigというか、その辺のしくみを見ていく。
参考にするドキュメントは、これだ。

http://espressif.com/sites/default/files/documentation/30b-esp-touch_user_guide_en_v1.1_20160412_0.pdf

実は、以前も調べたことがあるのだが、深くは追っていなかったのだ。
hiro99ma blog: [esp8266]SmartConfig == ESP-TOUCH


まず、ESP-TOUCHとSmartConfigの関係だが、

  • Espressif's ESP-TOUCH protocol
  • Smart Config technology

ということで、Smart Configというのが方式の名前で、そこで使っているプロトコルがESP-TOUCHということらしい。
Espressif's、とあるので、ESP-TOUCHはEspressif独自だと思って良いだろう。
AirKissというプロトコルも使えるので、Smart ConfigではESP-TOUCHかAirKissが使える、ということになるのか。

今回はESP-TOUCHのみ見ていく。

 

APIは開始と中断、あとはタイムアウト時間設定とバージョン取得くらいか。
プロトコルでどれを使うのかを設定するAPIもあり、開始前に呼んでおくとのこと。
サンプルは設定していないので、デフォルトはおそらくSC_TYPE_ESPTOUCH_AIRKISSだ。

smartconfig_start()すると、あとはコールバックで進んでいく。

image

ESP8266のアプリとしては、SC_STATUS_LINKでwifi_station_set_config()するくらいしかやることがない。
起動してWiFi APと接続できなかったらSmartConfigモードになる、とか、ボタン押したらSmartConfigモードになる、というのが望ましいか。

 

さて、start()すると、ステータスはFIND_CHANNELまでは進むのだが、Nexus5をテザリングさせたままやると、次に進めなかった。
通信できなかったからだとは思うのだが、そもそもどうやってAndroidアプリと通信しているのだろうか?

ドキュメントでは、UDPを使っていると書かれている。
説明図は、こうなっていた。

image

このパケットは、本で調べるとIEEE802.3フレーム形状というもののようだ。
UDPかどうかは"DATA"の部分に載ると思うので、ESP-TOUCHとしてはEthernetパケットに載せているのだろうか?
あるいは、UDPのデータとしてこれが入っているのだろうか。
IEEE802.11標準だとアドレスが4つくらい入っているようだから、データ部に載せる・・・?

いや、Interface誌2012/11月号を読むと、送信側はアドレスとして「自分・AP・相手」を必要とするが、APはそれを受け取って流すときは「自分・相手」だけにしてしまうようだ。
ということは、SmartConfigアプリが自分をAPとして送信する?

そもそも、何も設定していない状態でどうやって希望する無線を見つけ出すのだろうか。
WPSで設定できるのだから、何か手段はあるはずだ。
ただ、なんとなくだが、Androidアプリからそんな深いパケットは制御できないような気がするのだ。
うーーーん。。。。


動かしながらやった方が早そうだ。

おそらく、AndroidアプリのConfirmボタンを押して送信開始するのは、ここだ。
違ってたら、済まん。

https://github.com/EspressifApp/EsptouchForAndroid/blob/master/src/com/espressif/iot/esptouch/udp/UDPSocketClient.java#L97

データを見てみると、0x31をひたすら送っている。
プリアンブルか?
ログでは"send gc code"となっている。ソースのコメントは"send guide code"となっていた。

https://github.com/EspressifApp/EsptouchForAndroid/blob/master/src/com/espressif/iot/esptouch/protocol/EsptouchGenerator.java#L30
gcがguide code、dcはdata codeを指しているようだ。

guide codeを流し続けて、相手が応答したらdata codeを流すのかと思ったが、どうもguide codeとdata codeを交互に流しているようだ。

  • WiFi AP接続中で偽パスワードだと、UDP受信しない
  • WiFi AP接続中で空パスワードだと、UDP受信しない
  • WiFi AP接続中で正しいパスワードだと、UDP受信する

という動きをしたので、ESP8266が応答したらデータを投げるのではなく、とにかくデータを投げ続けて、ESP8266が設定できたら何か送信するので応答できる、という作りのようだ。

 

ということは、テザリングしているときは相手が受け取れていないか、自分がうまく送信できていないかのどちらかだろう。
ドキュメントを読むと、ESP8266はSniffer modeを使っているらしい。
Sniffer modeは使ったこと無いのだけど、無線が出ていたら読み取ってくれるようになってるのではなかろうか。

UDPの送信先は、IPアドレスが"234.xx.xx.xx"(xxはカウント値で毎回変わる)、ポート番号は7001になっている。
これが出ていないのか、受け取れていないのか。
そもそも、テザリングで作ったアクセスポイントをWiFiのアクセスポイントと一緒にして良いものなのか。。。

 

うーん、Sniffer_DEMOを動かしてみた方が良いのか。
長くなってきたので、今回はここで打ち切ろう。

2017年4月1日

[android]WiFiテザリング中だったらSSIDを知りたい

ESP8266のSmartConfigを使えるようになっておきたい。
Androidの設定アプリから、今つないでいるWiFiのAPを登録することはできた。
WiFiがない場所でも、Nexus5のテザリングで使えるようにしたいのだが、動かすと<unknown ssid>になり、アプリが死んでしまった。

面倒だが、対応できるのかどうか調べてみよう。


http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/wifi/java/android/net/wifi/WifiManager.java#1541

WifiManager#getWifiApState()なり、isWifiApEnabled()なりを使えば、テザリング中かどうかを知ることはできるらしい。
@hideなので今後はわからんが、Android 7.1.1まではありそうだ。
あ、Android7では@SystemApiとかいう修飾が付いてるから、制限されるのかも。
持ってないので知らん(Java reflection is impossible、と書いているから、できんのかも)。

名前からすると、getWifiApConfiguration()で情報がとって来れそうだが、SmartConfigアプリと違ってWifiConfigurationを返す。
まあ、SSIDだけわかればよいから、問題なかろう。

幸い、reflectionしたサンプルがstackoverflowにあったので、使わせてもらう。
http://stackoverflow.com/questions/10850936/android-tether-get-current-ssid


テザリングしていたら、という条件を入れようかと思ったが、今のところ「<unknown ssid>」という文字列になっているから、その場合だけWifiApから取ってくることにした。

 

Javaが、ハードTABでインデントしているので、置換。
これでたぶんできたんだと思う。自信はないが。。。

$ find ./ -name "*.java" -exec sh -c 'expand -t 4 {} > $$$ ; mv $$$ {}' \;

 

よし、と実行すると、SSIDはテザリングの設定画面で入力していたものが表示された。
よしよし、と進めると・・・やはり死んでしまった。
どうやら、BSSIDがnullだったためのようだ。
無線LAN - BSSIDとESSID
通常は、BSSIDはMACアドレスと同じ、ということだったので、Nexus5の端末情報からWiFi MACアドレスを見て、まずはコード埋め込みにして動作確認することにした。

うん、BSSIDを入れておくと、死ぬことはなくなった。
が、ESP8266がNexus5を見つけられないのか、コンソールには何も出ない。

 

なんとなくだが、SmartConfigはWiFiクライアント同士が通信するようなものになってるのではないだろうか?
だからAPになったNexus5からはうまくいかない、と。

面倒だが、SmartConfigがどういうしくみなのかを調べる段階に来てしまったようだ。