Commit 63799992 authored by nanahira's avatar nanahira

add srv record support

parent 71712066
......@@ -8,6 +8,9 @@
#include "game.h"
#include "replay.h"
#include "replay_mode.h"
#ifdef _WIN32
#include <Windns.h>
#endif
namespace ygo {
......@@ -4065,4 +4068,96 @@ void DuelClient::BroadcastReply(evutil_socket_t fd, short events, void * arg) {
}
}
}
unsigned int DuelClient::LookupHost(char *host) {
unsigned int remote_addr = htonl(inet_addr(host));
if(remote_addr == -1) {
struct evutil_addrinfo hints;
struct evutil_addrinfo *answer = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = EVUTIL_AI_ADDRCONFIG;
int status = evutil_getaddrinfo(host, NULL, &hints, &answer);
if (status != 0) {
return 0;
}
sockaddr_in * sin = ((struct sockaddr_in *)answer->ai_addr);
char ip[20];
evutil_inet_ntop(AF_INET, &(sin->sin_addr), ip, 20);
remote_addr = htonl(inet_addr(ip));
evutil_freeaddrinfo(answer);
}
return remote_addr;
}
bool DuelClient::LookupSRV(char *hostname, HostResult* result) {
char resolved[100];
#ifdef _WIN32
PDNS_RECORD ret;
DNS_STATUS status = DnsQuery_UTF8(hostname, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &ret, NULL);
if(status != 0)
return false;
memcpy(resolved, ret->Data.SRV.pNameTarget, 100);
result->port = ret->Data.SRV.wPort;
DnsRecordListFree(ret, DnsFreeRecordListDeep);
#else
struct __res_state res;
int status = res_ninit(&res);
if(status != 0)
return false;
unsigned char answer[1024];
status = res_nsearch(&res, hostname, C_IN, T_SRV, answer, sizeof(answer));
if(status < 0)
return false;
ns_msg nsMsg;
ns_initparse(answer, status, &nsMsg);
bool found = false;
std::vector<RetrivedSRVRecord> records;
unsigned short minPriority = 0xffff;
for(int i = 0; i < ns_msg_count(nsMsg, ns_s_an); i++) {
auto record = RetrivedSRVRecord(nsMsg, i);
if(!record.valid || record.priority > minPriority)
continue;
for (int j = 0; j < record.weight; ++j) {
if(record.priority < minPriority) {
records.clear();
minPriority = record.priority;
}
records.push_back(record);
}
}
if (!records.size())
return false;
rnd.reset((unsigned int)time(nullptr));
rnd.shuffle_vector(records);
auto record = records.front();
memcpy(resolved, record.host, 100);
result->port = record.port;
#endif
result->host = LookupHost(resolved);
return true;
}
HostResult DuelClient::ParseHost(char *hostname) {
HostResult result;
auto trySplitter = strchr(hostname, ':');
if(trySplitter == NULL) {
char srvHostname[114];
sprintf(srvHostname, "_ygopro._tcp.%s", hostname);
if(!LookupSRV(srvHostname, &result)) {
result.host = LookupHost(hostname);
result.port = 7911;
}
} else {
char host[100];
auto hostLength = trySplitter - hostname;
strncpy(host, hostname, hostLength);
host[hostLength] = '\0';
result.host = LookupHost(host);
result.port = atoi(trySplitter + 1);
}
return result;
}
}
......@@ -17,6 +17,45 @@
namespace ygo {
class HostResult {
public:
unsigned int host;
unsigned short port;
bool isValid() {
return host > 0 && port > 0;
}
HostResult() {
host = 0;
port = 0;
}
};
#ifndef _WIN32
#include <resolv.h>
#include <arpa/nameser.h>
#include <arpa/nameser_compat.h>
class RetrivedSRVRecord {
public:
bool valid;
unsigned short priority;
unsigned short weight;
unsigned short port;
char host[100];
RetrivedSRVRecord(ns_msg nsMsg, int i) {
valid = false;
ns_rr rr;
if (ns_parserr(&nsMsg, ns_s_an, i, &rr) < 0 || ns_rr_type(rr) != T_SRV)
return;
priority = ns_get16(ns_rr_rdata(rr));
weight = ns_get16(ns_rr_rdata(rr) + NS_INT16SZ);
port = ns_get16(ns_rr_rdata(rr) + 2 * NS_INT16SZ);
if (dn_expand(ns_msg_base(nsMsg), ns_msg_end(nsMsg), ns_rr_rdata(rr) + 3 * NS_INT16SZ, host, sizeof(host)) < 0)
return;
valid = true;
}
};
#endif
class DuelClient {
private:
static unsigned int connect_state;
......@@ -51,6 +90,9 @@ public:
static void SetResponseI(int respI);
static void SetResponseB(void* respB, unsigned char len);
static void SendResponse();
static unsigned int LookupHost(char *host);
static bool LookupSRV(char *hostname, HostResult *result);
static HostResult ParseHost(char *hostname);
static void SendPacketToServer(unsigned char proto) {
char* p = duel_client_write;
BufferIO::WriteInt16(p, 1);
......@@ -84,7 +126,6 @@ public:
static int RefreshThread(event_base* broadev);
static void BroadcastReply(evutil_socket_t fd, short events, void* arg);
};
}
#endif //DUELCLIENT_H
......@@ -177,10 +177,8 @@ bool Game::Initialize() {
lstHostList->setItemHeight(18);
btnLanRefresh = env->addButton(rect<s32>(240, 325, 340, 350), wLanWindow, BUTTON_LAN_REFRESH, dataManager.GetSysString(1217));
env->addStaticText(dataManager.GetSysString(1221), rect<s32>(10, 360, 220, 380), false, false, wLanWindow);
ebJoinHost = env->addEditBox(gameConf.lasthost, rect<s32>(110, 355, 350, 380), true, wLanWindow);
ebJoinHost = env->addEditBox(gameConf.lasthost, rect<s32>(110, 355, 420, 380), true, wLanWindow);
ebJoinHost->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
ebJoinPort = env->addEditBox(gameConf.lastport, rect<s32>(360, 355, 420, 380), true, wLanWindow);
ebJoinPort->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
env->addStaticText(dataManager.GetSysString(1222), rect<s32>(10, 390, 220, 410), false, false, wLanWindow);
ebJoinPass = env->addEditBox(gameConf.roompass, rect<s32>(110, 385, 420, 410), true, wLanWindow);
ebJoinPass->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
......@@ -1272,7 +1270,6 @@ void Game::LoadConfig() {
gameConf.numfont[0] = 0;
gameConf.textfont[0] = 0;
gameConf.lasthost[0] = 0;
gameConf.lastport[0] = 0;
gameConf.roompass[0] = 0;
gameConf.bot_deck_path[0] = 0;
//settings
......@@ -1333,9 +1330,6 @@ void Game::LoadConfig() {
} else if(!strcmp(strbuf, "lasthost")) {
BufferIO::DecodeUTF8(valbuf, wstr);
BufferIO::CopyWStr(wstr, gameConf.lasthost, 100);
} else if(!strcmp(strbuf, "lastport")) {
BufferIO::DecodeUTF8(valbuf, wstr);
BufferIO::CopyWStr(wstr, gameConf.lastport, 20);
} else if(!strcmp(strbuf, "roompass")) {
BufferIO::DecodeUTF8(valbuf, wstr);
BufferIO::CopyWStr(wstr, gameConf.roompass, 20);
......@@ -1456,8 +1450,6 @@ void Game::SaveConfig() {
fprintf(fp, "serverport = %d\n", gameConf.serverport);
BufferIO::EncodeUTF8(gameConf.lasthost, linebuf);
fprintf(fp, "lasthost = %s\n", linebuf);
BufferIO::EncodeUTF8(gameConf.lastport, linebuf);
fprintf(fp, "lastport = %s\n", linebuf);
//settings
fprintf(fp, "automonsterpos = %d\n", (chkMAutoPos->isChecked() ? 1 : 0));
fprintf(fp, "autospellpos = %d\n", (chkSTAutoPos->isChecked() ? 1 : 0));
......
......@@ -18,7 +18,6 @@ struct Config {
unsigned short serverport;
unsigned char textfontsize;
wchar_t lasthost[100];
wchar_t lastport[10];
wchar_t nickname[20];
wchar_t gamename[20];
wchar_t lastcategory[64];
......@@ -325,7 +324,6 @@ public:
irr::gui::IGUIListBox* lstHostList;
irr::gui::IGUIButton* btnLanRefresh;
irr::gui::IGUIEditBox* ebJoinHost;
irr::gui::IGUIEditBox* ebJoinPort;
irr::gui::IGUIEditBox* ebJoinPass;
irr::gui::IGUIButton* btnJoinHost;
irr::gui::IGUIButton* btnJoinCancel;
......
......@@ -97,10 +97,16 @@ int main(int argc, char* argv[]) {
if(i < wargc)
ygo::mainGame->ebJoinHost->setText(wargv[i]);
continue;
} else if(!wcscmp(wargv[i], L"-p")) { // host Port
} else if(!wcscmp(wargv[i], L"-p")) { // host port, deprecated, and should use 1.1.1.1:7911 instead
++i;
if(i < wargc)
ygo::mainGame->ebJoinPort->setText(wargv[i]);
if(i < wargc) {
auto host = ygo::mainGame->ebJoinHost->getText();
if(wcslen(host) > 0) {
wchar_t appended[100];
myswprintf(appended, L"%ls:%ls", host, wargv[i]);
ygo::mainGame->ebJoinHost->setText(appended);
}
}
continue;
} else if(!wcscmp(wargv[i], L"-w")) { // host passWord
++i;
......
......@@ -65,40 +65,19 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
case BUTTON_JOIN_HOST: {
bot_mode = false;
mainGame->TrimText(mainGame->ebJoinHost);
mainGame->TrimText(mainGame->ebJoinPort);
char ip[20];
char hostname[100];
const wchar_t* pstr = mainGame->ebJoinHost->getText();
BufferIO::CopyWStr(pstr, ip, 16);
unsigned int remote_addr = htonl(inet_addr(ip));
if(remote_addr == -1) {
char hostname[100];
char port[6];
BufferIO::CopyWStr(pstr, hostname, 100);
BufferIO::CopyWStr(mainGame->ebJoinPort->getText(), port, 6);
struct evutil_addrinfo hints;
struct evutil_addrinfo *answer = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = EVUTIL_AI_ADDRCONFIG;
int status = evutil_getaddrinfo(hostname, port, &hints, &answer);
if(status != 0) {
mainGame->gMutex.lock();
soundManager.PlaySoundEffect(SOUND_INFO);
mainGame->env->addMessageBox(L"", dataManager.GetSysString(1412));
mainGame->gMutex.unlock();
break;
} else {
sockaddr_in * sin = ((struct sockaddr_in *)answer->ai_addr);
evutil_inet_ntop(AF_INET, &(sin->sin_addr), ip, 20);
remote_addr = htonl(inet_addr(ip));
}
BufferIO::CopyWStr(pstr, hostname, 100);
HostResult remote = DuelClient::ParseHost(hostname);
if(!remote.isValid()) {
mainGame->gMutex.lock();
soundManager.PlaySoundEffect(SOUND_INFO);
mainGame->env->addMessageBox(L"", dataManager.GetSysString(1412));
mainGame->gMutex.unlock();
break;
}
unsigned int remote_port = _wtoi(mainGame->ebJoinPort->getText());
BufferIO::CopyWStr(pstr, mainGame->gameConf.lasthost, 100);
BufferIO::CopyWStr(mainGame->ebJoinPort->getText(), mainGame->gameConf.lastport, 20);
if(DuelClient::StartClient(remote_addr, remote_port, false)) {
if(DuelClient::StartClient(remote.host, remote.port, false)) {
mainGame->btnCreateHost->setEnabled(false);
mainGame->btnJoinHost->setEnabled(false);
mainGame->btnJoinCancel->setEnabled(false);
......@@ -497,11 +476,9 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
break;
int addr = DuelClient::hosts[sel].ipaddr;
int port = DuelClient::hosts[sel].port;
wchar_t buf[20];
myswprintf(buf, L"%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, (addr >> 24) & 0xff);
wchar_t buf[26];
myswprintf(buf, L"%d.%d.%d.%d:%d", addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, (addr >> 24) & 0xff, port);
mainGame->ebJoinHost->setText(buf);
myswprintf(buf, L"%d", port);
mainGame->ebJoinPort->setText(buf);
break;
}
case LISTBOX_REPLAY_LIST: {
......
......@@ -63,11 +63,11 @@ project "YGOPro"
filter {}
end
end
links { "opengl32", "ws2_32", "winmm", "gdi32", "kernel32", "user32", "imm32" }
links { "opengl32", "ws2_32", "winmm", "gdi32", "kernel32", "user32", "imm32", "Dnsapi" }
filter "not action:vs*"
buildoptions { "-std=c++14", "-fno-rtti" }
filter "not system:windows"
links { "event_pthreads", "dl", "pthread" }
links { "event_pthreads", "dl", "pthread", "resolv" }
filter "system:macosx"
links { "z" }
defines { "GL_SILENCE_DEPRECATION" }
......
#config file
#nickname & gamename should be less than 20 characters
use_d3d = 0
use_image_scale = 1
antialias = 2
errorlog = 3
nickname = Player
gamename = Game
lastcategory = 未分类卡组
lastdeck = new
textfont = ./fonts/textFont.ttf 14
numfont = ./fonts/numFont.ttf
serverport = 7911
lasthost = 127.0.0.1
lastport = 7911
automonsterpos = 0
autospellpos = 0
randompos = 0
autochain = 0
waitchain = 0
mute_opponent = 0
mute_spectators = 0
use_lflist = 1
default_lflist = 0
default_rule = 0
hide_setname = 0
hide_hint_button = 0
#control_mode = 0: Key A/S/D/R Chain Buttons. control_mode = 1: MouseLeft/MouseRight/NULL/F9 Without Chain Buttons
control_mode = 0
draw_field_spell = 1
separate_clear_button = 1
#auto_search_limit >= 0: Start search automatically when the user enters N chars
auto_search_limit = -1
#search_multiple_keywords = 0: Disable. 1: Search mutiple keywords with separator " ". 2: with separator "+"
search_multiple_keywords = 1
ignore_deck_changes = 0
default_ot = 1
enable_bot_mode = 0
bot_deck_path = ./botdeck
quick_animation = 0
auto_save_replay = 0
draw_single_chain = 0
prefer_expansion_script = 0
window_maximized = 0
window_width = 1280
window_height = 800
resize_popup_menu = 0
enable_sound = 1
enable_music = 1
#Volume of sound and music, between 0 and 100
sound_volume = 50
music_volume = 50
music_mode = 1
#config file
#nickname & gamename should be less than 20 characters
use_d3d = 0
use_image_scale = 1
antialias = 2
errorlog = 3
nickname = Player
gamename = Game
lastcategory = 未分类卡组
lastdeck = new
textfont = ./fonts/textFont.ttf 14
numfont = ./fonts/numFont.ttf
serverport = 7911
lasthost = 127.0.0.1:7911
automonsterpos = 0
autospellpos = 0
randompos = 0
autochain = 0
waitchain = 0
mute_opponent = 0
mute_spectators = 0
use_lflist = 1
default_lflist = 0
default_rule = 0
hide_setname = 0
hide_hint_button = 0
#control_mode = 0: Key A/S/D/R Chain Buttons. control_mode = 1: MouseLeft/MouseRight/NULL/F9 Without Chain Buttons
control_mode = 0
draw_field_spell = 1
separate_clear_button = 1
#auto_search_limit >= 0: Start search automatically when the user enters N chars
auto_search_limit = -1
#search_multiple_keywords = 0: Disable. 1: Search mutiple keywords with separator " ". 2: with separator "+"
search_multiple_keywords = 1
ignore_deck_changes = 0
default_ot = 1
enable_bot_mode = 0
bot_deck_path = ./botdeck
quick_animation = 0
auto_save_replay = 0
draw_single_chain = 0
prefer_expansion_script = 0
window_maximized = 0
window_width = 1280
window_height = 800
resize_popup_menu = 0
enable_sound = 1
enable_music = 1
#Volume of sound and music, between 0 and 100
sound_volume = 50
music_volume = 50
music_mode = 1
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment