Commit 17ed8a79 authored by nanahira's avatar nanahira

add srv record support & remove port field

parent 75b4f7c5
Pipeline #16746 failed with stages
in 1 minute and 51 seconds
......@@ -8,6 +8,15 @@
#include "game.h"
#include "replay.h"
#include "replay_mode.h"
#ifdef _WIN32
#include <Windows.h>
#include <Windns.h>
#else
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#endif
namespace ygo {
......@@ -4343,4 +4352,86 @@ 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;
}
evutil_freeaddrinfo(answer);
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));
}
return remote_addr;
}
bool DuelClient::LookupSRV(char *hostname, HostResult* result) {
#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;
result->host = LookupHost(ret->Data.SRV.pNameTarget);
result->port = ntohs(ret->Data.SRV.wPort);
return true;
#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_rr rr;
ns_initparse(answer, status, &nsMsg);
for (int i = 0; i < ns_msg_count(nsMsg, ns_s_an); i++) {
if (ns_parserr(&nsMsg, ns_s_an, i, &rr) < 0 || ns_rr_type(rr) != T_SRV)
continue;
// priority = ns_get16(ns_rr_rdata(rr));
// weight = ns_get16(ns_rr_rdata(rr) + NS_INT16SZ);
result->port = ns_get16(ns_rr_rdata(rr) + 2 * NS_INT16SZ);
char resolved[100];
// decompress domain name
if (dn_expand(ns_msg_base(nsMsg), ns_msg_end(nsMsg), ns_rr_rdata(rr) + 3 * NS_INT16SZ, resolved, sizeof(resolved)) < 0)
continue;
result->host = LookupHost(resolved);
return true;
}
return false;
#endif
}
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];
strncpy(host, hostname, trySplitter - hostname);
result.host = LookupHost(host);
result.port = atoi(trySplitter + 1);
}
return result;
}
}
......@@ -17,6 +17,19 @@
namespace ygo {
class HostResult {
public:
unsigned int host;
unsigned int port;
bool isValid() {
return host > 0 && port > 0;
}
HostResult() {
host = 0;
port = 0;
}
};
class DuelClient {
private:
static unsigned int connect_state;
......@@ -56,6 +69,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);
......@@ -100,7 +116,6 @@ public:
static int RefreshThread(event_base* broadev);
static void BroadcastReply(evutil_socket_t fd, short events, void* arg);
};
}
#endif //DUELCLIENT_H
......@@ -201,10 +201,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);
......@@ -1381,9 +1379,6 @@ bool Game::LoadConfigFromFile(const char* file) {
} 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);
......@@ -1505,7 +1500,6 @@ void Game::LoadConfig() {
gameConf.numfont[0] = 0;
gameConf.textfont[0] = 0;
gameConf.lasthost[0] = 0;
gameConf.lastport[0] = 0;
gameConf.roompass[0] = 0;
//settings
gameConf.chkMAutoPos = 0;
......@@ -1639,8 +1633,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));
......
......@@ -19,7 +19,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];
......@@ -360,7 +359,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;
......
......@@ -98,10 +98,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,44 +65,23 @@ 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();
if (auto_watch_mode) {
mainGame->actionSignal.Wait(2000);
mainGame->device->closeDevice();
}
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();
if (auto_watch_mode) {
mainGame->actionSignal.Wait(2000);
mainGame->device->closeDevice();
}
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);
......@@ -505,11 +484,9 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
}
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: {
......
......@@ -70,7 +70,7 @@ project "YGOPro"
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" }
......
......@@ -12,8 +12,7 @@ lastdeck = new
textfont = ./fonts/simhei.ttf 14
numfont = ./fonts/arial.ttf
serverport = 7911
lasthost = 127.0.0.1
lastport = 7911
lasthost = 127.0.0.1:7911
automonsterpos = 0
autospellpos = 0
randompos = 0
......
#config file
#nickname & gamename should be less than 20 characters
use_d3d = 0
use_image_scale = 1
pro_version = 4946
antialias = 2
errorlog = 3
nickname = Nanahira
gamename = Game
lastcategory = OCG
lastdeck = wws
textfont = ./fonts/simhei.ttf 14
numfont = ./fonts/arial.ttf
serverport = 7911
lasthost = tiramisu.mycard.moe
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 = 2
#search_multiple_keywords = 0: Disable. 1: Search mutiple keywords with separator " ". 2: with separator "+"
search_multiple_keywords = 1
search_regex = 1
ignore_deck_changes = 0
default_ot = 1
enable_bot_mode = 1
bot_deck_path = ./windbot/Decks
quick_animation = 1
auto_save_replay = 0
draw_single_chain = 1
prefer_expansion_script = 1
ask_mset = 1
window_maximized = 0
window_width = 1402
window_height = 806
resize_popup_menu = 0
enable_sound = 1
enable_music = 0
#Volume of sound and music, between 0 and 100
sound_volume = 100
music_volume = 100
music_mode = 1
enable_pendulum_scale = 1
skin_index = -1
locale = default
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