2016年1月23日土曜日

go1.5.2 で開発環境構築2

今回は環境設定にあるoracle のダウンロードと、それをビルドするために必要なパッケージのダウンロードについて。
go get -u golang.org/x/tools/cmd/oracle
go get golang.org/x/tools/cmd/goimports
go get golang.org/x/net/html
go get golang.org/x/net/websocket
go get golang.org/x/text
go get golang.org/x/crypto
とりあえず、上記のパッケージを入れたら、ビルドエラーは消えました。
あと、ちょっと時間空けてgo を触り直してまたハマった所としては、package を新規作成した場合、go ファイルの先頭が、package xxx といった記載になるが、このままbuild すると、bin フォルダにバイナリファイルが無い、と怒られる。
以下のような感じ。

これは、前回も記載したが、package xxx の部分をpackage main に変更すれば、bin フォルダにバイナリファイルが生成され、実行可能となる。

2016年1月11日月曜日

go1.5.2 で開発環境構築1

以下の環境で、golang の環境を構築しました。
---------------------------------------------
Mac: 10.9.5
Java: 1.8.0_65
Eclipse:
Version: Mars.1 Release (4.5.1)
Build id: 20150924-1200
GoClipse: 0.13.0.v201510291605
gdb: 7.10.1
---------------------------------------------

以下のリンクより、Go をインストール。
「インストールの確認」までを実施。
http://golang.jp/install
GOROOT は、Go がインストールされたディレクトリのルートディレクトリを設定。
私はデフォルト通りのため、「/usr/local/go」を設定。
GOPATH は自分が生成するプロジェクトのパスを指定する。
私の場合は、/workspace/go/test というtest プロジェクトを作成したので、「/workspace/go/test」を設定。

次に以下のリンクから、Eclipse の「Eclipse IDE for Java EE Developers」をダウンロード。
https://eclipse.org/downloads/
Eclipse を起動するとき、GoClipse がJava8 で動作させる必要があるため、以下からJava8 をダウンロードしてインストール。
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
Java8 の設定は、以下のリンクを参照。
http://qiita.com/deonathg/items/31d1ef610e429e3da7b0

Eclipse を起動させて、GoClipse をインストールするために、メニューバー > Help より、以下を選択。

以下のようにGoClipse のURL をセットしてやり、前の画面に戻ると、URL 上に存在するSoftware が出力されるので、GoClipse を選択します。


途中で、別のSoftware をインストールしなければいけない、という警告等がでますが、気にせずOKを押してインストールします。
インストールが完了すると、Eclipse の再起動を促されますので、再起動します。
次にGoClipse の設定をするため、Eclipse > 環境設定 を開き、以下のように設定します。

また、Go の入力補完をするために、gocode をインストールします。
しかし、GoClipse 上で以下の画面の下の部分の「Download go get (...)」を押してもNo such directory とかでエラーが出てインストールできませんでした。
そのため、私はterminal 上から、gocode をインストールしました。
まずは、~/.bash_profile に、GOPATH として、以下を設定します。
/workspace/go/test/gocode
このパスを設定後、以下のコマンドでgocode をインストールします。
go get -u github.com/nsf/gocode
これで、/workspace/go/test/bin 以下に、gocode のバイナリファイルと、src フォルダ以下に、gocode のコードが配置されます。
このバイナリが配置されたパスを、上記の図のように、GoClipse の設定に反映させます。
最後にデバッグするために、gdb を導入します。
gdb は、homebrew を使ってインストールしました。
brew install gdb
後は、以下のリンクを元に、Gatekeeper の設定をしてあげればデバッグできるようになります。
http://blog.amedama.jp/entry/2015/10/06/231038

あと、ハマってしまったところとしては、go install を実行するとき(Eclipse 上でDebug ボタンを押すと実行される)に、パッケージ名がmain でないとbin フォルダにバイナリが生成されませんでした。
理由はわかりませんが、解消したら追記しようと思います。

2016年1月3日日曜日

homebrew のupdate とgit のupgrade

以下のコマンドで、Mac にインストールされているbrew をupdate。
homebrew update

以下のコマンドで、git をupgrade。
git upgrade

homebrew の仕組みを理解しておかないと、homebrew でインストールしたgit を使えません。
homebrew はgit を/usr/local/bin にインストールします。
しかし、PATH を/usr/local/bin を優先するように/etc/paths ファイルを編集する必要があります。
下記のように、/usr/local/bin をファイルの先頭に記載します。sudo 権限が必要です。
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin

この後、以下のコマンドでgit のバージョンを確認してください。
git --version

2015年10月14日水曜日

Keystore と秘密鍵と公開鍵の関係について

Java では、Keytool という鍵と証明書を管理するためのユーティリティを利用して、SSL やTLS などの暗号化通信を実現します。

SSL/TLS 通信は、以下のステップで実現されます。(Server Hello Done までを記載)

Client Hello
Server Hello
Server Certificate
Server Hello Done
Client Hello で、どの暗号化スイートを利用して通信したいかを問い合わせます。


Server Hello で、暗号化スイートを決定し、Server Certificate でサーバ証明書を渡します。



このサーバ証明書を作成するために、Keytool を使います。

サーバ証明書は、認証局の署名が必要です。 企業は正規の業者から署名をしてもらいますが、テスト時やインターナルな環境では、必ずしも正規の業者からの署名は必要ないかもしれません。

そのような場合、通称「オレオレ認証局」という、自作認証局を作成して、サーバ証明書に署名をすることになります。

オレオレ認証局の作成の仕方は他のサイトを見て頂くことにしますが、大きく2通りのやり方が公開されています。 1つは、OpenSSL とPerl を利用して認証局を構築するやり方。
もう1つは、OpenSSL のみで構築するやり方。

どちらでも構築はできますので、調べてみてください。
で、Keytool を利用し、Keystore を生成する場合、以下の2種類のエントリが存在します。
PrivateKeyEntry
TrustedCertEntry
暗号化通信をする場合に必要となるエントリは、PrivateKeyEntry になります。 これは、公開鍵と秘密鍵のペアのエントリになります。

以下では、Keystore ファイルの生成方法の概要を記載します。
サーバ管理者が秘密鍵を生成
サーバ管理者が秘密鍵から証明書署名要求ファイルを生成
オレオレ認証局は自分の秘密鍵で証明書署名要求ファイルに署名してサーバ証明書を生成
サーバ管理者はサーバ証明書とサーバ管理者側の秘密鍵を利用して、公開鍵と秘密鍵のペアファイルを生成
生成するKeystore ファイルにペアファイルをインポート

具体的なコマンドは以下の通り。
openssl genrsa -des3 -out private.key
openssl req -new -days 3650 -key private.key -out server.csr
openssl req -keyout ca/cakey.pem -out ca/cacert.pem -new -x509
openssl ca -in server.csr -keyfile ca\cakey.pem -cert ca\cacert.pem –out server.crt
openssl pkcs12 -inkey private.key -in server.crt -export -out pair.pkcs12
keytool -importkeystore -srckeystore pair.pkcs12 -srcstoretype PKCS12 -destkeystore keystore
※下記の修正は事前にしておくこと。
修正1:openssl.cnf を開いて、ca のディレクトリを指定する。(実行フォルダにca フォルダを新規で作成しておく)
[ CA_default ]
dir  = ./ca  # Where everything is kept
修正2:空のindex.txt ファイルを./ca に配置しておく。
修正3:4桁以上の数字が記入されたserial というファイル名(拡張子無し)のファイルを./ca に配置しておく。

2015年5月26日火曜日

Java1.7 Compile で検知できないキャストエラーについて

Java1.6 で動作しているJenkins で、ビルドがコケた。
理由は、キャストエラー。これをJava1.7 のデフォルトではコンパイルエラーとして表示してくれないため、開発環境ではエラーがでないが、Java1.6 でBuild したらコケる。


以下、テストコード
package test;

import java.util.Map;
import java.util.HashMap;

public class Test {
    public static void main(String args[]) {
     Map result = new HashMap();
     result.put("key",new Integer(2));
     int errorCode = (int)result.get( "key" );
     System.err.println("errorCode: " + errorCode);
    }
}

で、問題は以下の部分。
int errorCode = (int)result.get( "key" );

以下のようにキャストすべき。
int errorCode = (Integer)result.get( "key" );

-source option に1.6 を指定すると、キャスト失敗。
javac -source 1.6 -bootclasspath "C:\Program Files\Java\jdk1.7.0_67\jre\lib\rt.jar" Test.java
Test.java:11: エラー: 変換できない型
        int errorCode = (int)result.get( "key" );
                                       ^
  期待値: int
  検出値:    Object
エラー1個

しかし、source を1.7 に指定すれば、コンパイルに問題は起きない。
javac -source 1.7 -bootclasspath "C:\Program Files\Java\jdk1.7.0_67\jre\lib\rt.jar" Test.java

で、開発中にどうやってこれを検知するか(コンパイルエラーとして表示させるか)という点ですが、 Eclipse の以下の設定で、実行環境をJava1.7 から、1.6 に変更すれば検知可能です。
Right click on the project > Build Path > Java Build Path > Libraries

2015年5月18日月曜日

XMLStreamReader が持つXML をファイル出力する場合

[ 解決課題 ]
XML に問題があり、ファイル退避、かつ、問題箇所以降のXML を読み込みたい。

[ 検討結果 ]
ファイル退避、もしくはXML の読み込みのどちらかを選択する必要がある。 両方実施したい場合は、自前パーサーを作成する必要がある。

[ 処理内容 ]
前提として、reader は元から存在するものとし、XML 情報を持つとする。
 StringWriter sw と、XMLStreamWriter writer を準備して、Transformer class を利用して、 transform method をCall するとsw にXML 情報が入力される。
これをtoString() してあげれば、XML の出力が可能。

 しかし、問題点があり、transform() をCall すると、XMLStreamReader reader の情報がすべて失われてしまう。
そのため、XML のある1箇所に問題があり、すべてのXML を出力、かつ、問題の箇所以降のXML を再読み込みすることができない。
 DeepCopy もできないため(*1)、2回XML の読み込みをしたい場合は、StringWriter にすべて書きだした後に、 自前のパーサーを作って処理を実行しないといけない。

*1) http://stackoverflow.com/questions/9837861/how-to-remember-xmlstreamreader-position-in-xml-with-stax

public void parse(XMLStreamReader reader){
 StringWriter sw = new StringWriter();
 StAXSource source = new StAXSource( reader );
 XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();
 XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
 XMLStreamWriter writer;
 String rawxml = null;
 try {
     XMLStreamReader re = xmlInputFactory.( reader );
     writer = xmlOutputFactory.createXMLStreamWriter( sw );
     TransformerFactory tf = TransformerFactory.newInstance();
     Transformer t = tf.newTransformer();
     StAXResult result = new StAXResult( writer );
     t.transform( source, result );
     rawxml = sw.toString();
    } catch ( XMLStreamException e ) {
     e.printStackTrace();
    } catch ( TransformerConfigurationException e ) {
     e.printStackTrace();
    } catch ( TransformerException e ) {
     e.printStackTrace();
    }
} 

2015年5月8日金曜日

Java でClose したPort にアクセスした場合について

閉じているポートにアクセスすると、以下のException がでる。
java.net.ConnectException: Connection refused: connect
 at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
 at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
 at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
 at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
 at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
 at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
 at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
 at java.net.Socket.connect(Socket.java:579)

では、これはなぜおこるのか、というと以下の記載がありました。
http://docs.oracle.com/cd/E19455-01/806-2720/msgs-175/index.html

[ 抜粋 ]
[ 原因 ]
対象のマシンが拒否したため、接続できません。
アクティブでないサービスに接続しようとした場合、または要求したアドレスにサービスプロセスが存在しなかった場合に起こります。

[ 対処方法 ]
対象のマシン上のサービスをアクティブにするか、またはサービスがなくなっていた場合は再度起動します。
セキュリティ上の理由からこのサービスを提供したくない場合は、ユーザーグループにそのことを伝え、できれば代替サービスを提供します。

では、なぜConnection refused になるのでしょうか?
その答えは以下に有りました。
http://www5d.biglobe.ne.jp/stssk/rfc/rfc793j.html

[ 抜粋 ]
1.  If the connection does not exist (CLOSED) then a reset is sent
    in response to any incoming segment except another reset.  In
    particular, SYNs addressed to a non-existent connection are rejected
    by this means.

つまり、CLOSED の状態のポートにアクセスすると、リセットがレスポンスとしてアクセス元に送られるそうです。

で、リセットって何?とググると、以下が出てきました。
http://e-words.jp/w/RST%E3%83%91%E3%82%B1%E3%83%83%E3%83%88.html

[ 抜粋 ]
TCPで接続を中断・拒否する際に送られるパケット。
TCPヘッダの制御フラグでRSTフィールドがセットされたパケットのこと。
接続要求を拒絶したり、確立された接続を一方的に切断する際に送られるもの。

最後に、ポートを閉じている、とはどういう状態か、という点に関しては、RFC793 ではCLOSED の状態である、ということでした。