2015年12月18日金曜日

lua-resty-libcjson をインストール

概要

Nginx + Lua スクリプト内で JSON 情報を扱うために lua-resty-libcjson というライブラリを追加してみました

環境

  • CentOS 6.7 64bit Final
  • LuaJIT 2.0.4
  • ngx devel kit 0.2.19
  • lua-nginx-module 0.9.19
  • nginx 1.9.3
  • lua-resty-libcjson 5260553b26a264c1cfb27bcd1b9c28d117f05b8f
  • cJSON 67d3c7fbc705e82e97baf22d35aa8abfddbe2d3e

インストール

lua-resty-libcjson のインストール

まずは Lua スクリプト用のライブラリをインストールします

Lua のライブラリは /usr/local/openresty/lualib/resty にインストールしていますが、お好きなところにインストールして OK です

cJSON のインストール

cJSON とはその名の通り C/C++ で JSON を扱えるようにするためのライブラリです
ソースをダウンロードしてコンパイルして共有ライブラリ ( .so ) ファイルを作成する必要があります

共有ライブラリのパスはすでに通っているパスに配置してください
独自のパスに配置した場合は ldconfig 等を使ってパスを通してから Nginx を起動してください

サンプル

  • json_sample.lua
local p = "/usr/local/openresty/lualib/"
local m_package_path = package.path
package.path = string.format("%s?.lua;%s?/init.lua;%s", p, p, m_package_path)

local json = require "resty.libcjson"
local str = json.encode({key = "value"}, false)
ngx.log(ngx.ERR, str)
  • ログ
    • tail -f /opt/nginx/logs/error.log

2015/12/18 12:23:39 [error] 11875#0: *1 [lua] json_sample.lua:47: main(): {“key”:”value”}, client: 127.0.0.1, server: localhost, request: “GET /hoge HTTP/1.1”, host: “localhost”

テーブル情報を JSON 文字列に変換するサンプルです

はじめに lua-resty-libcjson を配置したパスを package.path に追加します
追加に成功していれば require してライブラリを読み込みます
パスがうまく通っていない場合、require に失敗します

テーブルから JSON の文字列を取得するには json.encode を使用します
第一引数にテーブル情報を与えて第二引数には JSON をフォーマットするかの boolean を与えます
true を指定すると改行コードやタブ文字が入った情報が取得できます
JSON 文字列からテーブル情報を取得する場合は json.decode を使用してください

2015年12月16日水曜日

lua-nginx-module でサンプルの lua スクリプトを試してみた

概要

前回 Nginx + lua-nginx-module のインストール方法を紹介しました
今回は簡単なサンプルの挙動を確認してみます

環境

  • CentOS 6.7 64bit Final
  • LuaJIT 2.0.4
  • ngx devel kit 0.2.19
  • lua-nginx-module 0.9.19
  • nginx 1.9.3

サンプルの Lua スクリプト作成

  • touch /opt/nginx/lua/sample.lua
  • vim /opt/nginx/lua/sample.lua
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.header.content_type = "application/json"
ngx.say('{"code": "E401001", "error": "Authentication error by header incorrect."}')
ngx.exit(ngx.HTTP_OK)

今回は、認証エラーを返却する lua スクリプトを作成しました
ステータスを設定 (ngx.status) して、Content-type を設定 (ngx.header.content_type) してレスポンスボディを設定 (ngx.say) して、スクリプトを終了しています
最後の ngx.HTTP_OK は 200 以上のステータスを設定すれば OK です
200 以上のステータスを設定した場合はリクエスト全体のレスポンスを返却し、200 未満の場合はそのスクリプトが実行されているフェーズだけが終了され、次の処理に進みます

Lua スクリプトを呼び出す

  • vim /opt/nginx/conf/nginx.conf
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    access_by_lua_file "/opt/nginx/lua/sample.lua";
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            proxy_pass   http://www.kakakikikeke.blogspot.jp/;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

nginx.conf はデフォルトのものからコメントアウトを削除した設定を使用しています
http ブロック内で先ほど作成した Lua スクリプトを access_by_lua_file を使ってコールします
これで各リクエストが来た時に必ず Lua スクリプトが呼ばれることになります

動作確認

今回のサンプルは Lua スクリプトを有効にしている場合は必ず認証エラー用の JSON が返ってくることになります

まず Lua スクリプトを有効にした状態で Nginx を起動しましょう
その状態でリクエストしてみると

> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.19.1 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: localhost
> Accept: */*
> 
< HTTP/1.1 401 Unauthorized
< Server: nginx/1.9.3
< Date: Mon, 14 Dec 2015 02:16:19 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< 
{"code": "E401001", "error": "Authentication error by header incorrect."}

こんな感じで先ほど設定した Json が返却されます

では、次に nginx.conf で呼び出した Lua スクリプトをコメントアウトして Nginx を再起動してください
すると次は認証エラーにはならず HTML が返ってくることが確認できると思います

最後に

簡単なサンプルを試してみました
リクエストのヘッダ情報やボディ情報を取得することができるので簡単な認証フィルタを作成したいのであれば、Nginx だけでできるようになると思います
ただ、認証情報が MySQL や Redis 等のデータベースにある場合がほとんどだと思うので、その場合は DB にアクセスできる Lua ドライバを使う必要があります

この辺のドライバの使い方も今後試したいなと思っています

2015年12月15日火曜日

lua-resty-mongol を使って Nginx から MongoDB を操作してみた

概要

Nginx 上で Lua スクリプトを動作させる環境を構築しました
http://kakakikikeke.blogspot.jp/2015/12/nginx-with-lua-nginx-module.html

今回は更に拡張して Lua スクリプトから MongoDB を操作できるようにしてみたいと思います

環境

  • CentOS 6.7 64bit Final
  • LuaJIT 2.0.4
  • ngx devel kit 0.2.19
  • lua-nginx-module 0.9.19
  • nginx 1.9.3
  • lua-resty-mongol 682ad317f0d3451308a2a953fef80fbad1de872d

lua-resty-mongol のインストール

/usr/local/openresty/lualib/resty/mongol/ に必要な Lua スクリプトがインストールされました

lua-resty-string のインストール

/usr/local/lib/lua/resty/ に必要な Lua スクリプトがインストールされました

nginx.conf の修正

MongoDB に接続するためのサンプルの Lua スクリプトを実行するように修正します

access_by_lua_file "/opt/nginx/lua/connect_db.lua";

nginx.conf でインストールした各種ライブラリを読み込むこともできますが、今回は Lua スクリプト側でライブラリの読み込みを行います

Lua スクリプトの作成

  • cd /opt/nginx/lua
  • vim connect_db.lua
local p = "/usr/local/openresty/lualib/"
local p2 = "/usr/local/lib/lua/"
local m_package_path = package.path
package.path = string.format("%s?.lua;%s?/init.lua;%s?.lua;%s?/init.lua;%s", p, p, p2, p2, m_package_path)

local function test_connect()
   local mongol = require "resty.mongol"
   local conn = mongol:new()
   conn:set_timeout(1000)
   local ok, err = conn:connect("127.0.0.1", 27017)
   if not ok then
      raise_error(ngx.HTTP_INTERNAL_SERVER_ERROR, '{"code": "E500001", "error": "Auth System error."}')
   end
   local db = conn:new_db_handle("test")
   local col = db:get_col("test_col")
   local r = col:find_one({key=value})
   ngx.log(ngx.ERR, r["key"])
end

local function main()
   test_connect()
end

main()

簡単にポイントを紹介します

まず、スクリプト冒頭でライブラリのパスを指定します
今回は別々のパスにインストールされたので、2 つのパスを読み込むように設定します
もし、一箇所にインストールした場合は 1 つのパスだけ設定すれば OK です
Lua スクリプトのインストールパスが違う場合は変更してください

connect する場合の引数は IP アドレス + ポート番号になります
ホスト名でも指定できるのですが、Nginx が名前解決できない場合があるので IP で指定すると確実です

あとはサンプル通り DB 接続、Collection 接続、データ取得の流れになります

その他のメソッドは細かい仕様については公式 の README.md を見るといいと思います
あとはソースもそこまで難しくないのでソースを見ても理解できると思います

最後に

これで Nginx だけで MongoDB にアクセスできるようになりました

まだガッツリと触っていないのと複雑な処理まで実装していないので、何とも言えませんが完成したら負荷テストなどでどれくらい処理性能があるかと DB への負荷が掛かるかは確認したほうがいいかもしれません

2015年12月14日月曜日

Nginx with lua-nginx-module のインストール

概要

Nginx 上で lua スクリプトを実行することができる lua-nginx-module をインストールしてみました
Nginx も一からインストールしているので既存の Nginx は一度アンインストールしてから行っています

環境

  • CentOS 6.7 64bit Final
  • LuaJIT 2.0.4
  • ngx devel kit 0.2.19
  • lua-nginx-module 0.9.19
  • nginx 1.9.3

事前準備

yum でインストールした既存の nginx を削除

  • yum remove nginx.x86_64

PCRE (Perl Compatible Regular Expressions) のインストール

正規表現を扱うためのパッケージをインストールします

  • yum -y install pcre-devel gcc openssl openssl-devel

インストール

LuaJIT インストール

  • cd /root/work
  • wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz
  • tar zvxf LuaJIT-2.0.4.tar.gz
  • cd LuaJIT-2.0.4
  • make
  • make install
  • luajit -v

ngx devel kit のダウンロード

  • cd /root/work
  • wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
  • tar zvxf v0.2.19.tar.gz

lua nginx mode のダウンロード

  • cd /root/work
  • wget https://github.com/openresty/lua-nginx-module/archive/v0.9.19.tar.gz
  • tar xvzf v0.9.19.tar.gz

nginx のインストール

  • cd /root/work
  • wget 'http://nginx.org/download/nginx-1.9.3.tar.gz'
  • tar -xzvf nginx-1.9.3.tar.gz
  • cd nginx-1.9.3/
  • export LUAJIT_LIB=/usr/local/lib
  • export LUAJIT_INC=/usr/local/include/luajit-2.0
  • ./configure --prefix=/opt/nginx --with-http_ssl_module --with-ld-opt="-Wl,-rpath,/usr/local/lib" --add-module=/root/work/ngx_devel_kit-0.2.19 --add-module=/root/work/lua-nginx-module-0.9.19
  • make -j2
  • make install

configure 時の各種パスは絶対パスで記述してください
https 用のモジュールもついでにインストールしておきます

動作確認

  • 起動

/opt/nginx/sbin/nginx

  • ログ確認

/opt/nginx/logs/access.log

  • 停止

/opt/nginx/sbin/nginx -s stop

最後に

これで nginx.conf 内に lua スクリプトが書けるようになりました
次回は実際に lua スクリプト書いてリクエストやレスポンスを操作してみたいと思います

参考サイト

2015年12月11日金曜日

SDK for NFC を使って Pasori でカード情報を読み込んでみた

概要

Pasori は Sony が提供する Ferica 用の IC カードリーダでよく目にするやつだと Edy のチャージなどに使います
SDK for NFC というこれまた Sony が提供する SDK がありこれを使うと Pasori を使っていろいろな IC カードの情報を読み込んだり書き込んだりすることができます
今回は SDK を使った簡単なサンプルを作成してみました

環境

  • Windows7 64bit
  • Felica RC-S320
  • Microsoft Visual Studio Express 2015 Community 14.0.24720.00 Update 1
  • SDK for NFC 2.0.3

Visual Studio のインストール

詳細はこちらを御覧ください
SDK for NFC に含まれる nfc 用のライブラリを使うのですが、これが .lib ファイルという形式で提供されているため Visual Studio が必要になります
自分もよくわかっていないのですが、 .lib ファイルをリンカーとして登録して実行するには普通の gcc が実行できる環境だけではダメなようです

SDK for NFC のダウンロードとインストール

ダウンロードは以下のリンクからできます
http://www.sony.co.jp/Products/felica/business/products/ICS-D004_002_003.html

sdk4nfc_starter203J.zip をダウンロードしたら解凍して、Cドライブ直下に保存します

C:\sdk4nfc_starter203J

あとは Pasori 用のドライバをインストールしましょう
SDK 内に含まれている exe ファイルを実行すれば OK です
C:\sdk4nfc_starter203J\driver\NFCPortWithDriver.exe がそれになるのでを実行してドライバをインストールしてください
ドライバをインストールしたら一度再起動したほうが良いと思います

プロジェクトの作成と各種ライブラリの追加

Visual Studio を起動してプロジェクトを作成しましょう
作成するプロジェクトの種類は「Visual C++ -> Windows -> 全般 -> 空のプロジェクト」で OK です

プロジェクトを作成したインクルードパスとリンカーの設定をしましょう

インクルードパスの設定

プロジェクトのプロパティを開きます

C/C++ -> 全般 -> 追加のインクルードディレクトリ -> 編集

で追加ダイアログを開いて

新しい行 -> 参照ボタン

で以下のパスを追加します

  • C:\sdk4nfc_starter203J\FeliCa_Library\include
  • C:\sdk4nfc_starter203J\NFCAccessLibrary\include

追加できたら OK -> 適用しましょう

リンカーの設定

プロジェクトのプロパティを開きます

リンカー -> 入力 -> 追加の依存ライブラリ -> 編集

で追加のダイアログを開いて以下のライブラリを追加します

  • C:\sdk4nfc_starter203J\FeliCa_Library\lib\x86\felica.lib
  • C:\sdk4nfc_starter203J\NFCAccessLibrary\lib\x86\felica_nfc_library.lib

追加できたら OK -> 適用でプロパティを閉じましょう

ソースファイルの追加

ソースファイルをプロジェクトに追加します

プロジェクトを右クリック -> 追加 -> 新しい項目

で追加ダイアログを開いて

Visual C++ -> C++ ファイル (.cpp) -> 追加

でソースファイルを追加しましょう
デフォルトだと Source.cpp というファイルが追加されます

追加できたら早速サンプルコードを記載しましょう
コードの全容は以下の通りです

#include <cstdio>
#include <cstdlib>

#include "felica.h"

int main(void);
void error_routine(void);
void print_vector(char* title, unsigned char* vector, int length);

int main(void)
{
    if (!initialize_library()) {
        fprintf(stderr, "Can't initialize library.\n");
        return EXIT_FAILURE;
    }
    printf("Complete initialize_library\r\n");

    if (!open_reader_writer_auto()) {
        fprintf(stderr, "Can't open reader writer.\n");
        return EXIT_FAILURE;
    }
    printf("Complete open_reader_writer_auto\r\n");

    structure_polling polling;
    unsigned char system_code[2] = { 0xFF, 0xFF };
    polling.system_code = system_code;
    polling.time_slot = 0x00;

    unsigned char number_of_cards = 0;

    structure_card_information card_information;
    unsigned char card_idm[8];
    unsigned char card_pmm[8];
    card_information.card_idm = card_idm;
    card_information.card_pmm = card_pmm;

    unsigned long timeout;
    get_polling_timeout(&timeout);
    printf("timeout: %lu\r\n", timeout);
    timeout = 2000;
    set_polling_timeout(timeout);

    if (!polling_and_get_card_information(&polling, &number_of_cards, &card_information)) {
        fprintf(stderr, "Can't find FeliCa.\n");
        return EXIT_FAILURE;
    }

    fprintf(stdout, "number of cards: %d\n", number_of_cards);

    print_vector("card IDm:", card_idm, sizeof(card_idm));
    print_vector("card PMm:", card_pmm, sizeof(card_pmm));

    if (!close_reader_writer()) {
        fprintf(stderr, "Can't close reader writer.\n");
        return EXIT_FAILURE;
    }

    if (!dispose_library()) {
        fprintf(stderr, "Can't dispose library.\n");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

void error_routine(void) {
    enumernation_felica_error_type felica_error_type;
    enumernation_rw_error_type rw_error_type;
    get_last_error_types(&felica_error_type, &rw_error_type);
    printf("felica_error_type: %d\n", felica_error_type);
    printf("rw_error_type: %d\n", rw_error_type);

    close_reader_writer();
    dispose_library();
}

void print_vector(char* title, unsigned char* vector, int length) {
    if (title != NULL) {
        fprintf(stdout, "%s ", title);
    }

    int i;
    for (i = 0; i < length - 1; i++) {
        fprintf(stdout, "%02x ", vector[i]);
    }
    fprintf(stdout, "%02x", vector[length - 1]);
    fprintf(stdout, "\n");
}

SDK に含まれているサンプルのソースコードをほぼ流用しています
C:\sdk4nfc_starter203J\sample\FeliCa_Library\sample_06.cpp

サンプルコードの説明

以下ポイントを説明していきます

main メソッドの一番初めで NFC ライブラリの初期化をしています

if (!initialize_library()) {
    fprintf(stderr, "Can't initialize library.\n");
    return EXIT_FAILURE;
}

初期化が完了したら接続されている Pasori をオープンします
なので、これを実行するときに Pasori がパソコンに接続されて、正常に動作する状態になっている必要があります

if (!open_reader_writer_auto()) {
    fprintf(stderr, "Can't open reader writer.\n");
    return EXIT_FAILURE;
}

もし、Pasori が接続されていなかったりドライバインストールされていなくてうまく動作しない場合はここでエラーになります

カードのスキャンをスタートする前に Pasori がスキャンする時間を設定してます

unsigned long timeout;
get_polling_timeout(&timeout);
printf("timeout: %lu\r\n", timeout);
timeout = 2000;
set_polling_timeout(timeout);

デフォルトだと 100 ms しかスキャンしないので、カードを乗せた状態で実行しないと検知してくれません
なので、今回は少しスキャンに余裕を持たせて 2 秒間スキャンするようにしました

このあとでスキャンを開始します

if (!polling_and_get_card_information(&polling, &number_of_cards, &card_information)) {
    fprintf(stderr, "Can't find FeliCa.\n");
    return EXIT_FAILURE;
}

スキャンに成功してカードの情報が取得できると引数として渡している card_information に値が設定されます

それをその後で参照します

print_vector("card IDm:", card_idm, sizeof(card_idm));
print_vector("card PMm:", card_pmm, sizeof(card_pmm));

最後に処理が完了したので終了処理をしています

if (!close_reader_writer()) {
    fprintf(stderr, "Can't close reader writer.\n");
    return EXIT_FAILURE;
}

if (!dispose_library()) {
    fprintf(stderr, "Can't dispose library.\n");
    return EXIT_FAILURE;
}

このあたりでコールしている関数の詳細は SDK に付属の pdf を参照するといいと思います
C:\Users\username\Downloads\sdk4nfc_starter203J\sdk4nfc_starter203J\doc\FeliCa_Library\M735_FeliCaLibrary_StarterKit_1.3j.pdf

ビルドして実際に試してみる

ソースを記載したビルドしましょう
プロジェクトを選択した状態で

ビルド -> ソリューションのビルド

でビルドが成功すれば OK です
失敗する場合はインクルードパストリンカーの設定を再度見なおしてください
今回の場合だと大抵はライブラリの読み込みに失敗してビルドが失敗します

コマンドプロンプトを開いて実際に実行してみましょう
実行するまでに Pasori を PC に接続してください

C:\Users\username\Documents\Visual Studio 2015\Projects\Project2\Debug>Project2.exe

で Pasori のスキャンがはじまります
今回はスキャンが 2 秒なのであらかじめ IC カードを置いておくといいと思います
スキャンに成功するとカードの IDm という識別番号が表示されると思います

自分は Pasumo がうまくスキャンできて IDm が取得できることは確認しました

最後に

今回スキャンして IDm を表示するとこまでやってみました
Pasumo の場合は乗車履歴とかも書き込まれているようで、それも取得できるみたいなので、次はそこまでやってみたいです
あとは、読み込みだけじゃなくて IC カードへの書き込みもやってみたいなと思います

ライブラリにはもう一つ lite 版というのがあり、関数とかの先頭に「felica_」がついた版があります
自分は初め lite 版を使っていたのですが、どうしても「 felicalib_nfc_open」で Pasori をオープンするところでこけてしまい、lite 版をあきらめました
これは予想ですが、Pasori のバージョンが RC-S320 というだいぶ古いバージョンを使っていたので失敗したのかもしれません
S370 や S380 という比較的新しいバージョンの Pasori を使えば lite 版でも動作するかもしれません

2015年12月10日木曜日

Visual Studio Express 2015 Community バージョンをインストール

概要

タイトルの通りですが、Windows7 に Visual Studio 2015 をインストールしてみました
結構はまったのでメモしておきます

環境

  • Windows7 64bit
  • Microsoft Visual Studio Express 2015 Community 14.0.24720.00 Update 1
  • Microsoft .NET Framework 4.6.01055

インストール方法

インストーラをダンロードできるダウンロードサイトにいきます
https://www.visualstudio.com/ja-jp/products/visual-studio-express-vs.aspx

ダウンロードできた「vs_community_JPN.exe」をクリックしインストールを開始します

IE のバージョン 10 以上がインストールされていないと警告が表示されます
特に気にせず次に進みます
install_vc_step1.png

インストール方法を選択します
ここでは必ず「カスタム」を選択しましょう
install_vc_step2.png

インストール機能を選択します
「すべて選択」のチェックボックスがあるのでチェックします
自分の場合はすべてインストールするのに 32GB 必要と言われました
他のマシンでインストールしたときは 23GB 必要と言われたので環境によってはすでに必要な機能がインストールされており、必要な容量が少なく表示されるのだと思います
それにしても 32GB も必要というのは IDE としてちょっとありえないかなと思います
install_vc_step3.png

あとは確認画面を確認してインストールすれば OK です
install_vc_step4.png

さらっと書きましたがインストールまでに数時間平気でかかります
自分は正確に測っていませんが 3 時間以上かかったと思います
install_vc_step5.png

無事インストールが完了したら Visual Studio を起動しましょう
一応起動するときもポイントなのですが、起動するためのファイルが 2 種類あるみたいで「Blend for Visual Studio 2015」と「Start Experimental Instance of Visual Studio 2015」があり、後者を起動しましょう
起動も結構長いので気長に起動を待ってください

コンソールアプリケーションのサンプルプロジェクト作成

簡単なサンプルプロジェクトの作成までやってみましょう
初回起動時は開発する言語やカラーテーマを選択するように言われると思います
開発する言語は「全般」を選択しましょう
カラーテーマは好きなのを選択してください
( すいません、ここのスクリーンショットを撮るのを忘れました )

あと確か Microsoft アカウントでログインも求められると思います
これも任意なのでどちらでも OK です
アカウントがない場合は「後で登録する」みたいな文言のボタンがあったと思うのでそれを選択すれば OK です

起動したら「新しいプロジェクト」を選択します
vs_new_project.png

テンプレートを選択するダイアログが表示されるので

インストール済み -> テンプレート -> Visual C++ -> Windows -> Win32 -> Win32 コンソールアプリケーション

を選択しましょう
vs_select_template.png

プロジェクトの作成がはじまります
アプリケーションウィザードが表示されますが、どんどん進んでいけば OK です
プロジェクトはデフォルトだと「C:\Users\Username\Documents\Visual Studio 2015\Projects」に保存されます

プロジェクトが作成できたらソースファイルを追加しましょう

ソースファイルが作成できたら以下のサンプルコードを記載しましょう
そのままコピペでもいいと思います
ConsoleApplication1.cpp

#include "stdafx.h"

int main() {
    printf("Hello world");
    return 0;
}

記載できたらビルドしてみましょう
右ペインのソリューションエクスプローラーでプロジェクトを選択した状態で

ビルド -> ソリューションのビルド

でビルドできます
成功すれば OK です

これで exe ファイルも作成されているのでコマンドプロンプトで exe ファイルを実行してみてください
実行に成功すると「Hello world」と表示されるはずです

C:\Users\Username\Documents\Visual Studio 2015\Projects\ConsoleApplication1\Debug>ConsoleApplication1.exe
Hello world

はまったポイント

数々のはまったポイントを紹介します

  • Visual C++ の Win32 コンソールアプリケーションが新しいプロジェクト作成時に選択することができない

新しいプロジェクトを作成するときに

インストール済み -> テンプレート -> Visual C++ -> Windows -> Win32 -> Win32 コンソールアプリケーション

がなぜかありません

インストール済み -> テンプレート -> Visual C++ -> Windows -> ユニバーサル

しか選択できずにコマンドプロンプトで実行できる exe ファイルが作成できませんでした
ネットでいろいろ調べると、ちゃんとインストールできていないのが原因らしいとわかりました
ちなみに今となってはわかるのですが、一番はじめにインストールしたときにインストールを「標準」にしていたので、コントーロルパネル -> プログラムのアンインストールから「変更」で足りない機能を追加でインストールしたり、「修復」とか何度も試してみたのですが、結局どれもダメであきらめて再インストールをしました

再インストールするときにはカスタムインストールを選択して、はじめからフルインストールしました

  • 起動するアプリケーションの選択

これはインストール方法の部分でも書きましたが「Start Experimental Instance of Visual Studio 2015」から起動するようにしてください
調べてみると「Blend for」の方は Windows のデスクトップアプリなど GUI アプリを開発するための IDE のようでこれだと Win32 コンソールアプリケーションが作成できないようです
「Start Experimental Instance of Visual Studio 2015」これがすべてのプログラムから選択できない、もしくは存在しない場合はカスタムインストールに失敗している可能性が高いと思います

  • 最新版の IE をインストールする

自分は再インストールしたときに最新版の IE ( ver11) もインストールしました
その後カスタムインストールで必要な機能を全部インストールしたら無事インストールが完了しました
IE が絶対必要だとは考えられないですが、どうしてもうまくインストールできない場合はためしてみるのはありかなと思います

最後に

とにかく動作が重いので何をするにも忍耐が必要です

C や C++ の開発だけであれば別に Visual Studio を使う必要はありません
今回は .lib ファイルをリンカーにしたかったのと、Windows 向けのアプリを開発する必要があったのでどうしても Visual Studio が必要でした

にしても開発するだけなのにこれだけの時間とコストを使うのは割にあわないかなと、もう少し軽量で気軽に使える IDE を作ってほしいなと思いました

2015年12月4日金曜日

AllJoyn 触ってみた

概要

Alljoyn はスマホやデバイス間同士の近傍 P2P を実現するための規格です
元は Qualcomm がオープンソースとして公開した規格で現在は Linux Foundation の AllSeen Alliance という会社が仕切っているようです
今回は導入として iPhone 上で動作する AllJoyn のサンプルアプリを動作させるところまでやってみました

環境

  • Mac OS X 10.10.5
  • Xcode 7.1.1
  • OpenSSL 1_0_2d
  • Alljoyn 14.12.00
  • iPhone 5 ( iOS 7.0.2 )

SDK をビルドする

SDK はサイトからほいとダウンロードしていきなり使える感じではありません
自分でビルドして、できたスタティックライブラリを使っていきます

サイトから SDK をダウンロードする

まずはビルド元になる SDK をダウンロードします
https://allseenalliance.org/framework/download

ここから以下 5 つの iOS 用の zip をダウンロードしてください

  • Core SDK (alljoyn-14.12.00b-osx_ios-sdk.zip)
  • Onboarding SDK (alljoyn-onboarding-service-framework-14.12.00-ios-sdk-rel.zip)
  • Configuration SDK (alljoyn-config-service-framework-14.12.00-ios-sdk-rel.zip)
  • Notification SDK (alljoyn-notification-service-framework-14.12.00-ios-sdk-rel.zip)
  • Control Panel SDK (alljoyn-controlpanel-service-framework-14.12.00-ios-sdk-rel.zip)

ダウンロードが完了したら解凍して適切なパスに配置していきます

  • mkdir -p ~/work_alljoyn
  • cd ~/work_alljoyn
  • mkdir -p alljoyn-ios/core
  • unzip alljoyn-14.12.00b-osx_ios-sdk.zip
  • mv alljoyn-14.12.00b-osx_ios-sdk alljoyn-ios/core/alljoyn
  • unzip alljoyn-config-service-framework-14.12.00-ios-sdk-rel.zip
  • unzip alljoyn-controlpanel-service-framework-14.12.00-ios-sdk-rel.zip
  • unzip alljoyn-notification-service-framework-14.12.00-ios-sdk-rel.zip
  • unzip alljoyn-onboarding-service-framework-14.12.00-ios-sdk-rel.zip
  • pushd alljoyn-ios/

とりあえず問題なく解凍できればここは OK です
初めの work_alljoyn はお好きな名前で大丈夫です

openssl を使って SDK をビルドする

次に解凍した SDK を openssl を使ってビルドします
作業パスは前のコマンドのパスを引き継いでいる想定なので cd とかで移動しないでください

  • git clone git://git.openssl.org/openssl.git
  • git clone https://github.com/sqlcipher/openssl-xcode.git
  • cp -r openssl-xcode/openssl.xcodeproj openssl
  • pushd openssl
  • git checkout tags/OpenSSL_1_0_2d
  • sed -ie 's/\(ONLY_ACTIVE_ARCH.*\)YES/\1NO/' * openssl.xcodeproj/project.pbxproj
  • xcodebuild -configuration Release -sdk iphonesimulator
  • xcodebuild -configuration Release -sdk iphoneos
  • xcodebuild -configuration Release
  • xcodebuild -configuration Debug -sdk iphonesimulator
  • xcodebuild -configuration Debug -sdk iphoneos
  • xcodebuild -configuration Debug

ビルド時間は全部で 20 分くらいかかると思います
すべてビルドが問題なく完了すれば OK です

ビルドおよび Xcode で開発するための環境変数を設定します

ビルドが完了したら環境変数を設定します
ここで設定した環境変数は再起動するとなくなるので、必要な場合は Mac 自体に環境変数を設定してください
ここも作業パスは引き継いでいる想定なので移動せずそのまま作業してください

  • sudo launchctl setenv OPENSSL_ROOT `pwd`
  • export OPENSSL_ROOT=`launchctl getenv OPENSSL_ROOT`
  • popd
  • popd
  • cd alljoyn-ios
  • sudo launchctl setenv ALLJOYN_SDK_ROOT `pwd`
  • export ALLJOYN_SDK_ROOT=`launchctl getenv ALLJOYN_SDK_ROOT`
  • cd services
  • sudo launchctl setenv ALLSEEN_BASE_SERVICES_ROOT `pwd`
  • export ALLSEEN_BASE_SERVICES_ROOT=`launchctl getenv ALLSEEN_BASE_SERVICES_ROOT`

必要なスタティックライブラリを一箇所にコピーする

このあと Xcode でスタティックライブラリ (xxx.a のファイル) を参照するライブラリとして使うのですが、いろいろな場所にあり追加が面倒なので、一箇所にコピーします

結構あるのでコマンド長いです

  • DIST_PATH=”core/alljoyn/build/darwin/armv7/iphoneos/debug/dist/cpp”
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-config-14.12.00-rel/cpp/lib/liballjoyn_services_common_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_config_services_common_cpp.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-controlpanel-14.12.00-rel/cpp/lib/liballjoyn_services_common_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_controlpanel_services_common_cpp.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-notification-14.12.00-rel/cpp/lib/liballjoyn_services_common_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_notification_services_common_cpp.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-onboarding-14.12.00-rel/cpp/lib/liballjoyn_services_common_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_onboarding_services_common_cpp.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-config-14.12.00-rel/objc/lib/liballjoyn_services_common_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_config_services_common_objc.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-controlpanel-14.12.00-rel/objc/lib/liballjoyn_services_common_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_controlpanel_services_common_objc.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-notification-14.12.00-rel/objc/lib/liballjoyn_services_common_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_notification_services_common_objc.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-onboarding-14.12.00-rel/objc/lib/liballjoyn_services_common_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_onboarding_services_common_objc.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/debug/dist/about/lib/liballjoyn_about_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_debug_about_cpp.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/release/dist/about/lib/liballjoyn_about_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_release_about_cpp.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/debug/dist/about/lib/liballjoyn_about_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_debug_about_objc.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/release/dist/about/lib/liballjoyn_about_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_release_about_objc.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/debug/dist/about/lib/libAllJoynFramework_iOS.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/libAllJoynFramework_iOS_debug.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/release/dist/about/lib/libAllJoynFramework_iOS.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/libAllJoynFramework_iOS_release.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-config-14.12.00-rel/cpp/lib/liballjoyn_config_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-config-14.12.00-rel/objc/lib/liballjoyn_config_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-controlpanel-14.12.00-rel/cpp/lib/liballjoyn_controlpanel_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-controlpanel-14.12.00-rel/objc/lib/liballjoyn_controlpanel_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-notification-14.12.00-rel/cpp/lib/liballjoyn_notification_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-notification-14.12.00-rel/objc/lib/liballjoyn_notification_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-onboarding-14.12.00-rel/cpp/lib/liballjoyn_onboarding_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-onboarding-14.12.00-rel/objc/lib/liballjoyn_onboarding_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/

これをやることで Xcode 上で Search Paths を設定するのも少し楽になります
この DIST_PATH はサンプルアプリを開いた時にデフォルトで Search Paths の対象になっています

Xcode の起動

今回 Xcode の起動方法も少しポイントです
環境変数をターミナルで設定している関係で Xcode の起動は環境変数を設定したターミナル上から起動してください

  • open -a xcode

でないと環境変数が xcode にわたらずビルドでエラーになります

Xcode でサンプルアプリを開く

今回開くサンプルアプリはチャットアプリを開きます

$ALLJOYN_SDK_ROOT/core/alljoyn/alljoyn_objc/samples/iOS/AllJoynChat/AllJoynChat.xcodeproj

上記を開きましょう

プロジェクトの設定をする

開いたらプロジェクトの設定を変更します
プロジェクトを選択し

Targets -> AlljoynChat -> Building Settings -> All

と選択して以下を設定していきます

  • Architectures -> Architectures -> Standard architectures (armv7, armv7s) を選択
  • Architectures -> Build Active Architecture only -> Yes を選択
  • Linking -> Other Linker Flags -> -lalljoyn -lajrouter -lBundledRouter.o -lssl -lcrypto を選択
  • Search Paths -> Header Search Paths -> + -> "$(ALLJOYN_SDK_ROOT)/core/alljoyn/build/darwin/arm/$(PLATFORM_NAME)/$(CONFIGURATION)/dist/cpp/inc""$(ALLJOYN_SDK_ROOT)/core/alljoyn/alljoyn_objc/AllJoynFramework/AllJoynFramework/" を追加
  • Search Paths -> Library Search Paths -> + -> "$(ALLJOYN_SDK_ROOT)/core/alljoyn/build/darwin/$(CURRENT_ARCH)/$(PLATFORM_NAME)/$(CONFIGURATION)/dist/cpp/lib""$(OPENSSL_ROOT)/build/$(CONFIGURATION)-$(PLATFORM_NAME)" を追加
  • Apple LLVM 7.0 - Language - C++ -> Enable C++ Exceptions -> No
  • Apple LLVM 7.0 - Language - C++ -> Enable C++ Runtime Types -> No
  • Apple LLVM 7.0 - Language - C++ -> C++ Language Dialect -> Compiler Default
  • Apple LLVM 7.0 - Custom Compiler Flags -> Other C Flags -> Debug -> -DQCC_OS_GROUP_POSIX -DQCC_OS_DARWIN を入力
  • Apple LLVM 7.0 - Custom Compiler Flags -> Other C Flags -> Release -> -DNS_BLOCK_ASSERTIONS=1 -DQCC_OS_GROUP_POSIX -DQCC_OS_DARWIN
  • Apple LLVM 7.0 - Language -> C Language Dialect -> Compiler Default
  • Apple LLVM 7.0 - Language -> Compile Sources As -> Objective-C++

次に

Targets -> AlljoynChat -> Building Phases

と選択して以下を設定していきます

  • Link Binary With Libraries -> + -> で以下のライブラリを追加

    • SystemConfiguration.framework
    • libstdc++.6.0.9.tdb
    • libstdc++.6.tdb
    • libstdc++.tdb
  • Link Binary With Libraries -> + -> Add Other で先ほどコピーしたスタティックライブラリを全部追加

で Xcode 上での設定は完了です
設定から完了したら iPhone 5 を USB で接続して Xcode で実機ビルドをする準備をしましょう

サンプルアプリを動作させる

では実機を接続してビルドしましょう
おそらく特に問題なくビルドできてアプリが起動すると思います
起動するとチャットアプリが立ち上がります
※起動するチャットアプリのイメージはこちら

このチャットアプリは join モードと host モードがあり、join モードの場合は同一ネットワーク上に存在する host モードのデバイスを自動で検索してチャットに参加します
host モードの場合は自分がホストになるので、join モードのデバイスが来るまで待ちます

なのでチャット実際に試したい場合は 2 台のデバイスが必要になります

最後に

感想としては「便利だけど、開発が大変そう」というイメージです
サービスへの応用としてはいろいろ考えられて 3DS みたいなすれちがい通信や HEMS に応用して家に帰った ( 家のネットワークに入った ) ら勝手に電気をつけるなんかもできると思います

ただ、今回触ってみて気づいた点ですが、最新バージョンのデバイスや OS に追従ができていなかったので、その辺の対応速度が遅いとなるとちょっと実用面では厳しいような気もします

あとは今回は実際に SDK を使って AllJoyn アプリを開発していないので開発の難易度や他の SDK とのシナジーなんかもどれくらいあるのかわかっていません

トラブルシューティング

  • iOS9 には対応していません

  • iPhone 6 以上のデバイスにも対応していません
    正確に言うと arm64 のアーキテクチャに対応していません

  • 今回の手順の場合は実機の iPhone 5 ( iOS7 ) でしかおそらく動作しません
    上記のアーキテクチャ問題にも絡んでくるのですが、この AllJoyn のサンプルは環境変数で読み込むライブラリが変わってくるためシミュレータや armv7 以外のアーキテクチャの iPhone だと動作しません
    もう少し話をすると、Xcode 上で設定した Search Paths 上で PLATFORM_NAME や CURRENT_ARCH などの環境変数を使っており、これがデバイスやシミュレータごとに異なるためライブラリを見つけれれずビルドを実行すると
    ld: library not found for -lalljoyn_config_cpp
    みたいな感じでエラーになります

  • コピーするスタティックライブラリや Search Paths を変えればシミュレータでも動作すると思います
    上記の問題を逆に考えるとシミュレータで動作する場合の環境変数がわかり、それを Search Paths と Link Binary With Libraries に追加すれば、シミュレータでも動作すると思います

  • Xcode7 で bit code のエラーが出た場合
    http://qiita.com/satoshi_imanishi/items/8b64af8262d7fe2eb2ba で対応してください

参考サイト