このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
いよいよ今年も最後になった。今日中に開通できるか。
PASV コマンドを引き金として、UPnPNT で登録する。
前作ったループの中身を書き換えてみよう。
TcpConsole も使って行単位の送受信を行う。
TcpConsole *client, *server;
bool pasvReceived = false;
ループの中身はこんな感じに変更。
if (index == 0) { // client
const char *command = client->Read();
if (command == NULL) break; // disconnected
// PASV 要求の検出
if (IsEqualFtpCommand(command, "PASV")) {
pasvReceived = true;
}
} else { // server
const char *command = server->Read();
if (command == NULL) break; // disconnected
// PASV にサーバが成功コード 2xx を返したか。
if (pasvReceived && command[0] == '2') {
// PASV の応答を読み取り待機アドレスを得る。
sockaddr_in dtpAddr;
if (ParsePasvAddress(command, &dtpAddr)) {
// UPnPNAT オブジェクトを利用して登録。
sockaddr_in mappedAddr;
RegisterPortMapping(dtpAddr, &mappedAddr);
// 登録した外部アドレスで返答する
u_short port = ntohs(mappedAddr.sin_port);
char buffer[256];
sprintf(buffer,
"227 Entering Passive Mode"
" (%d,%d,%d,%d,%d,%d)",
(int)mappedAddr.sin_addr.S_un.S_un_b.s_b1,
(int)mappedAddr.sin_addr.S_un.S_un_b.s_b2,
(int)mappedAddr.sin_addr.S_un.S_un_b.s_b3,
(int)mappedAddr.sin_addr.S_un.S_un_b.s_b4,
(int)(port >> 8),
(int)(port & 0xff);
client->Write(buffer);
} else {
// 解析できない場合はそのまま転送。
client->Write(command);
}
} else {
// その他の応答行はそのまま転送。
client->Write(command);
}
pasvReceived = false;
}
さて、テスト。
# telnet <server> <port>
<=P 220 Microsoft FTP Service
C=> USER <user>
<=P 331 Password required for <user>.
C=> PASS <password>
<=P 230 User <user> logged in.
C=> PASV
<=P 227 Entering Passive Mode (222,x,x,x,7,23).
ここでもう一つ telnet を立ち上げる。
# telnet 222.x.x.x 1815
メインの方で
C=> LIST
P<= 150 Opening ASCII mode data connection for /bin/ls.
P<= 226 Transfer complete.
OK。サブの方にファイル一覧が表示された。
どうやらうまく動いているようだ。
ただ、繰り返すとルータの NAT エントリを使い尽くすので、
クリーンアップする方法を考えないといけない。