diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/admin/ladmin.cpp | 31 | ||||
-rw-r--r-- | src/char/char.cpp | 88 | ||||
-rw-r--r-- | src/login/login.cpp | 73 | ||||
-rw-r--r-- | src/map/chrif.cpp | 27 | ||||
-rw-r--r-- | src/map/chrif.hpp | 1 | ||||
-rw-r--r-- | src/map/clif.cpp | 64 | ||||
-rw-r--r-- | src/map/trade.cpp | 5 | ||||
-rw-r--r-- | src/mmo/socket.cpp | 109 | ||||
-rw-r--r-- | src/mmo/socket.hpp | 49 |
9 files changed, 262 insertions, 185 deletions
diff --git a/src/admin/ladmin.cpp b/src/admin/ladmin.cpp index c635379..307e13b 100644 --- a/src/admin/ladmin.cpp +++ b/src/admin/ladmin.cpp @@ -286,6 +286,18 @@ void ladmin_log(XString line) } static +void delete_fromlogin(Session *) +{ + { + PRINTF("Impossible to have a connection with the login-server [%s:%d] !\n"_fmt, + login_ip, login_port); + LADMIN_LOG("Impossible to have a connection with the login-server [%s:%d] !\n"_fmt, + login_ip, login_port); + exit(0); + } +} + +static bool qsplit(ZString src) { return !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"_fmt, - login_ip, login_port); - LADMIN_LOG("Impossible to have a connection with the login-server [%s:%d] !\n"_fmt, - login_ip, login_port); - delete_session(s); - exit(0); - } - while (RFIFOREST(s) >= 2) { switch (RFIFOW(s, 0)) @@ -1964,7 +1966,7 @@ void parse_fromlogin(Session *s) PRINTF(" - administration system not activated, or\n"_fmt); PRINTF(" - unauthorised IP.\n"_fmt); LADMIN_LOG("Error at login: incorrect password, administration system not activated, or unauthorised IP.\n"_fmt); - s->eof = 1; + s->set_eof(); //bytes_to_read = 1; // not stop at prompt } else @@ -2763,7 +2765,7 @@ void parse_fromlogin(Session *s) default: PRINTF("Remote administration has been disconnected (unknown packet).\n"_fmt); LADMIN_LOG("'End of connection, unknown packet.\n"_fmt); - s->eof = 1; + s->set_eof(); return; } } @@ -2781,7 +2783,8 @@ int Connect_login_server(void) Iprintf("Attempt to connect to login-server...\n"_fmt); LADMIN_LOG("Attempt to connect to login-server...\n"_fmt); - login_session = make_connection(login_ip, login_port); + login_session = make_connection(login_ip, login_port, SessionParsers{func_parse: parse_fromlogin, func_delete: delete_fromlogin}); + if (!login_session) return 0; @@ -2900,8 +2903,6 @@ int do_init(Slice<ZString> argv) LADMIN_LOG(""_fmt); LADMIN_LOG("Configuration file readed.\n"_fmt); - set_defaultparse(parse_fromlogin); - Iprintf("EAthena login-server administration tool.\n"_fmt); Version version = CURRENT_LOGIN_SERVER_VERSION; Iprintf("for tmwA version %hhu.%hhu.%hhu (dev? %hhu) (flags %hhx) (which %hhx) (vend %hu)\n"_fmt, diff --git a/src/char/char.cpp b/src/char/char.cpp index 123ce3c..477c699 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -185,6 +185,38 @@ 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 delete_tologin(Session *sess) +{ + assert (sess == login_session); + PRINTF("Char-server can't connect to login-server (connection #%d).\n"_fmt, + sess); + login_session = nullptr; +} +static +void delete_char(Session *sess) +{ + (void)sess; +} +static +void delete_frommap(Session *sess) +{ + auto it = std::find(server_session.begin(), server_session.end(), sess); + assert (it != server_session.end()); + int id = it - server_session.begin(); + PRINTF("Map-server %d (session #%d) has disconnected.\n"_fmt, 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) +} + //------------------------------ // Writing function of logs file //------------------------------ @@ -1077,7 +1109,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 +1148,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"_fmt, - ls); - login_session = nullptr; - } - delete_session(ls); + ls->set_eof(); return; } @@ -1509,7 +1535,7 @@ void parse_tologin(Session *ls) break; default: - ls->eof = 1; + ls->set_eof(); return; } } @@ -1533,7 +1559,7 @@ void map_anti_freeze_system(TimerData *, tick_t) i); CHAR_LOG("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n"_fmt, i); - server_session[i]->eof = 1; + server_session[i]->set_eof(); } } } @@ -1546,20 +1572,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"_fmt, 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; } @@ -2040,7 +2055,7 @@ void parse_frommap(Session *ms) // inter server処理でもない場合は切断 PRINTF("char: unknown packet 0x%04x (%zu bytes to read in buffer)! (from map).\n"_fmt, RFIFOW(ms, 0), RFIFOREST(ms)); - ms->eof = 1; + ms->set_eof(); return; } } @@ -2160,11 +2175,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; } @@ -2429,7 +2446,7 @@ void parse_char(Session *s) { int len; WFIFOB(s, 2) = 0; - s->func_parse = parse_frommap; + s->set_parsers(SessionParsers{func_parse: parse_frommap, func_delete: delete_frommap}); server_session[i] = s; if (anti_freeze_enable) server_freezeflag[i] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed @@ -2473,11 +2490,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; } } @@ -2566,10 +2583,10 @@ void check_connect_login_server(TimerData *, tick_t) if (!login_session) { PRINTF("Attempt to connect to login-server...\n"_fmt); - login_session = make_connection(login_ip, login_port); + login_session = make_connection(login_ip, login_port, + SessionParsers{func_parse: parse_tologin, func_delete: delete_tologin}); if (!login_session) return; - login_session->func_parse = parse_tologin; realloc_fifo(login_session, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); WFIFOW(login_session, 0) = 0x2710; WFIFO_ZERO(login_session, 2, 24); @@ -2885,10 +2902,7 @@ int do_init(Slice<ZString> argv) update_online = TimeT::now(); create_online_files(); // update online players files at start of the server -// set_termfunc (do_final); - set_defaultparse(parse_char); - - char_session = make_listen_port(char_port); + char_session = make_listen_port(char_port, SessionParsers{parse_char, delete_char}); Timer(gettick() + std::chrono::seconds(1), check_connect_login_server, diff --git a/src/login/login.cpp b/src/login/login.cpp index e061e63..f8be4ce 100644 --- a/src/login/login.cpp +++ b/src/login/login.cpp @@ -256,6 +256,34 @@ void login_log(XString line) log_with_timestamp(logfp, line); } +static +void delete_login(Session *sess) +{ + (void)sess; +} + +static +void delete_fromchar(Session *sess) +{ + auto it = std::find(server_session.begin(), server_session.end(), sess); + assert (it != server_session.end()); + int id = it - server_session.begin(); + IP4Address ip = sess->client_ip; + PRINTF("Char-server '%s' has disconnected.\n"_fmt, server[id].name); + LOGIN_LOG("Char-server '%s' has disconnected (ip: %s).\n"_fmt, + server[id].name, ip); + server_session[id] = nullptr; + server[id] = mmo_char_server{}; +} + +static +void delete_admin(Session *s) +{ + PRINTF("Remote administration has disconnected (session #%d).\n"_fmt, + 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) @@ -945,7 +973,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"_fmt, i, server[i].name); - server_session[i]->eof = 1; + server_session[i]->set_eof(); } } } @@ -963,17 +991,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"_fmt, server[id].name); - LOGIN_LOG("Char-server '%s' has disconnected (ip: %s).\n"_fmt, - server[id].name, ip); - server_session[id] = nullptr; - server[id] = mmo_char_server{}; - } - delete_session(s); + s->set_eof(); return; } @@ -1585,7 +1605,7 @@ void parse_fromchar(Session *s) } PRINTF("parse_fromchar: Unknown packet 0x%x (from a char-server)! -> disconnection.\n"_fmt, RFIFOW(s, 0)); - s->eof = 1; + s->set_eof(); PRINTF("Char-server has been disconnected (unknown packet).\n"_fmt); return; } @@ -1601,14 +1621,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"_fmt, - s); - return; - } - while (RFIFOREST(s) >= 2) { if (display_parse_admin == 1) @@ -1630,7 +1642,7 @@ void parse_admin(Session *s) LOGIN_LOG("'ladmin': End of connection (ip: %s)\n"_fmt, ip); RFIFOSKIP(s, 2); - s->eof = 1; + s->set_eof(); break; case 0x7920: // Request of an accounts list @@ -2700,7 +2712,7 @@ void parse_admin(Session *s) } LOGIN_LOG("'ladmin': End of connection, unknown packet (ip: %s)\n"_fmt, ip); - s->eof = 1; + s->set_eof(); PRINTF("Remote administration has been disconnected (unknown packet).\n"_fmt); return; } @@ -2734,12 +2746,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) @@ -3000,7 +3006,7 @@ void parse_login(Session *s) WFIFOW(s, 0) = 0x2711; WFIFOB(s, 2) = 0; WFIFOSET(s, 3); - s->func_parse = parse_fromchar; + s->set_parsers(SessionParsers{func_parse: parse_fromchar, func_delete: delete_fromchar}); realloc_fifo(s, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); // send GM account to char-server len = 4; @@ -3046,7 +3052,7 @@ void parse_login(Session *s) case 0x7532: // Request to end connection LOGIN_LOG("End of connection (ip: %s)\n"_fmt, ip); - s->eof = 1; + s->set_eof(); return; case 0x7918: // Request for administation login @@ -3074,7 +3080,7 @@ void parse_login(Session *s) password, ip); PRINTF("Connection of a remote administration accepted (non encrypted password).\n"_fmt); WFIFOB(s, 2) = 0; - s->func_parse = parse_admin; + s->set_parsers(SessionParsers{func_parse: parse_admin, func_delete: 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"_fmt, @@ -3149,7 +3155,7 @@ void parse_login(Session *s) } } LOGIN_LOG("End of connection, unknown packet (ip: %s)\n"_fmt, ip); - s->eof = 1; + s->set_eof(); return; } } @@ -3896,8 +3902,7 @@ int do_init(Slice<ZString> argv) read_gm_account(); mmo_auth_init(); // set_termfunc (mmo_auth_sync); - set_defaultparse(parse_login); - login_session = make_listen_port(login_port); + login_session = make_listen_port(login_port, SessionParsers{func_parse: parse_login, func_delete: delete_login}); Timer(gettick() + std::chrono::minutes(5), diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index 04e82ca..64fd547 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -1035,6 +1035,15 @@ void ladmin_itemfrob(Session *s) } } +static +void chrif_delete(Session *s) +{ + assert (s == char_session); + PRINTF("Map-server can't connect to char-server (connection #%d).\n"_fmt, + s); + char_session = nullptr; +} + /*========================================== * *------------------------------------------ @@ -1046,15 +1055,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"_fmt, - s); - char_session = nullptr; - } - delete_session(s); + s->set_eof(); return; } @@ -1075,7 +1078,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]; @@ -1158,7 +1161,7 @@ void chrif_parse(Session *s) if (battle_config.error_log) PRINTF("chrif_parse : unknown packet %d %d\n"_fmt, s, RFIFOW(s, 0)); - s->eof = 1; + s->set_eof(); return; } RFIFOSKIP(s, packet_len); @@ -1211,10 +1214,10 @@ void check_connect_char_server(TimerData *, tick_t) { PRINTF("Attempt to connect to char-server...\n"_fmt); chrif_state = 0; - char_session = make_connection(char_ip, char_port); + char_session = make_connection(char_ip, char_port, + SessionParsers{func_parse: chrif_parse, func_delete: chrif_delete}); if (!char_session) return; - char_session->func_parse = chrif_parse; realloc_fifo(char_session, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); chrif_connect(char_session); 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 2eae52b..3e57a6f 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -145,6 +145,29 @@ int map_port = 5121; static int clif_changelook_towards(dumb_ptr<block_list> bl, LOOK type, int val, dumb_ptr<map_session_data> dstsd); +static +void clif_quitsave(Session *, dumb_ptr<map_session_data> sd); + +static +void clif_delete(Session *s) +{ + assert (s != char_session); + + dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(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"_fmt, 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"_fmt, sd->bl_id); // Player logout display [Yor] + map_deliddb(sd); // account_id has been included in the DB before auth answer + } +} + /*========================================== * map鯖のip設定 @@ -1098,10 +1121,8 @@ void clif_quitsave(Session *, dumb_ptr<map_session_data> sd) static void clif_waitclose(TimerData *, tick_t, Session *s) { - // TODO: what happens if the player disconnects - // and someone else connects? if (s) - s->eof = 1; + s->set_eof(); } /*========================================== @@ -1110,10 +1131,10 @@ void clif_waitclose(TimerData *, tick_t, Session *s) */ void clif_setwaitclose(Session *s) { - Timer(gettick() + std::chrono::seconds(5), + s->timed_close = Timer(gettick() + std::chrono::seconds(5), std::bind(clif_waitclose, ph::_1, ph::_2, s) - ).detach(); + ); } /*========================================== @@ -5199,7 +5220,7 @@ int clif_check_packet_flood(Session *s, int cmd) PRINTF("packet flood detected from %s [0x%x]\n"_fmt, 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; @@ -5334,32 +5355,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"_fmt, 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"_fmt, 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; } @@ -5380,7 +5387,7 @@ void clif_parse(Session *s) RFIFOSKIP(s, 2); break; case 0x7532: // 接続の切断 - s->eof = 1; + s->set_eof(); break; } return; @@ -5399,7 +5406,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) } } @@ -5495,6 +5502,5 @@ void clif_parse(Session *s) void do_init_clif(void) { - set_defaultparse(clif_parse); - make_listen_port(map_port); + make_listen_port(map_port, SessionParsers{func_parse: clif_parse, func_delete: clif_delete}); } diff --git a/src/map/trade.cpp b/src/map/trade.cpp index 7fbfbec..86d876f 100644 --- a/src/map/trade.cpp +++ b/src/map/trade.cpp @@ -260,8 +260,11 @@ void trade_tradeok(dumb_ptr<map_session_data> sd) for (trade_i = 0; trade_i < TRADE_MAX; trade_i++) { + int index = sd->deal_item_index[trade_i]; + if (index < 2 || index >= MAX_INVENTORY + 2) + continue; if (sd->deal_item_amount[trade_i] > - sd->status.inventory[sd->deal_item_index[trade_i] - 2].amount + sd->status.inventory[index - 2].amount || sd->deal_item_amount[trade_i] < 0) { trade_tradecancel(sd); diff --git a/src/mmo/socket.cpp b/src/mmo/socket.cpp index 364e769..2fec6c1 100644 --- a/src/mmo/socket.cpp +++ b/src/mmo/socket.cpp @@ -56,6 +56,39 @@ static std::array<std::unique_ptr<Session>, FD_SETSIZE> session; #pragma GCC diagnostic pop +Session::Session(SessionIO io, SessionParsers p) +: created() +, connected() +, eof() +, timed_close() +, rdata(), wdata() +, max_rdata(), max_wdata() +, rdata_size(), wdata_size() +, rdata_pos() +, client_ip() +, func_recv() +, func_send() +, func_parse() +, func_delete() +, for_inferior() +, session_data() +, fd() +{ + set_io(io); + set_parsers(p); +} +void Session::set_io(SessionIO io) +{ + func_send = io.func_send; + func_recv = io.func_recv; +} +void Session::set_parsers(SessionParsers p) +{ + func_parse = p.func_parse; + func_delete = p.func_delete; +} + + void set_session(io::FD fd, std::unique_ptr<Session> sess) { int f = fd.uncast_dammit(); @@ -98,25 +131,10 @@ size_t RFIFOSPACE(Session *s) } -/// Discard all input -static -void null_parse(Session *s); -/// Default parser for new connections -static -void (*default_func_parse)(Session *) = null_parse; - -void set_defaultparse(void (*defaultparse)(Session *)) -{ - default_func_parse = defaultparse; -} - /// Read from socket to the queue static void recv_to_fifo(Session *s) { - if (s->eof) - return; - ssize_t len = s->fd.read(&s->rdata[s->rdata_size], RFIFOSPACE(s)); @@ -127,16 +145,13 @@ void recv_to_fifo(Session *s) } else { - s->eof = 1; + s->set_eof(); } } static void send_from_fifo(Session *s) { - if (s->eof) - return; - ssize_t len = s->fd.write(&s->wdata[0], s->wdata_size); if (len > 0) @@ -151,18 +166,16 @@ void send_from_fifo(Session *s) } else { - s->eof = 1; + s->set_eof(); } } static -void null_parse(Session *s) +void nothing_delete(Session *s) { - PRINTF("null_parse : %d\n"_fmt, s); - RFIFOSKIP(s, RFIFOREST(s)); + (void)s; } - static void connect_client(Session *ls) { @@ -211,23 +224,21 @@ void connect_client(Session *ls) fd.fcntl(F_SETFL, O_NONBLOCK); - set_session(fd, make_unique<Session>()); + set_session(fd, make_unique<Session>( + SessionIO{func_recv: recv_to_fifo, func_send: send_from_fifo}, + ls->for_inferior)); Session *s = get_session(fd); s->fd = fd; s->rdata.new_(RFIFO_SIZE); s->wdata.new_(WFIFO_SIZE); - s->max_rdata = RFIFO_SIZE; s->max_wdata = WFIFO_SIZE; - s->func_recv = recv_to_fifo; - s->func_send = send_from_fifo; - s->func_parse = default_func_parse; s->client_ip = IP4Address(client_address.sin_addr); s->created = TimeT::now(); s->connected = 0; } -Session *make_listen_port(uint16_t port) +Session *make_listen_port(uint16_t port, SessionParsers inferior) { struct sockaddr_in server_address; io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0); @@ -276,18 +287,20 @@ Session *make_listen_port(uint16_t port) readfds.set(fd); - set_session(fd, make_unique<Session>()); + set_session(fd, make_unique<Session>( + SessionIO{func_recv: connect_client, func_send: nullptr}, + SessionParsers{func_parse: nullptr, func_delete: nothing_delete})); Session *s = get_session(fd); + s->for_inferior = inferior; s->fd = fd; - s->func_recv = connect_client; s->created = TimeT::now(); s->connected = 1; return s; } -Session *make_connection(IP4Address ip, uint16_t port) +Session *make_connection(IP4Address ip, uint16_t port, SessionParsers parsers) { struct sockaddr_in server_address; io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0); @@ -329,7 +342,9 @@ Session *make_connection(IP4Address ip, uint16_t port) readfds.set(fd); - set_session(fd, make_unique<Session>()); + set_session(fd, make_unique<Session>( + SessionIO{func_recv: recv_to_fifo, func_send: send_from_fifo}, + parsers)); Session *s = get_session(fd); s->fd = fd; s->rdata.new_(RFIFO_SIZE); @@ -337,9 +352,6 @@ Session *make_connection(IP4Address ip, uint16_t port) s->max_rdata = RFIFO_SIZE; s->max_wdata = WFIFO_SIZE; - s->func_recv = recv_to_fifo; - s->func_send = send_from_fifo; - s->func_parse = default_func_parse; s->created = TimeT::now(); s->connected = 1; @@ -350,6 +362,8 @@ void delete_session(Session *s) { if (!s) return; + // this needs to be before the fd_max-- + s->func_delete(s); io::FD fd = s->fd; // If this was the highest fd, decrease it @@ -434,13 +448,13 @@ void do_sendrecv(interval_t next_ms) Session *s = get_session(i); if (!s) continue; - if (wfd.isset(i)) + if (wfd.isset(i) && !s->eof) { if (s->func_send) //send_from_fifo(i); s->func_send(s); } - if (rfd.isset(i)) + if (rfd.isset(i) && !s->eof) { if (s->func_recv) //recv_to_fifo(i); @@ -461,23 +475,22 @@ void do_parsepacket(void) && static_cast<time_t>(TimeT::now()) - static_cast<time_t>(s->created) > CONNECT_TIMEOUT) { PRINTF("Session #%d timed out\n"_fmt, s); - s->eof = 1; + s->set_eof(); } - if (!s->rdata_size && !s->eof) - continue; - if (s->func_parse) + if (s->rdata_size && !s->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->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 3b411e3..c166794 100644 --- a/src/mmo/socket.hpp +++ b/src/mmo/socket.hpp @@ -51,16 +51,40 @@ struct SessionDeleter void operator()(SessionData *sd); }; -// Struct declaration +struct Session; +struct SessionIO +{ + void (*func_recv)(Session *); + void (*func_send)(Session *); +}; + +struct SessionParsers +{ + void (*func_parse)(Session *); + void (*func_delete)(Session *); +}; struct Session { + Session(SessionIO, SessionParsers); + Session(Session&&) = delete; + Session& operator = (Session&&) = delete; + + void set_io(SessionIO); + void set_parsers(SessionParsers); + /// Checks whether a newly-connected socket actually does anything 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; } + + /// Currently used by clif_setwaitclose + Timer timed_close; /// Since this is a single-threaded application, it can't block /// These are the read/write queues @@ -74,6 +98,7 @@ struct Session IP4Address client_ip; +private: /// Send or recieve /// Only called when select() indicates the socket is ready /// If, after that, nothing is read, it sets eof @@ -83,12 +108,23 @@ struct Session /// This is the important one /// Set to different functions depending on whether the connection /// 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 *); + +public: + // this really ought to be part of session_data, once that gets sane + SessionParsers for_inferior; + /// Server-specific data type + // (this really should include the deleter, but ...) std::unique_ptr<SessionData, SessionDeleter> session_data; io::FD fd; + + friend void do_sendrecv(interval_t next); + friend void do_parsepacket(void); + friend void delete_session(Session *); }; inline @@ -123,10 +159,10 @@ IteratorPair<ValueIterator<io::FD, IncrFD>> iter_fds(); /// open a socket, bind, and listen. Return an fd, or -1 if socket() fails, /// but exit if bind() or listen() fails -Session *make_listen_port(uint16_t port); +Session *make_listen_port(uint16_t port, SessionParsers inferior); /// Connect to an address, return a connected socket or -1 // FIXME - this is IPv4 only! -Session *make_connection(IP4Address ip, uint16_t port); +Session *make_connection(IP4Address ip, uint16_t port, SessionParsers); /// free() the structure and close() the fd void delete_session(Session *); /// Make a the internal queues bigger @@ -136,11 +172,6 @@ void do_sendrecv(interval_t next); /// Call the parser function for every socket that has read data 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 *)); - template<class T> uint8_t *pod_addressof_m(T& structure) { |