このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
続いてセキュリティハンドシェイクだ。
これはセキュリティの種類の決定と、
実際のセキュリティ処理の 2 段階で行われる。
ということは、これらを異なるクラスに分解する必要がある。
後者は SecurityHandler インタフェースの実装で表現可能だ。
前者は、後者のインスタンスを保持することで
セキュリティの種類の決定を行い、
適切な処理を呼び出すというクラスにすればよい。
========== SecurityHandshake.java ==========
package jp.loafer.rfb.server;
import java.io.IOException;
import jp.loafer.rfb.RFBContext;
import jp.loafer.rfb.RFBHandler;
import jp.loafer.rfb.io.RFBInputStream;
import jp.loafer.rfb.io.RFBOutputStream;
/**
* サーバ側セキュリティハンドシェイク。
* @author kes
*/
public class SecurityHandshake implements RFBHandler {
/**
* 決まったセキュリティ処理を行うインスタンスを作成。
* @param handler 唯一のセキュリティ処理。
*/
public SecurityHandshake(SecurityHandler handler) {
if (handler == null) throw new NullPointerException();
handlers = new SecurityHandler[] { handler };
}
/**
* 複数の中から選択可能なセキュリティ処理を行うインスタンスを作成。
* @param handlers
*/
public SecurityHandshake(SecurityHandler[] handlers) {
if (handlers == null) throw new NullPointerException();
if (handlers.length == 0) throw new IllegalArgumentException();
for (SecurityHandler h : handlers) {
if (h == null) throw new NullPointerException();
}
this.handlers = handlers;
}
/**
* @see RFBHandler#execute(RFBContext, RFBInputStream, RFBOutputStream)
*/
public void execute(RFBContext context, RFBInputStream in,
RFBOutputStream out) throws IOException {
SecurityHandler handler = null;
if (context.getVersion() >= 3007) {
// 3.7 以降は複数から選択可能
out.writeU8(handlers.length);
for (SecurityHandler h : handlers) {
out.writeU8(h.getType());
}
out.flush();
// クライアントが 1 つ選択
int type = in.readU8();
for (SecurityHandler h : handlers) {
if (h.getType() == type) {
handler = h;
break;
}
}
if (handler == null) // 不正な選択
throw new IOException("Unexpected security type.");
} else {
// 3.3 以前は 1 つのみ
handler = handlers[0];
out.writeU32(handler.getType());
out.flush();
// クライアントは選択できない
}
// セキュリティ処理
handler.execute(context, in, out);
}
private SecurityHandler[] handlers;
}
========== end of SecurityHandshake.java ==========
SecurityHandshake はサーバがサポートする形式を、
ハンドラの配列としてコンストラクタで受け取る。
実際のセキュリティ処理は、ハンドラが行うため、
SecurityHandshake は処理の選択と決定を行うだけである。
セキュリティハンドシェイクは、
RFB のバージョンによってかなり異なる部分である。
特に、RFB 3.3 と 3.7 以降の差は大きく、
3.7 以降は複数の中から選択させることができるが、
3.3 では常にサーバが決定した 1 つしか使えない。
複数のバージョンのクライアントに対応するために、
3.3 クライアントに対しては、
ハンドラの配列の先頭の要素を使うことにしよう。
こうすることで、ある程度の柔軟性が確保できる。