Mac専用バッテリーHyperMacを復活させる

HyperMacの寿命はどのくらいなのか

1年ほど前に購入したHyperMacですが、フル充電しているにも関わらず1分くらいでバッテリーが無くなってしまうようになりました。
そんなに使用回数は多くなかった気がします。少なくとも1000回は使っていないでしょう。
使用中は、火傷しそうなくらい熱くなったりしたので色々気になる所はありました。

こんな記事もあるようです。
http://blog.goo.ne.jp/portaledge/e/a3b352cf4e20f7d16ad37d548e5b9809

しかし、Macで使用出来る外部バッテリーはほとんどありません。自分が知っている限り、まともに使えるのはHyperMacくらいなのではないでしょうか。
ちなみにMBP-060とMBP-150を同じ時期に購入しましたが、偶然なのかどちらも使えなくなってしまいました。

まともな外部バッテリーが出てこないのはなぜか

どうしてまともな外部バッテリーが出てこないのか、それはMac独自の電源コネクタ「MagSafe」によるものです。Apple社は、この「MagSafe」の特許を取得しており、他社に対してライセンスする気がないようです。

ではなぜ、HyperMacは「MagSafe」を使用できているのか。Apple社からライセンスを受けている訳ではありません。純正品のMagSafe電源アダプタを加工し、流用することで、ライセンスの問題をクリアしているという事のようです。

中国企業らしいアイディアではありますが、ついにApple社から目をつけられたようです。
Apple、外部バッテリーメーカーを訴える|KODAWARISAN

今後、HyperMacはどうなってしまうのか心配ですが、現在持っているHyperMacを大事に使っていきたい所です。純正の外部バッテリーが出てくれれば、それが一番いいような気もしますが・・・。

外部バッテリーの寿命を延ばすには

大事に使っていきたい所ですが、所詮バッテリーは消耗品なので、時間が経てば使えなくなってしまうのは当然です。ではどうすれば、バッテリーの寿命を少しでも延ばす事ができるのでしょうか。

まず自分の反省を踏まえ、どうしてこんなに早くバッテリーがダメになってしまったのかを考えてみました。

  1. 日差しが入ってくるような室温が高い場所に放置していた。
  2. すぐ使えるように充電コネクタを挿し、いつもフル充電状態にしていた。
  3. 実は1000回近く使っていた。
  4. バッテリーセルが中国クオリティ。

さすがに購入して1年程度で毎日使うような事もしませんでしたので、3.はないでしょう。4.については、中国企業なので、中国製のバッテリーセルを使っていてもおかしくありません。中国製と日本製のものでどこまで品質に差があるのかというのも、素人の僕としては分かりません。

バッテリーの保存環境や使い方によって寿命に変化があるのかが一番気になる所ですが、下記のような衝撃的なサイトを発見しました。

リチウムイオンバッテリー考

「この(リチウムイオン電池の)劣化は満充電で保存すると激しくなり、また保存温度が高いほど劣化が早くすすみます。リチウムイオン電池を長期保存するときにはできるだけ冷暗所に保存し、あまり充電しない状態で保存することをお勧めします。」

長期保管
 例えば、iBookラボを学校で管理していて、夏休み中は使わないなど、ノートブックコンピュータをしばらく使う予定がない場合、アップルではバッテリーを50%充電した状態で保管しておくことをお勧めします。

 もし、バッテリーが完全にゼロになった状態でノートブックコンピュータを保管すると、深い放電状態となり、充電ができなくなってしまう可能性があります。

 逆に、フル充電の状態で長期保管すると、バッテリー容量が失われる、つまり、バッテリーの耐用年数が短くなる可能性があるのです。それを防ぐには、PowerBookiBookのバッテリーを取り出して、適温範囲内で保管しましょう。

自分の使っていた環境と合致します。一番衝撃的だったのは「満充電で保存すると劣化が激しくなる」という記述です。外部バッテリーという性質上、常にフル充電状態にして保存している人は多いと思いますので、一番気をつけなくてはいけない所でしょう。

どうすれば少しでも寿命が延ばすことができるかをまとめると

  1. 温度が高い場所で保存せず、涼しい冷暗所で保存する。
  2. フル充電状態にして放置しない。
  3. 使用頻度に間がある場合は、50%程度充電し使用する際にフル充電するようにする。
  4. 過放電を防止するために長期間使用していなかった時は、たまに充電してあげる。

色々気を使わなくてはいけないようで少したいへんそうですね・・・。

バッテリーの寿命を復活させる方法はあるのか

どうすれば寿命を延ばせるかという観点で書いてきましたが、自分のバッテリーは既にお亡くなりになっているので、今さら寿命がどうとか言っても仕方ありません。
円高なのでまた海外から買ってもいいのですが、「バッテリーセルが中国クオリティ」という不安要素を排除することはできません。
そこでバッテリーを復活させる事ができないか調べた所、バッテリーセルを交換することで復活させる事ができるようです。

そもそもバッテリーセルとは何なのか

自分も詳しくないので分かりませんが調べた感じだと、セルというのは電池の事であり、バッテリーとはこのセルの集合体という事のようです。
要するにセルを交換するという事は、バッテリー内部の電池を新しい物に交換するという事になります。
電池なら自分で替えられるのではないか、と思う人もいるかもしれません。バッテリーの内部は若干複雑になっており、リチウムイオンの場合、充電・放電に対して制御を必要とし、制御基板と繋がっているようです。
自己責任で替えておられる方がいるようでしたが、とても怖くて自分で交換する事はできませんでした。

バッテリーセルを購入する場合、数千円程度で購入できるようです。
※自分で交換をする事を推奨しているわけではありません。自分で交換する場合は、必ず自己責任でおこなってください。
ロワジャパン バッテリーバンク  デジカメ携帯パソコンバッテリー・充電器

バッテリーセルを交換してみる事に

そこで今回はバッテリーリフレッシュサービスを利用する事にしました。バッテリーリフレッシュサービスとは、バッテリーのセルを新しい物に交換してくれるサービスで、ベイサンという所が最大手のようです。
ソフマップなどでも受付代行をおこなっているようです。

今回は利用したのはベイサンではなく、バッテリーリフレッシュという別の業者にお願いしてみる事にしました。
バッテリーリフレッシュ・セル交換の専門店

当然HyperMacは一覧に載っておりませんでしたので、見積りをお願いしてみることに。掲載されているバッテリーを見てみると、純正品と大差がない物もありましたので、海外から購入するより安ければいいなという感じでした。その後、ベイサンでも交換可能か問い合わせた所、対応不可との事でした。

実際に見積りをお願いしてみた結果を踏まえてまとめてみました。

直接購入(Cableなし$-30.95) バッテリーリフレッシュ ベイサン
MBP-060 14,365円 11,890円 対応不可
MBP-150 31,365円 29,890円 対応不可

※$1=85円で計算

送料などを考慮するとバッテリーセルを交換した方が安く済むようです。また、バッテリーリフレッシュさんでセルを交換した場合、元の単セルあたり2200mAhに対して、日本製のセルになり2600mAhと容量までアップします。

このサービスで一点注意しないといけないのは、「バッテリーセル」のみを交換するサービスだという事です。動作確認や保証はおこなっておらず、動作を保証してくれるわけではないという事に注意しなくてはいけません。
※リフレッシュサービスにお願いする際も必ず自己責任でおこなってください。

HyperMacのmAhとは

HyperMacのバッテリー容量(mAh)ですが、公式サイトを調べても一切記載されていません。おそらく、充電する端末ごとに使われる電圧が違うため記載されていないのかもしれません。
ここでふと気づいたのですが、外部バッテリーでよく書いてある「8000mAh」などの記載は、電圧ごとに変わるのであって、これはアテにならないと今ごろ気づきました。多くの場合は、3.7V換算での値を表記しているみたいです。

以下のような計算で求められるようです。
Wh x 1000 / V = mAh

とりあえず、3.7V換算で計算してみました。

Energizer XP18000 68Whくらい? 約18000mAh
MBP-060 60Wh 約16000mAh
MBP-100 100Wh 約27000mAh
MBP-150 150Wh 約40000mAh
MBP-222 222Wh 約60000mAh

こうして見てみると、HyperMacはすごいバッテリー容量です。
ちなみにMacBookPro13インチで、システムプロファイラの「電源」から確認した所、12494mV(12Vくらい?)で、4951mAhと表示されていました。MBP-060の公称では、1.0倍長く使えるとの事なので合っているのか計算してみました。

60Wh x 1000 / 12V = 5000mAh

4951mAhと近い数字が出たので計算方法は間違っていないようです。このような感じで、使用する端末ごとに使われる電圧を調べて計算してみると、どのくらいバッテリーが持つのか計算することもできるでしょう。

バッテリーリフレッシュしたバッテリーはちゃんと使うことができるのか

まだ交換したバッテリーが届いていないため、ちゃんと使うことができるかは分かりませんが、届き次第またレポしたいと思います。HyperMacのこれからが分からない状況なので、少しでも寿命を延ばせるように使ったり、使えなくなってしまったらどうすれば良いかを考えるいい機会になりました。
HyperMacを使っている人は参考にしてみてはどうでしょうか。
※バッテリーセルを交換する場合は、くれぐれも自己責任でお願いします。

実際に交換してみた記事はこちらから。
HyperMacのバッテリーセルを交換してみた – フタなしカンヅメ

tarボールソースからインストールしたソフトを管理する「Graft」を使ってみる

ソースインストールした物を管理するツール「Graft」をインストールして使ってみたので、記録として残しておきます。

インストールと言っても簡単で、配布元サイトのドキュメント通りに実行すれば問題ありません。
配布元サイト
graft.html – peters

$ wget -O graft-2.4.tar.gz "http://peters.gormand.com.au/Home/tools/graft/graft-2.4.tar.gz?attredirects=0"
$ tar zxvf graft-2.4.tar.gz
$ cd graft-2.4
## ここでエラーがでます。
$ make -f Makefile.dist
######################################################
#                                                    #
#       You'll now need to modify the Makefile       #
#      variables to suit your local conditions.      #
#                                                    #
######################################################
make: *** [Makefile] Error 1
## エラーが出るので、Makefileを編集する必要があるようです。

Makefile

このPACKAGEDIRがパッケージ管理用のディレクトリになり、ここにソースからインストールします。
PACKAGEDIR	= /pkgs
TARGETDIRは、通常インストールしたい場所、つまり/usr/localなどを指定します。
# TARGETDIR	= /pkgs
TARGETDIR	= /usr/local
Perlコマンドの場所を指定します。/pkgs/bin/perl となっていますが、ほとんどの場合、/usr/bin/perl に設置されていると思いますので変更します。
# PERL		= /pkgs/bin/perl
PERL		= /usr/bin/perl

あらためてビルドします。

$ make clean
$ make
# sudo make install
## graftがインストール出来ていることを確認。
$ ls /pkgs
graft-2.4
## graft自身を/usr/local/bin配下にインストール
# /pkgs/graft-2.4/bin/graft -i graft-2.4
## シンボリックリンクされていることがわかる
$ ls -l /usr/local/bin
lrwxrwxrwx  1 root root 25 7月 30日 09:23 /usr/local/bin/graft -> /pkgs/graft-2.4/bin/graft

これでインストールは無事に完了しましたので、さっそく使ってみます。
今回は、試しにrubyをインストールしてみました。

$ wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p299.tar.gz
$ tar zxvf ruby-1.8.7-p299.tar.gz
$ cd ruby-1.8.7-p299
$ ./configure --prefix=/pkgs/ruby-1.8.7-p299 && make
# make install
## 無事にインストール出来たことを確認
$ ls /pkgs
graft-2.4  ruby-1.8.7-p299
## graftコマンドでインストール
# graft -i ruby-1.8.7-p299
$ ls -l /usr/local/bin
lrwxrwxrwx  1 root root 30 7月 30日 09:27 /usr/local/bin/ruby -> /pkgs/ruby-1.8.7-p299/bin/ruby

rubyをアンインストールしてみる。

# graft -d ruby-1.8.7-p299
EMPTY        /usr/local/lib/ruby/1.8/bigdecimal/ is now empty. Delete manually if necessary.
EMPTY        /usr/local/lib/ruby/1.8/cgi/session/ is now empty. Delete manually if necessary.
...

一部ディレクトリが残ってしまっていますが、-Dオプションで実行することで、空のディレクトリも削除してくれるようです。

アップデートを想定して、ruby1.9系を入れてみることにしました。
アンインストール後に、インストールしても問題ないかと思いますが、今回はPruneという機能を使ってみます。これは既存のファイル群との衝突を回避するために、末尾に.prunedを付けたファイル名にリネームしてくれるものです。

## まず1.8.7をインストール
# graft -i ruby-1.8.7-p299
$ /usr/local/bin/ruby -v
ruby 1.8.7 (2010-06-23 patchlevel 299) [i686-linux]
## 1.9.1をダウンロード、インストール
$ wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p429.tar.gz
$ tar zxvf ruby-1.9.1-p429.tar.gz
$ cd ruby-1.9.1-p429
$ ./configure --prefix=/pkgs/ruby-1.9.1-p429 && make
# make install
## graftコマンドでrubyを1.8.7から1.9.1にアップデートします
## アンインストール前に新しいバージョンの物をインストールしようとすると、衝突としてエラーが表示されます
# graft -i ruby-1.9.1-p429
CONFLICT     /usr/local/bin/erb is linked to something other than /pkgs/ruby-1.9.1-p429/bin/erb (/usr/local/bin/erb -> /pkgs/ruby-1.8.7-p299/bin/erb)
# graftコマンドを-pオプションで実行してみると、ファイル名の後ろに.prunedとリネームされているのがわかる
# graft -p ruby-1.8.7-p299
$ ls -l /usr/local/bin
lrwxrwxrwx  1 root root 30 7月 30日 09:39 /usr/local/bin/ruby.pruned -> /pkgs/ruby-1.8.7-p299/bin/ruby
# あらためてインストール
$ graft -i ruby-1.9.1-p429
## 1.9.1がインストールできていることを確認
$ ls -l /usr/local/bin
lrwxrwxrwx  1 root root 30 7月 30日 10:02 /usr/local/bin/ruby -> /pkgs/ruby-1.9.1-p429/bin/ruby

いくつか気になった点がありました。

  • 衝突回避のためにリネームされた.prunedファイルを消せない。

 (-pオプションで実行させる度に、上書きされるようなので問題なし?)

  • 設定ファイルも一緒に上書きされそうなので、.graft-exclude

や.graft-includeなどを使って、必要なものだけインストールするように調整する必要があるかもしれません。(未検証)

非常にシンプルに出来ていて簡単に使うことが出来るので、ごちゃごちゃとした余計な機能はいらない、という人にとってはオススメです。
あとは、ソースからインストールしたものが/pkgsに溜まっていくので、前のバージョンにすぐに切り替えたりといった事もできます。

tarボールからインストールしたものを管理

最近はほとんどのものがパッケージで提供されており、ソースからわざわざインストールする機会もずいぶん減った気がします。
しかし、中にはソースからインストールしないといけない場合もあるかと思います。
自分はApachePHPなど主要なソフトは、ソースからインストールする事が多いです。

今までは、バージョンアップさせる度にバカの一つ覚えと言わんばかりに、make && make installをひたすら叩きまくっていたわけです。
バージョアップしたはいいけど、おかしくなったらすぐ戻せる環境がベストだと思い、ちょっと色々調べてみました。

僕が理想とする機能は、

  • ソースから入れたファイル群を管理できる
  • バージョン毎にインストールしたものが管理できる
  • 前のバージョンに戻せる
  • コマンドから削除ができる

paco

まず最初に見つけたのがpacoです。
これはほぼ理想通りで、欲しい機能がほとんど揃っていました。なにより、使っている人が多くて、実績という点でも安心できそうです。
一つ気になった点は、前のバージョンに戻すような履歴管理が簡単ではなかった点です。
軽く調べた感じだと、pacoballというコマンドで、今のバージョンをtarボール化し、新しいバージョンの物を入れるという感じになりそうです。

インストール

## -Dオプションでカレントディレクトをパッケージ名として利用します
# paco -D make install
## -pオプションでパッケージ名の指定が可能
# paco -p "app-1.4.1" make install

アンインストール

# paco -r app-1.4.1

その他

## インストール済みソフトの一覧表示
# paco -a
## 共有ファイルの表示
# paco -fc app
app-1.4.1:
/usr/local/app/conf/local.conf
## インストールした日を表示
# paco -dd app
01-Sep-2008 18:46  app-1.4.1
## configureオプションの表示
# paco -o app
--disable-hoge --enable-extension
## 現在のバージョンをtarボール化
# pacoball -b app-1.4.1
app-1.4.1.paco.tar.bz2
## tarボール化したものに戻す
# tar jtvf app-1.4.1.paco.tar.bz2

参考
Pacoでソースからインストールした物を管理する – WapBox
paco – a source code pacKAGE oRGANIZER for Unix/Linux
pacoでソースから導入したパッケージを管理する | Glide Note – グライドノート

Graft

次に見つけたのがこのGraftです。
pacoより機能面では劣るものの、ずいぶん昔から存在していたようです。
しかし、使ってる人の情報がほとんどない・・・。非常にシンプルが故に簡単に使うことができます。
衝突回避のためのPruneという機能がユニークです。

インストール

# graft -i app-1.4.1

アンインストール

# graft -d app-1.4.1

その他

## 衝突回避のためのPrune機能。既存ファイルが.pruned拡張子にリネームされる
# graft -p app-1.4.1

Graftの詳細記事はこちら
tarボールソースからインストールしたソフトを管理する「Graft」を使ってみる – フタなしカンヅメ

Stow

次は、Stow(すとーんと読むのかな?)です。
これもけっこう有名な物のようで、色々なサイトで紹介されていました。
モデルとしてはGraftと似ているようですが、Graftより機能が少ないようです。
たぶんこっちのStowのほうが古い。

インストール

# stow -t /usr/local/bin app-1.4.1

アンインストール

# stow -D app-1.4.1

その他

## 既存のファイルを更新した時の再処理(再読込)
# stow -R app-1.4.1

調べてみた感じだと、paco >> Graft >> Stowという印象です。後発であるpocoは機能面で優れており、色々便利な機能がたくさんあるので、新しく使うならpocoが良さそうです。
シンプルで最小限の機能だけで十分ということであれば、Graftがよさそうです。

RPMのDBがぶっ壊れた

いつものようにyumでパッケージを更新しようとしたらハングしてしまう。

# yum update
Loaded plugins: fastestmirror ## ここで止まってしまう

再起動して、またアップデートを実行してみたら、今度は次のようなエラーが表示された。

# yum update
error: rpmdb: damaged header #1304 retrieved -- skipping.
エラー: rpmdbNextIterator: スキップします。 h#    1304 タグ[60]: 異常です。tag 33281 type 4 offset 42564 count 1

またyumのキャッシュがおかしくなったのかと思い、yum clean allを実行してみたが同様にハングしてしまう。調べてみた所、RPMのDBが壊れているようで、DBを再構築することで対応できました。

# rpm --rebuilddb
zsh: segmentation fault  rpm --rebuilddb ## 一度目はこんなエラーがだた。
## /var/lib/rpm/ 以下のファイルをバックアップして、削除後にもう一度実行。
# rm /var/lib/rpm/*
# rpm --rebuilddb

参考サイト
RPM DB リビルド – まーのすけRoom
404 Not Found | Web、スマートフォンのオフショア開発 バイタリフィ

iptablesのセッション管理テーブルの上限を上げる

下記のようなログが出るようになったので、調べてみるとiptablesのセッション管理テーブルを使い果たすと出てくるエラーみたいです。

Jul 24 19:25:44 www-02 kernel: printk: 39 messages suppressed.
Jul 24 19:25:44 www-02 kernel: ip_conntrack: table full, dropping packet.

下記のURLを参考にnet.ipv4.ip_conntrack_maxの上限を上げてみたところ、エラーは出なくなった。とりあえず、これで様子見。

処理するセッション数が増えると、突然通信できなくなる(又は検査できなくなる。)(ip_conntrack数の変更) – 覚え書き Plus!

fon2405EルータにDD-WRTを入れる

iPadを買った時にfonという無線ルータをもらいました。どうせなので、色々いじってみたいと思い、改造ファームウェアを入れてみることにしました。

ファームウェアを書き換えるには、シリアルケーブルで接続する必要があるようで、fonの基盤に直接ケーブルをハンダ付けします。
SSHやtelnetなどの接続も試みましたが、このfonでは無理なようでした。
下記サイトを参考にしました。
unix is mine oyster, which I with code will open!: FON2405Eの中身
FONルータ復旧大作戦 | このいえ
DD-WRT – FoNまとめwiki
[FON] –  
Hot Tuna Labs

今回用意したのは、9-KEというシリアルケーブルと、fon本体のみです。9-KEは、ネット通販で送料込み数百円くらいでした。
ちなみにハンダ付けは今回が初めてで、以前から電子工作に興味があったので、これを機会にやってみようと思ったわけです。

なんとか取り付けることができ、シリアル経由でコンソールに繋いでみた所、起動ログがちゃんと流れてきました。ちょっと感動。

こんなログが流れてきました。

U-Boot 1.1.3 (Jan  6 2010 - 07:10:30)
Board: Fonera
DRAM:  32 MB
relocate_code Pointer at: 81fac000
spi_wait_nsec: 3e
spi deice id: c2 20 15 c2 20 (2015c220)
find flash: mx25l1605d
raspi_read: from:41030000 len:1000
Using default environment
##### The CPU freq = 320 MHZ ####
SDRAM bus set to 16 bit
SDRAM size =32 Mbytes
Please choose the operation:
1: Boot system code via Flash (default).
2: Load system code then write to Flash via TFTP.
3: Entr boot command line interface.
booting from flash
## Booting image at bf020000 ...
raspi_read: from:20000 len:40
Image Name:   MIPS OpenWrt Linux-2.6.21
Created:      2010-02-11   8:09:34 UTC
Image Type:   MIPS Linux Kernel Image (lzma compressed)
Data Size:    613723 Bytes = 599.3 kB
Load Address: 80000000
Entry Point:  80000000
raspi_read: from:20040 len:95d5b
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
No initrd
## Transferring control to Linux (at address 80000000) ...
## Giving linux memsize in MB, 32
Starting kernel ...
LINUX started...
THIS IS ASIC
Linux version 2.6.21 (blogic@blap4) (gcc version 4.1.2) #143 Thu Feb 11 09:09:18 CET 2010
The CPU feqenuce set to 320 MHz
CPU revision is: 0001964c
Determined physical RAM map:
memory: 02000000 @ 00000000 (usable)
Built 1 zonelists.  Total pages: 8128
Kernel command line: console=ttyS1,57600n8 root=/dev/mtdblock4 init=/sbin/preinit
Primary instruction cache 32kB, physically tagged, 4-way, linesize 32 bytes.
Primary data cache 16kB, 4-way, linesize 32 bytes.
Synthesized TLB refill handler (20 instructions).
Synthesized TLB load handler fastpath (32 instructions).
Synthesized TLB store handler fastpath (32 instructions).
Synthesized TLB modify handler fastpath (31 instructions).
Cache parity protection disabled
cause = 80800000, status = 1100ff00
PID hash table entries: 128 (order: 7, 512 bytes)
calculating r4koff... 0030d400(3200000)
CPU frequency 320.00 MHz
Using 160.000 MHz high precision timer.
Dentry cache hash table entries: 4096 (order: 2, 16384 bytes)
Inode-cache hash table entries: 2048 (order: 1, 8192 bytes)
Memory: 30416k/32768k available (1689k kernel code, 2352k reserved, 186k data, 100k init, 0k highmem)
Mount-cache hash table entries: 512
NET: Registered protocol family 16
Generic PHY: Registered new driver
NET: Registered protocol family 2
Time: MIPS clocksource has been installed.
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 1024 (order: 1, 8192 bytes)
TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
TCP reno registered
was not able to assign mahjor 200 to button chardev
ramips_gpio: done
squashfs: version 3.2-r2 (2007/01/15) Phillip Lougher
squashfs: LZMA suppport for slax.org by jro
io scheduler noop registered
io scheduler deadline registered (default)
ramips_wdt: loaded
Serial: 8250/16550 driver $Revision: 1.3 $ 2 ports, IRQ sharing disabled
serial8250: ttyS0 at I/O 0xb0000500 (irq = 37) is a 16550A
serial8250: ttyS1 at I/O 0xb0000c00 (irq = 12) is a 16550A
PPP generic driver version 2.4.2
NET: Registered protocol family 24
tun: Universal TUN/TAP device driver, 1.6
tun: (C) 1999-2004 Max Krasnyansky <[email protected]>
deice id : c2 20 15 c2 20 (2015c220)
mx25l3205d(c2 20160000) (4096 Kbytes)
mtd .name = raspi, .size = 0x00400000 (4M) .erasesize = 0x00010000 (64K) .numeraseregions = 0
ramips_mtd: kernel size is 613787
padded kernel is 00096000
Creating 6 MTD partitions on "raspi":
0x00000000-0x00010000 : "uboot"
0x00010000-0x00020000 : "boardconfig"
0x00020000-0x00200000 : "image"
0x00020000-0x000b6000 : "linux"
mtd: partition "linux" doesn't end on an erase block -- force read-only
0x000b6000-0x001f0000 : "rootfs"
mtd: partition "rootfs" doesn't start on an erase block boundary -- force read-only
mtd: partition "rootfs" set to be root filesystem
0x001f0000-0x00200000 : "uci_overlay"
Registered led device: power
Registered led device: wps
Registered led device: wlan
nf_conntrack version 0.5.0 (256 buckets, 2048 max)
IPv4 over IPv4 tunneling driver
ip_tables: (C) 2000-2006 Netfilter Core Team, Type=Linux
TCP cubic registered
NET: Registered protocol family 1
NET: Registered protocol family 17
802.1Q VLAN Support v1.8 Ben Greear <[email protected]>
All bugs added by David S. Miller <[email protected]>
ramips: ethernet loaded
ramips_eth: loaded
VFS: Mounted root (squashfs filesystem) readonly.
Freeing unused kernel memory: 100k freed
Warning: unable to open an initial console.
Preinit complete, spawning microd
found uci_overlay -> /dev/mtd5
i found OPENWRT_UCI_OVERLAY inside /dev/mtd5
loading file zepttho 275
loading file wireless 696
loading file user 70
loading file system 72
loading file reg 16
loading file network 473
loading file led 342
loading file lang 33
loading file form 4768
loading file fonsmcd 290
loading file fon 4Algorithmics/MIPS FPU Emulator v1.5
07
loading file firewall 907
loading file passwd 149
loading file chilli.conf 566
loading fon config
Spawning syslogd
registering led wps -> /sys/class/leds/wps/
registering led wlan -> /sys/class/leds/wlan/
registering led power -> /sys/class/leds/power/
loading base firewall ...iptables: Chain already exists
done
adding zone wannet
adding zone lan
adding zone wan
adding zone hotspotwifi
adding zone hotspot
adding forwarding lan->wan
adding forwarding hotspot->wan
interface loopback
proto = static
ipaddr = 127.0.0.1
netmask = 255.0.0.0
ifname = lo
interface lan
proto = static
ipaddr = 192.168.10.1
netmask = 255.255.255.0
ifname = eth0.1
type = bridge
interface wan
proto = dhcp
ifname = eth0.2
interface hotspot
ifname = tun0
interface hotspotwifi
proto = none
ifname = ra1
net event up loopback ...bringing up lo
done
net event up lan ...bringing ueth0.1: dev_set_promiscuity(master, 1)
p eth0.1
device eth0 entered promiscuous mode
device eth0.1 entered promiscuous mode
br-lan: port 1(eth0.1) entering learning state
adding br-lan to zone lan
done
net event up wan ...bringing up eth0.2
Spawning udhcpc for eth0.2
udhcpc (v0.9.9-pre) started
Trying to connect...
sending -> "udhcpc|deconfig|eth0.2|"
adding eth0.2 to zone wan
Sending discover...
done
wifi device rt305x
type = rt305x
channel = 11
mode = 9
wifi interface public
ifname = ra1
ssid = FON_FREE_INTERNET
encryption = none
network = hotspotwifi
device = rt305x
isolate = 1
auto = 1
wifi interface private
ifname = ra0
ssid = MyPlace
encryption = wpa-wpa2
key = 4141414141
password = ueriehaeph
wpa_crypto = mixed
network = lan
device = rt305x
channel = 0
mode = bgn
txpower = 100
br-lan: topology change detected, propagating
br-lan: port 1(eth0.1) entering forwarding state
rt2860v2_ap: module license 'unspecified' taints kernel.
Sending discover...
WSending discover...
0x1300 = 00064380
bringing up rt30device ra0 entered promiscuous mode
5x ...done
br-lan: port 2(ra0) entering learning state
Terminate the task(RtmpCmdQTask) with pid(202)!
Terminate the task(RtmpWscTask) with pid(203)!
br-lan: port 2(ra0) entering disabled state

しかし、入力を一切受け付けてくれません。どうやら制限が入っているようで、こちらの操作を受け付けないようになっているようです。
これではファームウェアの更新はできません…。色々試してみたものの、結局解決には至りませんでした。残念。

f:id:happytar0:20100719003100j:image

配線を4本ハンダ付けしてしまったり、他の線と干渉?しちゃったりで、電子工作はやっぱりたいへんだなという感じでしたが、面白かったのでこれからもいじっていきたいです。

mixiアプリでRESTful APIを使う

今さらながらmixiアプリでRESTful APIが使えることに気づいたわけで、早速試してみました。

mixiデベロッパー向けサイトに、サンプルコードも付いて詳しく説明されているので、これを参考にして書いていけば問題なさそうです。

実際のリクエストには、「Consumer Key」と「Consumer Secret」を使い、2-legged OAuthによって適切に署名をする必要があります。
「Consumer Key」と「Consumer Secret」は、アプリごとに割り当てられており、mixiアプリ設定画面より、確認することができます。

注意する点は「xoauth_requestor_id」をリクエストに付加する必要があるということです。公式サイトから引用です。

RESTful APIにアクセスする際に、xoauth_requestor_idパラメータによって、誰の権限でアクセスを行うかを指定することが必要になります。パラメータ値は、対象ユーザのIDとなります。このユーザIDについて、「一定時間内にWebブラウザで対象のmixiアプリを起動したユーザ」のIDのみ指定することが可能です。

対象ユーザが対象のmixiアプリを起動していない、もしくは起動から一定時間が経過した後にRESTful APIにアクセスを行った際には、HTTPレスポンスコードとして「401 Unauthorized」が返却されます。

対象ユーザのID、すなわちコンテナから送られてくる「opensocial_viewer_id」を指定することになります。

下記のようなコードで動かすことが出来ました。署名にはoauthライブラリを使います。

  require 'oauth'
consumer = OAuth::Consumer.new(「アプリのConsumer Key」,
「アプリのConsumer Secret」,
{:site => 'http://api.mixi-platform.com'})
end_point = 'http://api.mixi-platform.com/os/0.8'
req = consumer.request(:get, end_point + '/people/@me/@self' + '?xoauth_requestor_id=' + opensocial_viewer_id)
JSON.parse(req.body) # JSONデータをオブジェクト化

公式にはRubyのコードがなかったようなので載せておきます。

PHP版Shindigが上手く動かない

オープンソーシャルのアプリを開発する上で、必須といえるShindigShindigでコンテナを構築すればローカルでオープンソーシャルの開発をすることが出来ます。
そこでちょっとハマったことを記録として残しておきます。

まずShindigには、色々なバージョンがある上にJava版とPHP版の二種類が存在します。
以前開発に使っていたのはJava版で、PHPで上手く動かすことが出来なかったため使っていました。が、、、HAS_APPフィルタがなぜか上手く動かない事に気づき、調べてみたもののJavaがほとんど分からず、これを機会にPHP版を新たにインストールしてみた訳です。

Shindigをインストールする

ShindigApacheの所で開発されているようで、下記からダウンロードできます。
Shindig – Download
今回は、Currentの「shindig-1.1-BETA5-incubating-php.zip」を使いました。SVNリポジトリから落とすと、Java版も含まれているため、ディレクトリパスの設定がちょっとめんどうだと思います。

zipを展開し、Webからアクセス出来るように各々で設定してください。注意点は、.htaccessも含まれており、mod_rewriteも必要になるということです。

<VirtualHost *:80>
ServerName shindig.localhost.man
DocumentRoot /home/wwww/shindig # zipを展開したディレクトリ
<Directory />
AllowOverride All # .htaccessを読み込めるようにする
</Directory>
</VirtualHost>

URLパラメータ付きでも動くようにする

上記のようにインストールすれば、とりあえずは動くのですが、僕が使う上でちょっと不便な部分があったので修正しました。
それは、コンテナのURLにパラメータが指定されている場合に上手く動かなかった事です。
正しくパラメータを処理できず、「400 – Bad Request」となってしまいます。

http://shindig.localhost.man/gadgets/files/container/container.html?view=canvas
こんな感じで引数で画面を切り替えていました。

# src/gadgets/servlet/FileServlet.php
# 40行目の下にパラメータを無視するようなコード追加
#
$file = str_replace(Config::get('web_prefix') . '/gadgets/files/', '', $_SERVER["REQUEST_URI"]);
$file = Config::get('javascript_path') . $file;
// ここを追加
$file = substr($file, 0, strlen($file) - strlen(strstr($file, '?')));
// make sure that the real path name is actually in the javascript_path, so people can't abuse this to read
// your private data from disk .. otherwise this would be a huge privacy and security issue
if (substr(realpath($file), 0, strlen(realpath(Config::get('javascript_path')))) != realpath(Config::get('javascript_path'))) {

署名付きリクエストに対応する

署名付きリクエストとは何か、それはオープンソーシャル開発をする上、外部サーバを呼び出したい場合にとても重要になってきます。「makeRequest」というJavaScript関数を使用し、外部サーバに非同期にリクエストを送るわけですが、ここで重要なのは、リクエストが改ざんされないように署名するということです。

Shindigで署名付きリクエストを使うために、opensslで秘密鍵と証明書を作成します。

$ openssl req -newkey rsa:1024 -days 365 -nodes -x509 -keyout test.pem -out test.pem -subj '/CN=mytestke
$ openssl pkcs8 -in test.pem -out private.key -topk8 -nocrypt -outform PEM

とりあえず: [Apache Shindig][お勉強][OpenSocial] メモ118 gadgets.io.makeRequest 認証認可タイプSIGNEDをやってみる(RSA-SHA1で署名)

出来た証明書と鍵をcertsディレクトリに保存し、Shindigの設定ファイルを書き換えます。

# config/container.php
'private_key_file' => realpath(dirname(__FILE__) . '/../certs') . '/private.key',
'public_key_file' => realpath(dirname(__FILE__) . '/../certs') . '/test.pem',
'private_key_phrase' => '',

これで問題なしと思われたのですが、上手く署名付きリクエストをおこなう事が出来ませんでした。

パラメータ付きURLから上手くmakeRequestがおこなえない

makeRequestで外部サーバを呼び出すときに、パラメータを付加すると上手く動かないという現象が発生しました。

var url = 'http://localhost/gadget/canvas?ts=1277893054';
gadgets.io.makeRequest(url, null, this.makeParams(data));

タイムスタンプ値を末尾に付加してリクエストを送っていたのですが、「?ts=1277893054」が問題で、このパラメータを上手く処理出来ていないために失敗しているようでした。

# src/gadgets/oauth/OAuth.php
# 186行目のbuild_signatureが実際に署名をおこなっている箇所になります。
public function build_signature(&$request, OAuthConsumer $consumer, $token) {
$base_string = $request->get_signature_base_string();
// Fetch the private key cert based on the request
$cert = $consumer->getProperty(OAuthSignatureMethod_RSA_SHA1::$PRIVATE_KEY);
// Pull the private key ID from the certificate
//FIXME this function seems to be called both for a oauth.json action where
// there is no phrase required, but for signed requests too, which do require it
// this is a dirty hack to make it work .. kinda
if (! $privatekeyid = @openssl_pkey_get_private($cert)) {
if (! $privatekeyid = @openssl_pkey_get_private($cert, Config::get('private_key_phrase') != '' ? (Config::get('private_key_phrase')) : null)) {
throw new Exception("Could not load private key");
}
}
// Sign using the key
$signature = '';
if (($ok = openssl_sign($base_string, $signature, $privatekeyid)) === false) {
throw new OAuthException("Could not create signature");
}
// Release the key resource
@openssl_free_key($privatekeyid);
return base64_encode($signature);
}

openssl_pkey_get_private関数によって、秘密鍵を取得し、$base_stringに対して署名していることが分かります。この$base_stringの中身はこうなっていました。

POST&http%3A%2F%2Flocalhost%3A3000%2Fgadget%2Fcanvas&dummy%3D1%26oauth_consumer_key%3Dcont%26oauth_nonce%3D96bd6e6d4103d3c5197f26d5dd6e3463%26oauth_signature_method%3DRSA-SHA1%26oauth_timestamp%3D1277893517%26oauth_token%3D%26opensocial_app_id%3Dappid%26opensocial_app_url%3Durl%26opensocial_owner_id%3Djohn.doe%26opensocial_viewer_id%3Djohn.doe%26ts%3D1277893516%26xoauth_public_key%3Dhttp%253A%252F%252Fshindig.localhost.man%252Fpublic.cer%26xoauth_signature_publickey%3Dhttp%253A%252F%252Fshindig.localhost.man%252Fpublic.cer

この時に「ts%3D1277893516」の文字列があり、パラメータ「ts」も含めて署名されている事が分かります。

続いて実際に外部サーバにリクエストを送る部分です。

# src/gadgets/SigningFetcher.php
# 111行目のsignRequestが送信リクエストを作成します。
# 174行目にクエリーストリングを処理する箇所があり、送信先リクエストにパラメータを追加して渡しています
$newQuery = '';
foreach ($req_req->get_parameters() as $key => $param) {
if (! isset($forPost[$key])) {
$newQuery .= urlencode($key) . '=' . urlencode($param) . '&';
}
}
# 問題の箇所
// and stick on the original query params too
if (isset($parsedUri['query']) && ! empty($parsedUri['query'])) {
$oldQuery = array();
parse_str($parsedUri['query'], $oldQuery);
foreach ($oldQuery as $key => $val) {
$newQuery .= urlencode($key) . '=' . urlencode($val) . '&';
}
}

一見問題ないように見えますが、$req_req->get_parameters関数が返す値には、既にクエリーストリングも処理されており、二重でクエリーストリングが処理されていることになります。
パラメータの二重化によって、署名されたリクエストと異なる値になってしまい、外部サーバでの署名確認時にエラーとなってしまいます。

パラメータが二重処理されたリクエストです。パラメータ「ts」が二つあることが分かります。

http://localhost/gadget/canvas?oauth_nonce=0c8c8040978beed7b0221f655ef50303&oauth_timestamp=1277893863&oauth_consumer_key=cont&ts=1277893863&opensocial_owner_id=john.doe&opensocial_viewer_id=john.doe&opensocial_app_id=appid&opensocial_app_url=url&oauth_token=&xoauth_signature_publickey=http%3A%2F%2Fshindig.localhost.man%2Fpublic.cer&xoauth_public_key=http%3A%2F%2Fshindig.localhost.man%2Fpublic.cer&oauth_signature_method=RSA-SHA1&oauth_signature=KTo5X7QxKg8mSpDiaGjljeyKAlmdMLO%2BbPrAr0qYycqAzqTSw8t44p2lXmdRZendFwEpbKLPZy9tAoJ98X9YVkOHjXsp6D19%2BtFBCgSQDJzuvWxHC6xKiRnw2iR0M0HcKSNeMf6x45W%2FJM9rwxT%2BdUYrDZ%2BO4IKbq1etvQj6nWs%3D&ts=1277893863&

src/gadgets/SigningFetcher.phpの181行目〜187行目までをコメントアウトすることで回避できます。

html_sanitize is not defined

これでようやく署名付きリクエストに対応出来たかと思われましたが、次に新たな問題が発生しました。
コンテナ内で「Tabs」Featureを利用した時に「html_sanitize is not defined」というJavaScriptエラーが出ることです。
どうやら、core Featureでhtml-sanitizer.jsというのを読み込むコードが足りないようです。

# src/gadgets/GadgetFeatureRegistry.php
// Make html-santitization work see SHINDIG-346
if ($content == 'res://com/google/caja/plugin/html-sanitizer.js') {
$content= 'http://google-caja.googlecode.com/svn/trunk/src/com/google/caja/plugin/html-sanitizer.js';
} 

このような記述があり、html-sanitizer.jsだけ特別な処置がされているようです。
今回は、Tabs Featureにhtml-sanitizer.jsを読み込ませるコードを追加します。具体的には、feature.xmlに以下のように追加します。

# features/src/main/javascript/features/tabs/feature.xml
<feature>
<name>tabs</name>
<gadget>
<!-- for gadgets.util.sanitizeHtml -->
<script src="res://com/google/caja/plugin/html-sanitizer.js"/>
<script src="tabs.js"/>
<script src="taming.js"/>
</gadget>
</feature>

これでまともに使えるようになりました。PHP版Shindigは地雷が多いのでJava版を使ったほうが簡単ということでしょうか。それともやり方がおかしいのか・・・?

ブラウザでP2P通信、ファイル転送が出来るのか

P2Pと聞くとマイナスのイメージを持ってしまいますが、P2P技術が使われているプロダクトは意外に多いのではないかと思います。

もちろん、P2Pを利用する上での長所・短所はあります。
長所は、通信帯域を多く使うアプリケーションの場合、サーバを介さずに通信が出来るためコストを抑えることができ、Winnyに代表されるように匿名性やスケーラビリティといった耐障害性の観点からもメリットがあります。
逆に短所は、実装が困難な点やノード管理の複雑さ、接続先のネットワーク環境に左右されうる点などがあると思います。

特に通信帯域を多く使うような場面での効果は絶大です。動画や音声配信などの通信帯域を使う場面はどんどん増えていっています。
この状況下(1年くらい前?)で、FlashPlayer1.0から実装されたのがRTMFP(Real Time Media Flow Protocol)というプロトコルです。
これはUDPを使い、ユーザ間同士で直接通信することができるような夢のような機能です。

少し気になるのはUDP?というわけですが、これにはいくつか理由があるようです。動画や音声送信などのリアルタイム性(遅延が少ない)を求める場面で有利ということや、NAT越えもし易いってこともあるんじゃないでしょうか。

コネクションレスUDPでは、遅延が少ないといってもちゃんと届いている不安な感じですが、信頼性を上げるために輻輳処理や暗号化などが取り入れられているそうです。詳しくは下記参照。
Flash Player 10.1 と RTMFP – akihiro kamijo

あともう一つ、このプロトコルではStratusという中央サーバが必要であり、ハイブリッドP2Pであるということが言えます。Stratusは現在Adobeのサイトにて無償開放されていますが、将来的にはFMSに取り込まれるのではないかと思います。
Cirrus | Real Time Media Flow Protocol (RTMFP) – Adobe Labs

NAT越えは、UDPホールパンチングという方法を使っているそうで、最初に中央サーバに接続する事で実現しているようです。アウトバウンドのUDPが使える環境で、なおかつルータがNATトラバーサルに対応している必要があるという条件は限られますが、多くの環境では使えるのではないかと思います。信頼性を重視するサービスの場合、既存のRTMP等のプロトコルと併用します。

そして6月になり、FlashPlayer10.1が正式リリースされました。新たに10.1で導入された機能にピアアシストネットワークというものがあります。
これはノード同士をグループ化することができ、自律したネットワークを構成してくれるという優れものです。詳しくは下記参照。
Flash Player 10.1 と RTMFP (ピアアシストネットワーク) – akihiro kamijo

そんなこんなでFlashでP2Pを利用できる環境がばっちり整ってきた訳で、早速何か作ろうかと考えて出来たのが、ブラウザ間でファイルをP2P転送することが出来るWebサービスです。
We're sorry, but something went wrong (500)

まだ公開したばかりですが、上に書いたようにビアアシストネットワークを使ったりすれば、もう少し便利になるのではないかという感じです。他のサービスにも応用出来そうなので色々作れればいいなーと思います。

ひかりone(BL190HW)でYAMAHAのルータ(RTX1200)を使う

ひかりoneで他のルータを使う方法をまとめてみます。

付属のルータ(HGW)は「BL190HW」というもので、ひかりone自体はDHCPによってグローバルIPアドレスを割り振っているようです。この時にHGWのMACアドレスを参照しているため、他のルータなどに置き換えた場合、正常にIPアドレスが割り振られません。

MACアドレスをHGWのものに書き換えることが出来るルータならば、恐らくそのまま置き換えることが出来るのではないかと思います。
ひかりoneギガ得プランでRTX1200 – フタなしカンヅメ

今回は手持ちのRTX1200を使いたいので、MACアドレス書き換えなどは使えません。
ですので、RTX系ルータを使う場合はHGWを間に接続する必要があります。

+-----+    +-----+    +-----+
| ONU +----+ HGW +----+ RTX +
+-----+    +-----+    +-----+
DHCP(*1)   DMZ(*2)

*1) DHCPでグローバルIP割り当て
*2) HGWのDMZを使ってRTXにそのまま流す

上の図のように各機器を接続します。
HGWの代わりにRTX1200を使いたいので、HGWのDMZ機能を使って全てのパケットをRTX1200にそのまま流します。

BL190HWのDMZ機能ついてはこちら
DMZホスト機能

以下のようなローカルネットワークを構築することにします。

HGWとRTX間のネットワークは、192.168.99.0/24
HGWのDMZホスト機能をオンに設定し、192.168.99.2をDMZのIPアドレスとして設定
---
DMZで設定した「192.168.99.2」を使ってHGW-RTX間で通信
RTXにぶら下がってるネットワークは、129.168.101.0/24
RTXの下に「192.168.101.2」としてサーバを1台設置
「192.168.99.2」と「192.168.101.2」を静的NATを設定
                    192.168.99.2
|
+-----+    +-----+    +-----+    +-----+
| ONU +----+ HGW +----+ RTX +----+ P C | 192.168.101.2
+-----+    +-----+    +-----+    +-----+
192.168.99.0/24   192.168.101.0/24

RTX1200には以下のような設定をします。

ip route default gateway 192.168.99.1 filter 1001
lan type lan1 auto port-based-option=divide-network
ip vlan1 address 192.168.101.1/24
ip lan3 address 192.168.99.2/24
ip lan3 nat descriptor 1
ip filter 1001 pass 192.168.101.0/24 * * * *
nat descriptor type 1 nat
nat descriptor address outer 1 192.168.99.2
nat descriptor address inner 1 192.168.101.2
nat descriptor static 1 1 192.168.99.2=192.168.101.2 1

LAN3ポートにHGWを接続し、LAN1ポートのvlan1にサーバ側のLANを接続します。
フィルタリングは何もしていませんので、各自環境にあった正しい設定をおこなったほうがいいと思います。
ど素人なので参考程度にということでお願いします。