forked from metin2/server
Rewrote network stack, started working on porting to 64-bit
This commit is contained in:
@@ -45,7 +45,6 @@
|
||||
#include "polymorph.h"
|
||||
#include "blend_item.h"
|
||||
#include "castle.h"
|
||||
#include "passpod.h"
|
||||
#include "ani.h"
|
||||
#include "BattleArena.h"
|
||||
#include "over9refine.h"
|
||||
@@ -59,7 +58,9 @@
|
||||
#include "skill_power.h"
|
||||
#include "SpeedServer.h"
|
||||
#include "DragonSoul.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include <event2/event.h>
|
||||
#include <event2/listener.h>
|
||||
#include <event2/dns.h>
|
||||
|
||||
#ifdef __AUCTION__
|
||||
#include "auction_manager.h"
|
||||
@@ -95,12 +96,17 @@ int current_bytes_written = 0;
|
||||
int total_bytes_written = 0;
|
||||
BYTE g_bLogLevel = 0;
|
||||
|
||||
socket_t tcp_socket = 0;
|
||||
socket_t p2p_socket = 0;
|
||||
evconnlistener * tcp_listener = nullptr;
|
||||
evconnlistener * p2p_listener = nullptr;
|
||||
|
||||
LPFDWATCH main_fdw = NULL;
|
||||
event_base * ev_base = nullptr;
|
||||
evdns_base * dns_base = nullptr;
|
||||
|
||||
int io_loop(LPFDWATCH fdw);
|
||||
static void AcceptError(evconnlistener *listener, void *ctx);
|
||||
static void AcceptTCPConnection(evconnlistener* listener, evutil_socket_t fd, sockaddr* address, int socklen, void* ctx);
|
||||
static void AcceptP2PConnection(evconnlistener* listener, evutil_socket_t fd, sockaddr* address, int socklen, void* ctx);
|
||||
|
||||
int io_loop(event_base * base);
|
||||
|
||||
int start(int argc, char **argv);
|
||||
int idle();
|
||||
@@ -367,7 +373,6 @@ int main(int argc, char **argv)
|
||||
CTableBySkill SkillPowerByLevel;
|
||||
CPolymorphUtils polymorph_utils;
|
||||
CProfiler profiler;
|
||||
CPasspod passpod;
|
||||
CBattleArena ba;
|
||||
COver9RefineManager o9r;
|
||||
SpamManager spam_mgr;
|
||||
@@ -541,7 +546,7 @@ int start(int argc, char **argv)
|
||||
|
||||
case 'l':
|
||||
{
|
||||
long l = strtol(argv[optind], &ep, 10);
|
||||
int l = strtol(argv[optind], &ep, 10);
|
||||
|
||||
log_set_level(l);
|
||||
|
||||
@@ -607,27 +612,59 @@ int start(int argc, char **argv)
|
||||
}
|
||||
|
||||
signal_timer_disable();
|
||||
|
||||
main_fdw = fdwatch_new(4096);
|
||||
|
||||
if ((tcp_socket = socket_tcp_bind(g_szPublicIP, mother_port)) == INVALID_SOCKET)
|
||||
{
|
||||
perror("socket_tcp_bind: tcp_socket");
|
||||
return 0;
|
||||
}
|
||||
// Initialize the network stack
|
||||
// Create a new libevent base and listen for new connections
|
||||
ev_base = event_base_new();
|
||||
if (!ev_base) {
|
||||
sys_err("Libevent base initialization FAILED!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if internal ip exists, p2p socket uses internal ip, if not use public ip
|
||||
//if ((p2p_socket = socket_tcp_bind(*g_szInternalIP ? g_szInternalIP : g_szPublicIP, p2p_port)) == INVALID_SOCKET)
|
||||
if ((p2p_socket = socket_tcp_bind(g_szPublicIP, p2p_port)) == INVALID_SOCKET)
|
||||
{
|
||||
perror("socket_tcp_bind: p2p_socket");
|
||||
return 0;
|
||||
}
|
||||
dns_base = evdns_base_new(ev_base, 1);
|
||||
if (!dns_base) {
|
||||
sys_err("Libevent DNS base initialization FAILED!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fdwatch_add_fd(main_fdw, tcp_socket, NULL, FDW_READ, false);
|
||||
fdwatch_add_fd(main_fdw, p2p_socket, NULL, FDW_READ, false);
|
||||
sockaddr_in sin = {};
|
||||
|
||||
db_clientdesc = DESC_MANAGER::instance().CreateConnectionDesc(main_fdw, db_addr, db_port, PHASE_DBCLIENT, true);
|
||||
// Main TCP listener
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = inet_addr(g_szPublicIP);
|
||||
sin.sin_port = htons(mother_port);
|
||||
|
||||
tcp_listener = evconnlistener_new_bind(
|
||||
ev_base,
|
||||
AcceptTCPConnection, nullptr,
|
||||
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
|
||||
(const sockaddr*)&sin, sizeof(sin)
|
||||
);
|
||||
if (!tcp_listener) {
|
||||
sys_err("TCP listener initialization FAILED!");
|
||||
return 0;
|
||||
}
|
||||
evconnlistener_set_error_cb(tcp_listener, AcceptError);
|
||||
|
||||
// Game P2P listener
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = inet_addr(g_szPublicIP);
|
||||
sin.sin_port = htons(p2p_port);
|
||||
|
||||
p2p_listener = evconnlistener_new_bind(
|
||||
ev_base,
|
||||
AcceptP2PConnection, nullptr,
|
||||
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
|
||||
(const sockaddr*)&sin, sizeof(sin)
|
||||
);
|
||||
if (!p2p_listener) {
|
||||
sys_err("P2P listener initialization FAILED!");
|
||||
return 0;
|
||||
}
|
||||
evconnlistener_set_error_cb(p2p_listener, AcceptError);
|
||||
|
||||
// Create client connections
|
||||
db_clientdesc = DESC_MANAGER::instance().CreateConnectionDesc(ev_base, dns_base, db_addr, db_port, PHASE_DBCLIENT, true);
|
||||
if (!g_bAuthServer) {
|
||||
db_clientdesc->UpdateChannelStatus(0, true);
|
||||
}
|
||||
@@ -637,9 +674,9 @@ int start(int argc, char **argv)
|
||||
if (g_stAuthMasterIP.length() != 0)
|
||||
{
|
||||
fprintf(stderr, "SlaveAuth");
|
||||
g_pkAuthMasterDesc = DESC_MANAGER::instance().CreateConnectionDesc(main_fdw, g_stAuthMasterIP.c_str(), g_wAuthMasterPort, PHASE_P2P, true);
|
||||
g_pkAuthMasterDesc = DESC_MANAGER::instance().CreateConnectionDesc(ev_base, dns_base, g_stAuthMasterIP.c_str(), g_wAuthMasterPort, PHASE_P2P, true);
|
||||
P2P_MANAGER::instance().RegisterConnector(g_pkAuthMasterDesc);
|
||||
g_pkAuthMasterDesc->SetP2P(g_stAuthMasterIP.c_str(), g_wAuthMasterPort, g_bChannel);
|
||||
g_pkAuthMasterDesc->SetP2P(g_wAuthMasterPort, g_bChannel);
|
||||
|
||||
}
|
||||
else
|
||||
@@ -651,7 +688,7 @@ int start(int argc, char **argv)
|
||||
else
|
||||
{
|
||||
if (teen_addr[0] && teen_port)
|
||||
g_TeenDesc = DESC_MANAGER::instance().CreateConnectionDesc(main_fdw, teen_addr, teen_port, PHASE_TEEN, true);
|
||||
g_TeenDesc = DESC_MANAGER::instance().CreateConnectionDesc(ev_base, dns_base, teen_addr, teen_port, PHASE_TEEN, true);
|
||||
|
||||
extern unsigned int g_uiSpamBlockDuration;
|
||||
extern unsigned int g_uiSpamBlockScore;
|
||||
@@ -676,12 +713,26 @@ void destroy()
|
||||
sys_log(0, "<shutdown> regen_free()...");
|
||||
regen_free();
|
||||
|
||||
sys_log(0, "<shutdown> Closing sockets...");
|
||||
socket_close(tcp_socket);
|
||||
socket_close(p2p_socket);
|
||||
sys_log(0, "<shutdown> Closing network stack...");
|
||||
if (tcp_listener) {
|
||||
evconnlistener_free(tcp_listener);
|
||||
tcp_listener = nullptr;
|
||||
}
|
||||
|
||||
sys_log(0, "<shutdown> fdwatch_delete()...");
|
||||
fdwatch_delete(main_fdw);
|
||||
if (p2p_listener) {
|
||||
evconnlistener_free(p2p_listener);
|
||||
tcp_listener = nullptr;
|
||||
}
|
||||
|
||||
if (dns_base) {
|
||||
evdns_base_free(dns_base, 0);
|
||||
ev_base = nullptr;
|
||||
}
|
||||
|
||||
if (ev_base) {
|
||||
event_base_free(ev_base);
|
||||
ev_base = nullptr;
|
||||
}
|
||||
|
||||
sys_log(0, "<shutdown> event_destroy()...");
|
||||
event_destroy();
|
||||
@@ -724,7 +775,7 @@ int idle()
|
||||
s_dwProfiler[PROF_CHR_UPDATE] += (get_dword_time() - t);
|
||||
|
||||
t = get_dword_time();
|
||||
if (!io_loop(main_fdw)) return 0;
|
||||
if (!io_loop(ev_base)) return 0;
|
||||
s_dwProfiler[PROF_IO] += (get_dword_time() - t);
|
||||
|
||||
log_rotate();
|
||||
@@ -772,7 +823,29 @@ int idle()
|
||||
return 1;
|
||||
}
|
||||
|
||||
int io_loop(LPFDWATCH fdw)
|
||||
static void AcceptError(evconnlistener *listener, void *ctx) {
|
||||
struct event_base *base = evconnlistener_get_base(listener);
|
||||
int err = EVUTIL_SOCKET_ERROR();
|
||||
fprintf(stderr, "Got an error %d (%s) on the listener. "
|
||||
"Shutting down.\n", err, evutil_socket_error_to_string(err));
|
||||
|
||||
event_base_loopexit(base, nullptr);
|
||||
ShutdownOnFatalError();
|
||||
}
|
||||
|
||||
static void AcceptTCPConnection(evconnlistener* listener, evutil_socket_t fd, sockaddr* address, int socklen, void* ctx)
|
||||
{
|
||||
// Initialize the peer
|
||||
DESC_MANAGER::instance().AcceptDesc(listener, fd, address);
|
||||
}
|
||||
|
||||
static void AcceptP2PConnection(evconnlistener* listener, evutil_socket_t fd, sockaddr* address, int socklen, void* ctx)
|
||||
{
|
||||
// Initialize the peer
|
||||
DESC_MANAGER::instance().AcceptP2PDesc(listener, fd, address);
|
||||
}
|
||||
|
||||
int io_loop(event_base * base)
|
||||
{
|
||||
LPDESC d;
|
||||
int num_events, event_idx;
|
||||
@@ -780,100 +853,8 @@ int io_loop(LPFDWATCH fdw)
|
||||
DESC_MANAGER::instance().DestroyClosed(); // PHASE_CLOSE<53><45> <20><><EFBFBD>ӵ<EFBFBD><D3B5><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ش<EFBFBD>.
|
||||
DESC_MANAGER::instance().TryConnect();
|
||||
|
||||
if ((num_events = fdwatch(fdw, 0)) < 0)
|
||||
return 0;
|
||||
|
||||
for (event_idx = 0; event_idx < num_events; ++event_idx)
|
||||
{
|
||||
d = (LPDESC) fdwatch_get_client_data(fdw, event_idx);
|
||||
|
||||
if (!d)
|
||||
{
|
||||
if (FDW_READ == fdwatch_check_event(fdw, tcp_socket, event_idx))
|
||||
{
|
||||
DESC_MANAGER::instance().AcceptDesc(fdw, tcp_socket);
|
||||
fdwatch_clear_event(fdw, tcp_socket, event_idx);
|
||||
}
|
||||
else if (FDW_READ == fdwatch_check_event(fdw, p2p_socket, event_idx))
|
||||
{
|
||||
DESC_MANAGER::instance().AcceptP2PDesc(fdw, p2p_socket);
|
||||
fdwatch_clear_event(fdw, p2p_socket, event_idx);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int iRet = fdwatch_check_event(fdw, d->GetSocket(), event_idx);
|
||||
|
||||
switch (iRet)
|
||||
{
|
||||
case FDW_READ:
|
||||
if (db_clientdesc == d)
|
||||
{
|
||||
int size = d->ProcessInput();
|
||||
|
||||
if (size)
|
||||
sys_log(1, "DB_BYTES_READ: %d", size);
|
||||
|
||||
if (size < 0)
|
||||
{
|
||||
d->SetPhase(PHASE_CLOSE);
|
||||
}
|
||||
}
|
||||
else if (d->ProcessInput() < 0)
|
||||
{
|
||||
d->SetPhase(PHASE_CLOSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case FDW_WRITE:
|
||||
if (db_clientdesc == d)
|
||||
{
|
||||
int buf_size = buffer_size(d->GetOutputBuffer());
|
||||
int sock_buf_size = fdwatch_get_buffer_size(fdw, d->GetSocket());
|
||||
|
||||
int ret = d->ProcessOutput();
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
d->SetPhase(PHASE_CLOSE);
|
||||
}
|
||||
|
||||
if (buf_size)
|
||||
sys_log(1, "DB_BYTES_WRITE: size %d sock_buf %d ret %d", buf_size, sock_buf_size, ret);
|
||||
}
|
||||
else if (d->ProcessOutput() < 0)
|
||||
{
|
||||
d->SetPhase(PHASE_CLOSE);
|
||||
}
|
||||
else if (g_TeenDesc==d)
|
||||
{
|
||||
int buf_size = buffer_size(d->GetOutputBuffer());
|
||||
int sock_buf_size = fdwatch_get_buffer_size(fdw, d->GetSocket());
|
||||
|
||||
int ret = d->ProcessOutput();
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
d->SetPhase(PHASE_CLOSE);
|
||||
}
|
||||
|
||||
if (buf_size)
|
||||
sys_log(0, "TEEN::Send(size %d sock_buf %d ret %d)", buf_size, sock_buf_size, ret);
|
||||
}
|
||||
break;
|
||||
|
||||
case FDW_EOF:
|
||||
{
|
||||
d->SetPhase(PHASE_CLOSE);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
sys_err("fdwatch_check_event returned unknown %d", iRet);
|
||||
d->SetPhase(PHASE_CLOSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Process network events
|
||||
event_base_loop(base, EVLOOP_NONBLOCK);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
Reference in New Issue
Block a user