Jenkins 用 Tool Labels Plugin

先日の RAD Studio Plugin に続き、調子に乗って Tool Labels Plugin を公開いたしました。

このプラグインの機能は、インストール済みツールによりノードに動的にラベルを追加するというものです。ツールのインストール有無によりビルドを実行するノードを限定するのが目的で製作しました。

実を言えば、RAD Studio Plugin の新機能として企画していたのですが、他のツールにも使えることに気づいて、急遽 独立したプラグインに仕立てたものなのですけどね。例えば、RAD Studio XE7 に bds15.0 というラベルを付けておくと、インストール済みノードに動的にこのラベルが付くので、ビルドを実行するノードを限定するのに使えるようになる訳です。

便利だと感じたらフィードバックをいただけるとありがたいです。

IPv6 ソケット API プログラミングの基礎知識 (シリーズ第 2 回)

IPv6 ソケット API を使うための構造体を紹介した前回に続きまして、第 2 回はサーバーでは必須となる特定ポートへのバインドの基本的なやり方について書いてみます。

まず、sockaddr_in6 構造体を用意しなくてはなりませんが、今回はよく利用されるバインドするアドレスを指定しないやり方を扱うことにします。一般的なソケット API プログラミングと同様に <netinet/in.h> ヘッダーをインクルードすると (前回は書きましたっけ? ^^;)、in6addr_any オブジェクトを利用することができます。

const struct in6_addr in6addr_any;

このオブジェクトは IPv4 での INADDR_ANY に相当するものですが、IPv6 では構造体になので少しばかり勝手が異なります。例としてはこのように使います:

#include <netinet/in.h>
#include <arpa/inet.h> /* htons のため */

#define PORT ポート番号

int bind_in6_example1(int socket_fd) {
    struct sockaddr_in6 sa = {0}; /* 全メンバーを 0 に初期化 */
    sa.sin6_family = AF_INET6;
    sa.sin6_port = htohs(PORT);
    sa.sin6_flowinfo = 0; /* 初期化済みなので実際には不要 */
    sa.sin6_addr = in6addr_any;
    sa.sin6_scope_id = 0; /* 初期化済みなので実際には不要 */
    return bind(socket_fd, (const struct sockaddr *) &sa,
            sizeof (struct sockaddr_in6));
}

in6addr_any はオブジェクトですが、初期化子として利用する場合のために IN6ADDR_ANY_INIT マクロも用意されています。C99 で導入された記法を使うと、例えば次のように書くことができます:

#include <netinet/in.h>
#include <arpa/inet.h> /* for htons */

#define PORT ポート番号

static const struct sockaddr_in6 sa_init = {
    .sin6_family = AF_INET6,
    .sin6_flowinfo = 0, /* 暗黙的に初期化されるので実際には不要 */
    .sin6_addr = INADDR6_ANY_INIT,
    .sin6_scope_id = 0, /* 暗黙的に初期化されるので実際には不要 */
};

int bind_in6_example2(int socket_fd) {
    struct sockaddr_in6 sa = sa_init;
    sa.sin6_port = htohs(PORT);
    return bind(socket_fd, (const struct sockaddr *) &sa,
            sizeof (struct sockaddr_in6));
}

IPv4 の INADDR_ANY とは違って、初期化と代入で書き方が異なることに注目してくださいね。

それでは第 2 回はここまでです。例によって次回も期待しないで待っていてください。

Android Emulator でスクリーンショットが…

Android Emulator でアプリの公開用スクリーンショットを撮ろうといろいろ試してみたのだが、Host GPU を使う設定にすると Android SDK の機能ではどうやっても無理という結論に到達しました。

Host GPU を使わない設定では動作しないアプリだし、高速なエミュレーターの使える x86 版も出せないので、もう残る手段はホスト上に表示されたウィンドウ画像をキャプチャするぐらいしか思いつきませんね。

IPv6 ソケット API プログラミングの基礎知識 (シリーズ第 1 回)

xllmnrd を製作する過程で習得した IPv6 ソケット API に関する知見を、少しずつ書いていこうという不定期連載企画です。反応が薄ければ うやむやにするかもしれませんが…。

さて記念すべき第 1 回ですが、まずは sockaddr_in6 構造体の紹介で始めたいと思います。IPv4 の sockaddr_in 構造体に対応するものですが、この構造体には以下のメンバーがあります (OS によっては他のメンバーがあることもありますが ここでは触れません):

sa_family_t sin6_family;
アドレスファミリーです。IPv6 では AF_INET6 を指定します。
in_port_t sin6_port;
ポート番号です。IPv4 と同様にネットワーク バイト オーダーで指定します。
uint32_t sin6_flowinfo;
これは IPv6 に特有のメンバーで、トラフィック クラスとフロー情報を指定します。とりあえず 0 としておきましょう。
struct in6_addr sin6_addr;
お待ちかね、IPv6 アドレスです。in6_addr 構造体については後述します。
uint32_t sin6_scope_id;
これも IPv6 に特有のメンバーで、スコープ ID を指定します。スコープを指定する必要がない場合は 0 としておきます。

IPv6 アドレスを指定する in6_addr 構造体には以下のメンバーがあります:

uint8_t s6_addr[16];
IPv6 アドレスをバイト列で指定します。IPv4 とは違ってバイト列なので、バイト オーダーは意識する必要がありません。

第 1 回はここまでにしておきます。次回はいつになるか分かりませんが、期待しないで待っていてください。

racoon でらくらく iPhone VPN

BSD 系 OS や GNU/Linux 上の racoon を利用して、iPhone 等から IPSec VPN で接続可能にする設定を試行錯誤の末に発見したので公開してみます。(もしうまく接続できなければコメントで質問してください。)

[訂正] 初出時の内容に誤りもしくは不適切な部分がありましたので該当部分を訂正しました。

サーバー側の設定

まず racoon.conf の remote ノード指定を次のように書きます。(重要部分は太字で強調してあります。またホスト名や IP アドレスは記述例ですのでお使いの環境に合わせて書き換えてください。)

remote "server"anonymous {
    exchange_mode main, aggressive;
    my_identifier fqdn "server.example.com";
    mode_cfg on;
    passive on;
    generate_policy on;
    nat_traversal on;
    proposal {
        encryption_algorithm aes;
        hash_algorithm sha1;
        authentication_method xauth_psk_server;
        dh_group modp1024;
    }
}

次に sainfo 指定を次のように書きます。(pfs_group はお好みで追加してください。筆者は pfs_group modp1024 しか試していません。PFS は iOS では使えませんでした。)

sainfo anonymous {
    encryption_algorithm aes;
    authentication_algorithm hmac_sha1;
    compression_algorithm deflate;
}

最後に mode_cfg を次のように書きます。(auth_source 等はお好みで追加してください。筆者は auth_source pam しか試していません。)

mode_cfg {
    network4 198.51.100.0;
    netmask4 255.255.255.0;
    dns4 198.18.0.1;
    split_network include 198.51.100.0/24;
    default_domain "remote.example.com";
}

そしてもう一つ、psk.txt に次の行を追加してください。

グループ名 秘密鍵

例えば次のような記述になります。

iphone opensesame

iOS 側の設定

iOS の VPN 構成で IPSec を選択して各項目を次のように設定します。

  • 説明: 適当に決めてください。
  • サーバ: racoon を実行しているサーバーのホスト名を指定します。動的 DNS を利用している場合は、そのホスト名でもとりあえず OK です。
  • アカウント: サーバー上の自分のアカウント名を指定します。
  • パスワード: 空欄のままで OK です。(iOS の不具合なのか、ここで指定しても接続ごとに入力を要求されます。)
  • 証明書を試用: オフにします。
  • グループ名: psk.txt に追加した行のグループ名を指定します。
  • シークレット: psk.txt に追加した行の秘密鍵を指定します。

以上を設定したら保存して設定完了です。

Java SE 8 の非互換性

まず Java SE 7 の java.lang.refrect.TypeVariable と Java SE 8 の java.lang.refrect.TypeVariable を比べてほしい。簡潔に書けば Java SE 8 で getAnnotatedBounds() が追加されたことが分かるはずである。

このように既存のインターフェースにメソッドが追加された場合、このインターフェースを実装するクラスはそのままでは Java SE 8 でコンパイルできなくなってしまう。通常なら追加されたメソッドの実装を追加すれば解決するのであるが、ここで getAnnotatedBounds() の戻り型 AnnotatedType[] に注目してほしい。java.lang.reflect.AnnotatedType は Java SE 8 で追加されたので、Java SE 7 には存在していない。つまり getAnnotatedBounds() を実装してしまうと Java SE 7 ではもうコンパイルできなくなってしまうのである。何という非互換性だろうか。

本来なら新しいメソッドを追加した別のインターフェースを追加するか、Java SE 7 のクラス実装のままでもコンパイル可能なようにデフォルト メソッドを提供するべきだったのでしょうが、そこまで気が回らなかったんでしょうかねえ。

 

GlassFish 構成の紹介

せっかく Jenkins が復旧したことなので、このサイトで使っている GlassFish の構成を紹介してみようと思います。

まず GlassFish の「ドメイン」には管理サーバーがあるわけですが、これは表に出していません。管理サーバーとは別にクラスター インスタンスと今回新たに追加したスタンドアローン インスタンスがそれぞれ別の java プロセスで動作していています。それぞれのインスタンスには AJP (mod_jk) 対応のリスナーが追加してあり、フロントエンドの Web サーバーから間接的にアクセスするように設定しています。

結局 3 個の Java プロセスが動いているということになるわけですが、運用の勉強のつもりで動かしているクラスターは、実際にクラスターを組めるほどのインスタンス数がないので、将来的にはスタンドアローン インスタンスに一元化してしまうかもしれません。

Jenkins 復旧

GlassFish アップデートで障害発生から止まっていた Alfa.linuxfront.com の Jenkins がようやく復旧しました。

何が問題を起こしていたのかを簡潔に書けば、GlassFish 4.1 のクラスター インスタンスに配置していたために Jenkins初期化に失敗していたということでした。単一のスタンドアローン インスタンスに配置替えをしたことにより初期化に失敗することもなくなり、ひとまず平常運転に戻れそうです。

不思議なのは、前バージョンの GlassFish 4.0 ではクラスター インスタンスでも動いてたってことなんですよね。4.1 で動作が変わったのでしょうか。