diff options
Diffstat (limited to 'src/char_sql')
-rw-r--r-- | src/char_sql/char.c | 222 | ||||
-rw-r--r-- | src/char_sql/inter.c | 4 |
2 files changed, 120 insertions, 106 deletions
diff --git a/src/char_sql/char.c b/src/char_sql/char.c index fe5f72768..4ee3c51f9 100644 --- a/src/char_sql/char.c +++ b/src/char_sql/char.c @@ -20,13 +20,6 @@ #include "char.h" #include <sys/types.h> -#ifdef WIN32 -#include <winsock2.h> -#else -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#endif #include <time.h> #include <signal.h> #include <string.h> @@ -143,16 +136,6 @@ struct char_session_data { time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) }; -#define AUTH_FIFO_SIZE 256 -struct { - int account_id, char_id, login_id1, login_id2; - uint32 ip; - int delflag; - int sex; - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) -} auth_fifo[AUTH_FIFO_SIZE]; -int auth_fifo_pos = 0; - int char_num, char_max; int max_connect_user = 0; int gm_allow_level = 99; @@ -186,7 +169,27 @@ int GM_num = 0; int console = 0; -//Structure for holding in memory which characters are online on the map servers connected. +//----------------------------------------------------- +// Auth database +//----------------------------------------------------- +#define AUTH_TIMEOUT 30000 + +struct auth_node { + int account_id; + int char_id; + uint32 login_id1; + uint32 login_id2; + uint32 ip; + int sex; + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) +}; + +static DBMap* auth_db; // int account_id -> struct auth_node* + +//----------------------------------------------------- +// Online User Database +//----------------------------------------------------- + struct online_char_data { int account_id; int char_id; @@ -195,8 +198,8 @@ struct online_char_data { short server; // -2: unknown server, -1: not connected, 0+: id of server }; -// Holds all online characters. -DBMap* online_char_db; // int account_id -> struct online_char_data* +static DBMap* online_char_db; // int account_id -> struct online_char_data* +static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data); static void* create_online_char_data(DBKey key, va_list args) { @@ -210,12 +213,6 @@ static void* create_online_char_data(DBKey key, va_list args) return character; } -static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data); - -//------------------------------------------------- -// Set Character online/offline [Wizputer] -//------------------------------------------------- - void set_char_online(int map_id, int char_id, int account_id) { struct online_char_data* character; @@ -1876,9 +1873,12 @@ int parse_fromlogin(int fd) if (RFIFOREST(fd) < 7) return 0; { + unsigned char buf[16]; + int acc = RFIFOL(fd,2); int sex = RFIFOB(fd,6); - unsigned char buf[16]; + RFIFOSKIP(fd,7); + if( acc > 0 ) { int char_id[MAX_CHARS]; @@ -1888,6 +1888,10 @@ int parse_fromlogin(int fd) int i; char* data; + struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc); + if( node != NULL ) + node->sex = sex; + // get characters if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) ) Sql_ShowDebug(sql_handle); @@ -1943,7 +1947,6 @@ int parse_fromlogin(int fd) WBUFB(buf,6) = sex; mapif_sendall(buf, 7); } - RFIFOSKIP(fd,7); break; // reply to an account_reg2 registry request @@ -2013,18 +2016,19 @@ int parse_fromlogin(int fd) if (RFIFOREST(fd) < 6) return 0; { - struct online_char_data* character; int aid = RFIFOL(fd,2); - if ((character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL) - { //Kick out this player. + struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid); + RFIFOSKIP(fd,6); + if( character != NULL ) + {// account is already marked as online! if( character->server > -1 ) { //Kick it from the map server it is on. mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); if (character->waiting_disconnect == -1) - character->waiting_disconnect = add_timer(gettick()+15000, chardb_waiting_disconnect, character->account_id, 0); + character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0); } else - { //Manual kick from char server. + {// Manual kick from char server. struct char_session_data *tsd; int i; ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid ); @@ -2034,14 +2038,13 @@ int parse_fromlogin(int fd) WFIFOW(i,0) = 0x81; WFIFOB(i,2) = 2; // "Someone has already logged in with this id" WFIFOSET(i,3); + set_eof(i); } else //Shouldn't happen, but just in case. set_char_offline(99, aid); } } } - - RFIFOSKIP(fd,6); break; // ip address update signal from login server @@ -2489,30 +2492,37 @@ int parse_frommap(int fd) break; case 0x2b02: // req char selection - if (RFIFOREST(fd) < 18) + if( RFIFOREST(fd) < 18 ) return 0; + { + struct auth_node* node; - if (auth_fifo_pos >= AUTH_FIFO_SIZE) - auth_fifo_pos = 0; + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint32 ip = RFIFOL(fd,14); + RFIFOSKIP(fd,18); - auth_fifo[auth_fifo_pos].account_id = RFIFOL(fd,2); - auth_fifo[auth_fifo_pos].char_id = 0; - auth_fifo[auth_fifo_pos].login_id1 = RFIFOL(fd,6); - auth_fifo[auth_fifo_pos].login_id2 = RFIFOL(fd,10); - auth_fifo[auth_fifo_pos].delflag = 2; - auth_fifo[auth_fifo_pos].expiration_time = 0; // unlimited/unknown time by default (not display in map-server) - auth_fifo[auth_fifo_pos].ip = ntohl(RFIFOL(fd,14)); - auth_fifo_pos++; + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = account_id; + node->char_id = 0; + node->login_id1 = login_id1; + node->login_id2 = login_id2; + //node->sex = 0; + node->ip = ntohl(ip); + node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server) + idb_put(auth_db, account_id, node); //Set char to "@ char select" in online db [Kevin] - set_char_online(-3, 99, RFIFOL(fd,2)); + set_char_online(-3, 99, account_id); WFIFOHEAD(fd,7); WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = RFIFOL(fd,2); + WFIFOL(fd,2) = account_id; WFIFOB(fd,6) = 0; WFIFOSET(fd,7); - RFIFOSKIP(fd,18); + } break; case 0x2b05: // request "change map server" @@ -2961,20 +2971,23 @@ int parse_char(int fd) // request to connect // 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B case 0x65: - if (RFIFOREST(fd) < 17) + if( RFIFOREST(fd) < 17 ) return 0; { + struct auth_node* node; + int account_id = RFIFOL(fd,2); - int login_id1 = RFIFOL(fd,6); - int login_id2 = RFIFOL(fd,10); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); int sex = RFIFOB(fd,16); + RFIFOSKIP(fd,17); ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2); + if (sd) { //Received again auth packet for already authentified account?? Discard it. //TODO: Perhaps log this as a hack attempt? //TODO: and perhaps send back a reply? - RFIFOSKIP(fd,17); break; } @@ -2993,17 +3006,18 @@ int parse_char(int fd) WFIFOSET(fd,4); // search authentification - ARR_FIND( 0, AUTH_FIFO_SIZE, i, - auth_fifo[i].account_id == sd->account_id && - auth_fifo[i].login_id1 == sd->login_id1 && - auth_fifo[i].login_id2 == sd->login_id2 && - auth_fifo[i].ip == session[fd]->client_addr && - auth_fifo[i].delflag == 2 ); - - if( i < AUTH_FIFO_SIZE ) { - auth_fifo[i].delflag = 1; + node = (struct auth_node*)idb_get(auth_db, account_id); + if( node != NULL && + node->account_id == account_id && + node->login_id1 == login_id1 && + node->login_id2 == login_id2 && + node->ip == ipl ) + {// authentication found (coming from map server) + idb_remove(auth_db, account_id); char_auth_ok(fd, sd); - } else { // authentication not found + } + else + {// authentication not found (coming from login server) if (login_fd > 0) { // don't send request if no login-server WFIFOHEAD(login_fd,19); WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account @@ -3011,7 +3025,7 @@ int parse_char(int fd) WFIFOL(login_fd,6) = sd->login_id1; WFIFOL(login_fd,10) = sd->login_id2; WFIFOB(login_fd,14) = sd->sex; - WFIFOL(login_fd,15) = htonl(session[fd]->client_addr); + WFIFOL(login_fd,15) = htonl(ipl); WFIFOSET(login_fd,19); } else { // if no login-server, we must refuse connection WFIFOHEAD(fd,3); @@ -3021,21 +3035,22 @@ int parse_char(int fd) } } } - - RFIFOSKIP(fd,17); break; // char select case 0x66: FIFOSD_CHECK(3); - - do //FIXME: poor code structure { struct mmo_charstatus char_dat; char* data; int char_id; + uint32 subnet_map_ip; + struct auth_node* node; + + int slot = RFIFOB(fd,2); + RFIFOSKIP(fd,3); - if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, RFIFOB(fd,2)) + if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot) || SQL_SUCCESS != Sql_NextRow(sql_handle) || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) ) { @@ -3056,10 +3071,10 @@ int parse_char(int fd) Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH)); if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')", - charlog_db, sd->account_id, RFIFOB(fd, 2), esc_name) ) + charlog_db, sd->account_id, slot, esc_name) ) Sql_ShowDebug(sql_handle); } - ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, RFIFOB(fd, 2), char_dat.name); + ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name); // searching map server i = search_mapserver(char_dat.last_point.map, -1, -1); @@ -3107,31 +3122,8 @@ int parse_char(int fd) char_dat.last_point.map = j; } - //Send player to map - WFIFOHEAD(fd,28); - WFIFOW(fd,0) = 0x71; - WFIFOL(fd,2) = char_dat.char_id; - mapindex_getmapname_ext(mapindex_id2name(char_dat.last_point.map), (char*)WFIFOP(fd,6)); - { - // Advanced subnet check [LuzZza] - uint32 subnet_map_ip; - subnet_map_ip = lan_subnetcheck(ipl); - WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); - WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - WFIFOSET(fd,28); - } - if (auth_fifo_pos >= AUTH_FIFO_SIZE) - auth_fifo_pos = 0; - auth_fifo[auth_fifo_pos].account_id = sd->account_id; - auth_fifo[auth_fifo_pos].char_id = char_dat.char_id; - auth_fifo[auth_fifo_pos].login_id1 = sd->login_id1; - auth_fifo[auth_fifo_pos].login_id2 = sd->login_id2; - auth_fifo[auth_fifo_pos].delflag = 0; - auth_fifo[auth_fifo_pos].sex = sd->sex; - auth_fifo[auth_fifo_pos].expiration_time = sd->expiration_time; - auth_fifo[auth_fifo_pos].ip = session[fd]->client_addr; - //Send NEW auth packet [Kevin] + //FIXME: is this case even possible? [ultramage] if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL) { ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i); @@ -3145,26 +3137,46 @@ int parse_char(int fd) break; } + //Send player to map + WFIFOHEAD(fd,28); + WFIFOW(fd,0) = 0x71; + WFIFOL(fd,2) = char_dat.char_id; + mapindex_getmapname_ext(mapindex_id2name(char_dat.last_point.map), (char*)WFIFOP(fd,6)); + + // Advanced subnet check [LuzZza] + subnet_map_ip = lan_subnetcheck(ipl); + WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); + WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] + WFIFOSET(fd,28); + //Send auth ok to map server WFIFOHEAD(map_fd,20 + sizeof(struct mmo_charstatus)); WFIFOW(map_fd,0) = 0x2afd; WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus); - WFIFOL(map_fd,4) = auth_fifo[auth_fifo_pos].account_id; - WFIFOL(map_fd,8) = auth_fifo[auth_fifo_pos].login_id1; - WFIFOL(map_fd,16) = auth_fifo[auth_fifo_pos].login_id2; - WFIFOL(map_fd,12) = (unsigned long)auth_fifo[auth_fifo_pos].expiration_time; + WFIFOL(map_fd,4) = sd->account_id; + WFIFOL(map_fd,8) = sd->login_id1; + WFIFOL(map_fd,16) = sd->login_id2; + WFIFOL(map_fd,12) = (unsigned long)sd->expiration_time; memcpy(WFIFOP(map_fd,20), &char_dat, sizeof(struct mmo_charstatus)); WFIFOSET(map_fd, WFIFOW(map_fd,2)); - set_char_online(i, char_dat.char_id, char_dat.account_id); - auth_fifo_pos++; - } while(0); + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = sd->account_id; + node->char_id = char_dat.char_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->sex; + node->expiration_time = sd->expiration_time; + node->ip = ipl; + idb_put(auth_db, sd->account_id, node); - RFIFOSKIP(fd,3); + set_char_online(i, char_dat.char_id, char_dat.account_id); + } break; // create new char - // S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot.B <hair color>.W <hair style>.W + // S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W case 0x67: FIFOSD_CHECK(37); @@ -3922,6 +3934,7 @@ void do_final(void) do_close(char_fd); char_db_->destroy(char_db_, NULL); online_char_db->destroy(online_char_db, NULL); + auth_db->destroy(auth_db, NULL); Sql_Free(sql_handle); if( lsql_handle ) @@ -3972,6 +3985,7 @@ int do_init(int argc, char **argv) ShowInfo("Finished reading the inter-server configuration.\n"); ShowInfo("Initializing char server.\n"); + auth_db = idb_alloc(DB_OPT_RELEASE_DATA); online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); mmo_char_sql_init(); char_read_fame_list(); //Read fame lists. diff --git a/src/char_sql/inter.c b/src/char_sql/inter.c index 4f856211d..00c29568b 100644 --- a/src/char_sql/inter.c +++ b/src/char_sql/inter.c @@ -643,8 +643,8 @@ int mapif_parse_WisRequest(int fd) ShowError("inter: Wis message doesn't exist.\n"); return 0; } - memcpy(name, RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] - name[NAME_LENGTH-1]= '\0'; + + safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name) ) |