From ae7b06ff8ad775a945bd677effd72b7fafa13d8d Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Thu, 17 Apr 2014 16:10:11 -0700 Subject: Die sensibly, take 1 --- src/admin/ladmin.cpp | 28 +++++++++--------- src/char/char.cpp | 81 ++++++++++++++++++++++++++++++++-------------------- src/login/login.cpp | 70 +++++++++++++++++++++++++-------------------- src/map/chrif.cpp | 14 +++------ src/map/chrif.hpp | 1 + src/map/clif.cpp | 64 +++++++++++++++++++++++++---------------- src/mmo/socket.cpp | 34 +++++++++++++--------- src/mmo/socket.hpp | 10 ++++++- 8 files changed, 178 insertions(+), 124 deletions(-) (limited to 'src') diff --git a/src/admin/ladmin.cpp b/src/admin/ladmin.cpp index 5d772e3..0d53ff4 100644 --- a/src/admin/ladmin.cpp +++ b/src/admin/ladmin.cpp @@ -285,6 +285,18 @@ void ladmin_log(XString line) log_with_timestamp(logfp, line); } +static +void on_delete(Session *) +{ + { + PRINTF("Impossible to have a connection with the login-server [%s:%d] !\n", + login_ip, login_port); + LADMIN_LOG("Impossible to have a connection with the login-server [%s:%d] !\n", + login_ip, login_port); + exit(0); + } +} + static bool qsplit(ZString src) { @@ -1940,16 +1952,6 @@ void prompt(void) static void parse_fromlogin(Session *s) { - if (s->eof) - { - PRINTF("Impossible to have a connection with the login-server [%s:%d] !\n", - login_ip, login_port); - LADMIN_LOG("Impossible to have a connection with the login-server [%s:%d] !\n", - login_ip, login_port); - delete_session(s); - exit(0); - } - // PRINTF("parse_fromlogin : %d %d %d\n", fd, RFIFOREST(fd), RFIFOW(fd,0)); while (RFIFOREST(s) >= 2) @@ -1966,7 +1968,7 @@ void parse_fromlogin(Session *s) PRINTF(" - administration system not activated, or\n"); PRINTF(" - unauthorised IP.\n"); LADMIN_LOG("Error at login: incorrect password, administration system not activated, or unauthorised IP.\n"); - s->eof = 1; + s->set_eof(); //bytes_to_read = 1; // not stop at prompt } else @@ -2765,7 +2767,7 @@ void parse_fromlogin(Session *s) default: PRINTF("Remote administration has been disconnected (unknown packet).\n"); LADMIN_LOG("'End of connection, unknown packet.\n"); - s->eof = 1; + s->set_eof(); return; } } @@ -2902,7 +2904,7 @@ int do_init(Slice argv) LADMIN_LOG(""); LADMIN_LOG("Configuration file readed.\n"); - set_defaultparse(parse_fromlogin); + set_defaultparse(parse_fromlogin, on_delete); Iprintf("EAthena login-server administration tool.\n"); Version version = CURRENT_LOGIN_SERVER_VERSION; diff --git a/src/char/char.cpp b/src/char/char.cpp index d7849af..7eb446a 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -185,6 +185,40 @@ TimeT update_online; // to update online files when we receiving infor static pid_t pid = 0; // For forked DB writes +static +void create_online_files(void); + +static +void on_delete(Session *sess) +{ + if (sess == login_session) + { + PRINTF("Char-server can't connect to login-server (connection #%d).\n", + sess); + login_session = nullptr; + } + else + { + auto it = std::find(server_session.begin(), server_session.end(), sess); + if (it != server_session.end()) + { + int id = it - server_session.begin(); + PRINTF("Map-server %d (session #%d) has disconnected.\n", id, + sess); + server[id] = mmo_map_server{}; + server_session[id] = nullptr; + for (Session *& oci : online_chars) + if (oci == sess) + oci = nullptr; + create_online_files(); // update online players files (to remove all online players of this server) + } + else + { + // normal player session + } + } +} + //------------------------------ // Writing function of logs file //------------------------------ @@ -1077,7 +1111,7 @@ int disconnect_player(int accound_id) { if (sd->account_id == accound_id) { - get_session(i)->eof = 1; + get_session(i)->set_eof(); return 1; } } @@ -1116,15 +1150,9 @@ void parse_tologin(Session *ls) { // only login-server can have an access to here. // so, if it isn't the login-server, we disconnect the session (fd != login_fd). - if (ls != login_session || ls->eof) + if (ls != login_session) { - if (ls == login_session) - { - PRINTF("Char-server can't connect to login-server (connection #%d).\n", - ls); - login_session = nullptr; - } - delete_session(ls); + ls->set_eof(); return; } @@ -1520,7 +1548,7 @@ void parse_tologin(Session *ls) break; default: - ls->eof = 1; + ls->set_eof(); return; } } @@ -1546,7 +1574,7 @@ void map_anti_freeze_system(TimerData *, tick_t) i); CHAR_LOG("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n", i); - server_session[i]->eof = 1; + server_session[i]->set_eof(); } } } @@ -1559,20 +1587,9 @@ void parse_frommap(Session *ms) for (id = 0; id < MAX_MAP_SERVERS; id++) if (server_session[id] == ms) break; - if (id == MAX_MAP_SERVERS || ms->eof) + if (id == MAX_MAP_SERVERS) { - if (id < MAX_MAP_SERVERS) - { - PRINTF("Map-server %d (session #%d) has disconnected.\n", id, - ms); - server[id] = mmo_map_server{}; - server_session[id] = nullptr; - for (Session *& oci : online_chars) - if (oci == ms) - oci = nullptr; - create_online_files(); // update online players files (to remove all online players of this server) - } - delete_session(ms); + ms->set_eof(); return; } @@ -2057,7 +2074,7 @@ void parse_frommap(Session *ms) // inter server処理でもない場合は切断 PRINTF("char: unknown packet 0x%04x (%zu bytes to read in buffer)! (from map).\n", RFIFOW(ms, 0), RFIFOREST(ms)); - ms->eof = 1; + ms->set_eof(); return; } } @@ -2177,11 +2194,13 @@ void parse_char(Session *s) { IP4Address ip = s->client_ip; - if (!login_session || s->eof) - { // disconnect any player (already connected to char-server or coming back from map-server) if login-server is diconnected. + if (!login_session) + { + s->set_eof(); + + // I sure *hope* this doesn't happen ... if (s == login_session) login_session = nullptr; - delete_session(s); return; } @@ -2493,11 +2512,11 @@ void parse_char(Session *s) return; case 0x7532: // 接続の切断(defaultと処理は一緒だが明示的にするため) - s->eof = 1; + s->set_eof(); return; default: - s->eof = 1; + s->set_eof(); return; } } @@ -2906,7 +2925,7 @@ int do_init(Slice argv) create_online_files(); // update online players files at start of the server // set_termfunc (do_final); - set_defaultparse(parse_char); + set_defaultparse(parse_char, on_delete); char_session = make_listen_port(char_port); diff --git a/src/login/login.cpp b/src/login/login.cpp index f784c6a..966d7dc 100644 --- a/src/login/login.cpp +++ b/src/login/login.cpp @@ -256,6 +256,35 @@ void login_log(XString line) log_with_timestamp(logfp, line); } +static +void on_delete(Session *sess) +{ + auto it = std::find(server_session.begin(), server_session.end(), sess); + IP4Address ip = sess->client_ip; + if (it != server_session.end()) + { + int id = it - server_session.begin(); + PRINTF("Char-server '%s' has disconnected.\n", server[id].name); + LOGIN_LOG("Char-server '%s' has disconnected (ip: %s).\n", + server[id].name, ip); + server_session[id] = nullptr; + server[id] = mmo_char_server{}; + } + else + { + // player session + ; + } +} + +static +void on_delete_admin(Session *s) +{ + PRINTF("Remote administration has disconnected (session #%d).\n", + s); +} + + //---------------------------------------------------------------------- // Determine if an account (id) is a GM account // and returns its level (or 0 if it isn't a GM account or if not found) @@ -948,7 +977,7 @@ void char_anti_freeze_system(TimerData *, tick_t) i, server[i].name); LOGIN_LOG("Char-server anti-freeze system: char-server #%d '%s' is freezed -> disconnection.\n", i, server[i].name); - server_session[i]->eof = 1; + server_session[i]->set_eof(); } } } @@ -966,17 +995,9 @@ void parse_fromchar(Session *s) for (id = 0; id < MAX_SERVERS; id++) if (server_session[id] == s) break; - if (id == MAX_SERVERS || s->eof) + if (id == MAX_SERVERS) { - if (id < MAX_SERVERS) - { - PRINTF("Char-server '%s' has disconnected.\n", server[id].name); - LOGIN_LOG("Char-server '%s' has disconnected (ip: %s).\n", - server[id].name, ip); - server_session[id] = nullptr; - server[id] = mmo_char_server{}; - } - delete_session(s); + s->set_eof(); return; } @@ -1593,7 +1614,7 @@ void parse_fromchar(Session *s) } PRINTF("parse_fromchar: Unknown packet 0x%x (from a char-server)! -> disconnection.\n", RFIFOW(s, 0)); - s->eof = 1; + s->set_eof(); PRINTF("Char-server has been disconnected (unknown packet).\n"); return; } @@ -1609,14 +1630,6 @@ void parse_admin(Session *s) { IP4Address ip = s->client_ip; - if (s->eof) - { - delete_session(s); - PRINTF("Remote administration has disconnected (session #%d).\n", - s); - return; - } - while (RFIFOREST(s) >= 2) { if (display_parse_admin == 1) @@ -1638,7 +1651,7 @@ void parse_admin(Session *s) LOGIN_LOG("'ladmin': End of connection (ip: %s)\n", ip); RFIFOSKIP(s, 2); - s->eof = 1; + s->set_eof(); break; case 0x7920: // Request of an accounts list @@ -2708,7 +2721,7 @@ void parse_admin(Session *s) } LOGIN_LOG("'ladmin': End of connection, unknown packet (ip: %s)\n", ip); - s->eof = 1; + s->set_eof(); PRINTF("Remote administration has been disconnected (unknown packet).\n"); return; } @@ -2742,12 +2755,6 @@ void parse_login(Session *s) IP4Address ip = s->client_ip; - if (s->eof) - { - delete_session(s); - return; - } - while (RFIFOREST(s) >= 2) { if (display_parse_login == 1) @@ -3054,7 +3061,7 @@ void parse_login(Session *s) case 0x7532: // Request to end connection LOGIN_LOG("End of connection (ip: %s)\n", ip); - s->eof = 1; + s->set_eof(); return; case 0x7918: // Request for administation login @@ -3083,6 +3090,7 @@ void parse_login(Session *s) PRINTF("Connection of a remote administration accepted (non encrypted password).\n"); WFIFOB(s, 2) = 0; s->func_parse = parse_admin; + s->func_delete = on_delete_admin; } else if (admin_state != 1) LOGIN_LOG("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (non encrypted password: %s, ip: %s)\n", @@ -3157,7 +3165,7 @@ void parse_login(Session *s) } } LOGIN_LOG("End of connection, unknown packet (ip: %s)\n", ip); - s->eof = 1; + s->set_eof(); return; } } @@ -3904,7 +3912,7 @@ int do_init(Slice argv) read_gm_account(); mmo_auth_init(); // set_termfunc (mmo_auth_sync); - set_defaultparse(parse_login); + set_defaultparse(parse_login, on_delete); login_session = make_listen_port(login_port); diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index 9a70d63..86506b0 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -1048,15 +1048,9 @@ void chrif_parse(Session *s) // only char-server can have an access to here. // so, if it isn't the char-server, we disconnect the session (fd != char_fd). - if (s != char_session || s->eof) + if (s != char_session) { - if (s == char_session) - { - PRINTF("Map-server can't connect to char-server (connection #%d).\n", - s); - char_session = nullptr; - } - delete_session(s); + s->set_eof(); return; } @@ -1077,7 +1071,7 @@ void chrif_parse(Session *s) if (r == 2) return; // intifで処理したが、データが足りない - s->eof = 1; + s->set_eof(); return; } packet_len = packet_len_table[cmd - 0x2af8]; @@ -1160,7 +1154,7 @@ void chrif_parse(Session *s) if (battle_config.error_log) PRINTF("chrif_parse : unknown packet %d %d\n", s, RFIFOW(s, 0)); - s->eof = 1; + s->set_eof(); return; } RFIFOSKIP(s, packet_len); diff --git a/src/map/chrif.hpp b/src/map/chrif.hpp index 5e8263d..afeba75 100644 --- a/src/map/chrif.hpp +++ b/src/map/chrif.hpp @@ -59,6 +59,7 @@ int chrif_send_divorce(int char_id); void do_init_chrif(void); // only used by intif.cpp +// and clif.cpp for the new on_delete stuff ... extern Session *char_session; #endif // TMWA_MAP_CHRIF_HPP diff --git a/src/map/clif.cpp b/src/map/clif.cpp index ea92d15..8f9565e 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -145,6 +145,36 @@ int map_port = 5121; static int clif_changelook_towards(dumb_ptr bl, LOOK type, int val, dumb_ptr dstsd); +static +void clif_quitsave(Session *, dumb_ptr sd); + +static +void on_delete(Session *s) +{ + if (s == char_session) + { + PRINTF("Map-server can't connect to char-server (connection #%d).\n", + s); + char_session = nullptr; + } + else + { + dumb_ptr sd = dumb_ptr(static_cast(s->session_data.get())); + if (sd && sd->state.auth) + { + pc_logout(sd); + clif_quitsave(s, sd); + + PRINTF("Player [%s] has logged off your server.\n", sd->status_key.name); // Player logout display [Valaris] + } + else if (sd) + { // not authentified! (refused by char-server or disconnect before to be authentified) + PRINTF("Player with account [%d] has logged off your server (not auth account).\n", sd->bl_id); // Player logout display [Yor] + map_deliddb(sd); // account_id has been included in the DB before auth answer + } + } +} + /*========================================== * map鯖のip設定 @@ -1099,7 +1129,7 @@ static void clif_waitclose(TimerData *, tick_t, Session *s) { if (s) - s->eof = 1; + s->set_eof(); } /*========================================== @@ -5203,7 +5233,7 @@ int clif_check_packet_flood(Session *s, int cmd) PRINTF("packet flood detected from %s [0x%x]\n", sd->status_key.name, cmd); if (battle_config.packet_spam_kick) { - s->eof = 1; // Kick + s->set_eof(); return 1; } sd->packet_flood_in = 0; @@ -5338,32 +5368,18 @@ void clif_parse(Session *s) { if (RFIFOREST(s) < 2) { // too small a packet disconnect - s->eof = 1; + s->set_eof(); } if (RFIFOW(s, 0) != 0x72 && RFIFOW(s, 0) != 0x7530) { // first packet must be auth or finger - s->eof = 1; + s->set_eof(); } } - // 接続が切れてるので後始末 - if (!chrif_isconnect() || s->eof) - { // char鯖に繋がってない間は接続禁止 (!chrif_isconnect()) - if (sd && sd->state.auth) - { - pc_logout(sd); - clif_quitsave(s, sd); - - PRINTF("Player [%s] has logged off your server.\n", sd->status_key.name); // Player logout display [Valaris] - } - else if (sd) - { // not authentified! (refused by char-server or disconnect before to be authentified) - PRINTF("Player with account [%d] has logged off your server (not auth account).\n", sd->bl_id); // Player logout display [Yor] - map_deliddb(sd); // account_id has been included in the DB before auth answer - } - if (s) - delete_session(s); + if (!chrif_isconnect()) + { + s->set_eof(); return; } @@ -5384,7 +5400,7 @@ void clif_parse(Session *s) RFIFOSKIP(s, 2); break; case 0x7532: // 接続の切断 - s->eof = 1; + s->set_eof(); break; } return; @@ -5403,7 +5419,7 @@ void clif_parse(Session *s) packet_len = RFIFOW(s, 2); if (packet_len < 4 || packet_len > 32768) { - s->eof = 1; + s->set_eof(); return; // Runt packet (variable out of bounds) } } @@ -5499,6 +5515,6 @@ void clif_parse(Session *s) void do_init_clif(void) { - set_defaultparse(clif_parse); + set_defaultparse(clif_parse, on_delete); make_listen_port(map_port); } diff --git a/src/mmo/socket.cpp b/src/mmo/socket.cpp index 48cd149..322a1f4 100644 --- a/src/mmo/socket.cpp +++ b/src/mmo/socket.cpp @@ -104,17 +104,20 @@ void null_parse(Session *s); /// Default parser for new connections static void (*default_func_parse)(Session *) = null_parse; +static +void (*default_delete)(Session *) = nullptr; -void set_defaultparse(void (*defaultparse)(Session *)) +void set_defaultparse(void (*defaultparse)(Session *), void (*on_delete)(Session *)) { default_func_parse = defaultparse; + default_delete = on_delete; } /// Read from socket to the queue static void recv_to_fifo(Session *s) { - if (s->eof) + if (s->private_is_eof()) return; ssize_t len = s->fd.read(&s->rdata[s->rdata_size], @@ -127,14 +130,14 @@ void recv_to_fifo(Session *s) } else { - s->eof = 1; + s->set_eof(); } } static void send_from_fifo(Session *s) { - if (s->eof) + if (s->private_is_eof()) return; ssize_t len = s->fd.write(&s->wdata[0], s->wdata_size); @@ -151,7 +154,7 @@ void send_from_fifo(Session *s) } else { - s->eof = 1; + s->set_eof(); } } @@ -222,6 +225,7 @@ void connect_client(Session *ls) s->func_recv = recv_to_fifo; s->func_send = send_from_fifo; s->func_parse = default_func_parse; + s->func_delete = default_delete; s->client_ip = IP4Address(client_address.sin_addr); s->created = TimeT::now(); s->connected = 0; @@ -340,6 +344,7 @@ Session *make_connection(IP4Address ip, uint16_t port) s->func_recv = recv_to_fifo; s->func_send = send_from_fifo; s->func_parse = default_func_parse; + s->func_delete = default_delete; s->created = TimeT::now(); s->connected = 1; @@ -359,6 +364,8 @@ void delete_session(Session *s) fd_max--; readfds.clr(fd); { + s->func_delete(s); + s->rdata.delete_(); s->wdata.delete_(); s->session_data.reset(); @@ -461,23 +468,22 @@ void do_parsepacket(void) && static_cast(TimeT::now()) - static_cast(s->created) > CONNECT_TIMEOUT) { PRINTF("Session #%d timed out\n", s); - s->eof = 1; + s->set_eof(); } - if (!s->rdata_size && !s->eof) - continue; - if (s->func_parse) + if (s->rdata_size && !s->private_is_eof() && s->func_parse) { s->func_parse(s); /// some func_parse may call delete_session + // (that's kind of evil) s = get_session(i); - if (s && s->eof) - { - delete_session(s); - s = nullptr; - } if (!s) continue; } + if (s->private_is_eof()) + { + delete_session(s); + continue; + } /// Reclaim buffer space for what was read RFIFOFLUSH(s); } diff --git a/src/mmo/socket.hpp b/src/mmo/socket.hpp index 256c08b..53e0dfd 100644 --- a/src/mmo/socket.hpp +++ b/src/mmo/socket.hpp @@ -59,8 +59,14 @@ struct Session TimeT created; bool connected; +private: /// Flag needed since structure must be freed in a server-dependent manner bool eof; +public: + void set_eof() { eof = true; } + // not everything is a member yet ... + bool private_is_eof() { return eof; } + /// Currently used by clif_setwaitclose Timer timed_close; @@ -87,6 +93,8 @@ struct Session /// is a player or a server/ladmin /// Can be set explicitly or via set_defaultparse void (*func_parse)(Session *); + /// Cleanup function since we're not fully RAII yet + void (*func_delete)(Session *); /// Server-specific data type std::unique_ptr session_data; @@ -141,7 +149,7 @@ void do_parsepacket(void); /// Change the default parser for newly connected clients // typically called once per server, but individual clients may identify // themselves as servers -void set_defaultparse(void(*defaultparse)(Session *)); +void set_defaultparse(void(*defaultparse)(Session *), void(*defaultdelete)(Session *)); template uint8_t *pod_addressof_m(T& structure) -- cgit v1.2.3-60-g2f50