このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
今日はもう一つの壁 UPnPNT を C++ で実装する。
面倒なので、関数化しておく。今のところ汎用じゃないけど。
void RegisterPortMapping(const sockaddr_in &localAddr, sockaddr_in *externalAddr) {
// 内部ホストの文字列 IP と、自然表現のポート番号を得る。
char *localIP = inet_ntoa(localAddr.sin_addr);
u_short localPort = ntohs(localAddr.sin_port);
// COM の初期化
CoInitialize(NULL);
// UPnPNAT オブジェクトの作成。
IUPnPNAT *nat;
CoCreateInstance(CLSID_UPnPNAT, NULL, CLSCTX_ALL, IID_IUPnPNAT, (void **)&nat);
// IStaticPortMappingCollection インタフェースの取得。
IStaticPortMappingCollection *maps;
nat->get_StaticPortMappingCollection(&maps);
// エラー処理をしていないが、利用できない場合 maps に NULL が返る。
// COM 用に BSTR を割り当てる。
WCHAR localIPWideString[16];
MultiByteToWideChar(CP_ACP, 0, localIP, -1, localIPWideString, 16);
BSTR localIPBstr =
SysAllocString(localIPWideString);
BSTR proto = SysAllocString(L"TCP");
BSTR description = SysAllocString(L"FTP Proxy");
// 空きポートを自動的に割り当てることはできないらしいので、
// 片っ端に適当に空きポートを探してマッピング。
IStaticPortMapping *map;
long externalPort = 1024;
HRESULT result = S_OK;
do {
// choice between 1024 and 4095
externalPort = 1024 + (long)((double)rand() * 3072 / (RAND_MAX + 1));
result = maps->Add(externalPort, proto, localPort, localIPBstr,
VARIANT_TRUE, description, &map);
} while (SUCCEEDED(result));
// BSTR の解放。
SysFreeString(description);
SysFreeString(proto);
SysFreeString(localIPBstr);
// 外部 IP の文字列表現を得る。
BSTR externalIPBstr;
char externalIPString[16];
map->get_ExternalIPAddress(&externalIPBstr);
WideCharToMultiByte(CP_ACP, 0, externalIPBstr, -1, externalIPString, 16, NULL, NULL);
SysFreeString(externalIPW);
externalAddr->sin_family = AF_INET;
externalAddr->sin_port = htons(externalPort);
externalAddr->sin_addr.s_addr = inet_addr(externalIPString);
// オブジェクト解放しまくり。
map->Release();
maps->Release();
nat->Release();
// COM の後処理
CoUninitialize();
}
エラー処理などがないのは置いといても、変換が多くてコードが汚い汚い。
sockaddr_in や COM のラッパとか作りたいものがたくさんある。
ま、そのあたりは後で実装しようか。今日はテストできてないなぁ。