Browse Source

Modified the charservers to use a DBMap instead of a cyclic array for auth data.
Merged the auth fix from r12473 to TXT as well.
Removed the no-op from r12547.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@12551 54d463be-8e91-2dee-dedb-b68131a5f0ec

ultramage 17 years ago
parent
commit
fd5f918452
7 changed files with 440 additions and 424 deletions
  1. 309 291
      src/char/char.c
  2. 5 5
      src/char/inter.c
  3. 118 104
      src/char_sql/char.c
  4. 2 2
      src/char_sql/inter.c
  5. 0 9
      src/login/login.c
  6. 2 11
      src/login_sql/login.c
  7. 4 2
      src/map/chrif.c

+ 309 - 291
src/char/char.c

@@ -111,16 +111,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_id_count = START_CHAR_NUM;
 struct character_data *char_dat;
 
@@ -160,7 +150,29 @@ int online_gm_display_min_level = 20; // minimum GM level to display 'GM' when w
 //These are used to aid the map server in identifying valid clients. [Skotlex]
 static int max_account_id = DEFAULT_MAX_ACCOUNT_ID, max_char_id = DEFAULT_MAX_CHAR_ID;
 
-//Structure for holding in memory which characters are online on the map servers connected.
+int console = 0;
+
+//-----------------------------------------------------
+// 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;
@@ -169,135 +181,13 @@ struct online_char_data {
 	short server;
 };
 
-// Holds all online characters.
 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);
 
-int console = 0;
-
-//------------------------------
-// Writing function of logs file
-//------------------------------
-int char_log(char *fmt, ...)
-{
-	if(log_char)
-	{
-		FILE *logfp;
-		va_list ap;
-		time_t raw_time;
-		char tmpstr[2048];
-
-		va_start(ap, fmt);
-
-		logfp = fopen(char_log_filename, "a");
-		if (logfp) {
-			if (fmt[0] == '\0') // jump a line if no message
-				fprintf(logfp, "\n");
-			else {
-				time(&raw_time);
-				strftime(tmpstr, 24, "%d-%m-%Y %H:%M:%S", localtime(&raw_time));
-				sprintf(tmpstr + 19, ": %s", fmt);
-				vfprintf(logfp, tmpstr, ap);
-			}
-			fclose(logfp);
-		}
-		va_end(ap);
-	}
-	return 0;
-}
-
-//----------------------------------------------------------------------
-// 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)
-//----------------------------------------------------------------------
-int isGM(int account_id)
-{
-	int i;
-
-	for(i = 0; i < GM_num; i++)
-		if (gm_account[i].account_id == account_id)
-			return gm_account[i].level;
-	return 0;
-}
-
-//Search character data from the aid/cid givem
-struct mmo_charstatus* search_character(int aid, int cid)
-{
-	int i;
-	for (i = 0; i < char_num; i++) {
-		if (char_dat[i].status.char_id == cid && char_dat[i].status.account_id == aid)
-			return &char_dat[i].status;
-	}
-	return NULL;
-}
-	
-struct mmo_charstatus* search_character_byname(char* character_name)
-{
-	int i = search_character_index(character_name);
-	if (i == -1) return NULL;
-	return &char_dat[i].status;
-}
-
-//----------------------------------------------
-// Search an character id
-//   (return character index or -1 (if not found))
-//   If exact character name is not found,
-//   the function checks without case sensitive
-//   and returns index if only 1 character is found
-//   and similar to the searched name.
-//----------------------------------------------
-int search_character_index(char* character_name)
-{
-	int i, quantity, index;
-
-	quantity = 0;
-	index = -1;
-	for(i = 0; i < char_num; i++) {
-		// Without case sensitive check (increase the number of similar character names found)
-		if (stricmp(char_dat[i].status.name, character_name) == 0) {
-			// Strict comparison (if found, we finish the function immediatly with correct value)
-			if (strcmp(char_dat[i].status.name, character_name) == 0)
-				return i;
-			quantity++;
-			index = i;
-		}
-	}
-	// Here, the exact character name is not found
-	// We return the found index of a similar account ONLY if there is 1 similar character
-	if (quantity == 1)
-		return index;
-
-	// Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found
-	return -1;
-}
-
-//-------------------------------------
-// Return character name with the index
-//-------------------------------------
-char * search_character_name(int index)
-{
-	if (index >= 0 && index < char_num)
-		return char_dat[index].status.name;
-
-	return unknown_char_name;
-}
-
-// Searches if the given character is online, and returns the fd of the
-// map-server it is connected to.
-int search_character_online(int aid, int cid)
+static void* create_online_char_data(DBKey key, va_list args)
 {
-	//Look for online character.
 	struct online_char_data* character;
-	character = (struct online_char_data*)idb_get(online_char_db, aid);
-	if(character &&
-		character->char_id == cid &&
-		character->server > -1) 
-		return server[character->server].fd;
-	return -1;
-}
-static void * create_online_char_data(DBKey key, va_list args)
-{
-	struct online_char_data* character;
-	character = (struct online_char_data*)aCalloc(1, sizeof(struct online_char_data));
+	CREATE(character, struct online_char_data, 1);
 	character->account_id = key.i;
 	character->char_id = -1;
   	character->server = -1;
@@ -306,12 +196,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;
@@ -328,7 +212,7 @@ void set_char_online(int map_id, int char_id, int account_id)
 	}
 
 	character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data);
-	if (online_check && character->char_id != -1 && character->server > -1 && character->server != map_id)
+	if (online_check && character->char_id != -1 && character->server > -1 && character->server != map_id && map_id != -3)
 	{
 		//char == 99 <- Character logging in, so someone has logged in while one
 		//char is still on map-server, so kick him out, but don't print "error"
@@ -339,9 +223,6 @@ void set_char_online(int map_id, int char_id, int account_id)
 		mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
 	}
 
-	character->char_id = (char_id==99)?-1:char_id;
-	character->server = (char_id==99)?-1:map_id;
-
 	if( character->server > -1 )
 		server[character->server].users++;
 
@@ -349,6 +230,13 @@ void set_char_online(int map_id, int char_id, int account_id)
 		delete_timer(character->waiting_disconnect, chardb_waiting_disconnect);
 		character->waiting_disconnect = -1;
 	}
+
+	//If user is NOT at char screen, delete entry [Kevin]
+	if(character->char_id != -1)
+	{
+		idb_remove(online_char_db, account_id);
+	}
+
 	if (login_fd > 0 && !session[login_fd]->flag.eof)
 	{	
 		WFIFOHEAD(login_fd,6);
@@ -435,6 +323,116 @@ void set_all_offline(int id)
 	WFIFOSET(login_fd,2);
 }
 
+//------------------------------
+// Writing function of logs file
+//------------------------------
+int char_log(char *fmt, ...)
+{
+	if(log_char)
+	{
+		FILE *logfp;
+		va_list ap;
+		time_t raw_time;
+		char tmpstr[2048];
+
+		va_start(ap, fmt);
+
+		logfp = fopen(char_log_filename, "a");
+		if (logfp) {
+			if (fmt[0] == '\0') // jump a line if no message
+				fprintf(logfp, "\n");
+			else {
+				time(&raw_time);
+				strftime(tmpstr, 24, "%d-%m-%Y %H:%M:%S", localtime(&raw_time));
+				sprintf(tmpstr + 19, ": %s", fmt);
+				vfprintf(logfp, tmpstr, ap);
+			}
+			fclose(logfp);
+		}
+		va_end(ap);
+	}
+	return 0;
+}
+
+//----------------------------------------------------------------------
+// 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)
+//----------------------------------------------------------------------
+int isGM(int account_id)
+{
+	int i;
+
+	for(i = 0; i < GM_num; i++)
+		if (gm_account[i].account_id == account_id)
+			return gm_account[i].level;
+	return 0;
+}
+
+//Search character data from the aid/cid givem
+struct mmo_charstatus* search_character(int aid, int cid)
+{
+	int i;
+	for (i = 0; i < char_num; i++) {
+		if (char_dat[i].status.char_id == cid && char_dat[i].status.account_id == aid)
+			return &char_dat[i].status;
+	}
+	return NULL;
+}
+	
+struct mmo_charstatus* search_character_byname(char* character_name)
+{
+	int i = search_character_index(character_name);
+	if (i == -1) return NULL;
+	return &char_dat[i].status;
+}
+
+// Searches if the given character is online, and returns the fd of the
+// map-server it is connected to.
+int search_character_online(int aid, int cid)
+{
+	//Look for online character.
+	struct online_char_data* character;
+	character = idb_get(online_char_db, aid);
+	if(character &&
+		character->char_id == cid &&
+		character->server > -1) 
+		return server[character->server].fd;
+	return -1;
+}
+
+//----------------------------------------------
+// Search an character id
+//   (return character index or -1 (if not found))
+//   If exact character name is not found,
+//   the function checks without case sensitive
+//   and returns index if only 1 character is found
+//   and similar to the searched name.
+//----------------------------------------------
+int search_character_index(char* character_name)
+{
+	int i, quantity, index;
+
+	quantity = 0;
+	index = -1;
+	for(i = 0; i < char_num; i++) {
+		// Without case sensitive check (increase the number of similar character names found)
+		if (stricmp(char_dat[i].status.name, character_name) == 0) {
+			// Strict comparison (if found, we finish the function immediatly with correct value)
+			if (strcmp(char_dat[i].status.name, character_name) == 0)
+				return i;
+			quantity++;
+			index = i;
+		}
+	}
+	// Here, the exact character name is not found
+	// We return the found index of a similar account ONLY if there is 1 similar character
+	if (quantity == 1)
+		return index;
+
+	// Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found
+	return -1;
+}
+
 /*---------------------------------------------------
   Make a data line for friends list
  --------------------------------------------------*/
@@ -2066,72 +2064,77 @@ int parse_fromlogin(int fd)
 			RFIFOSKIP(fd,2);
 		break;
 
-		case 0x2723:	// changesex reply (modified by [Yor])
+		// changesex reply
+		case 0x2723:
 			if (RFIFOREST(fd) < 7)
 				return 0;
 		{
-			int acc, sex, i, j;
+			int i, j;
 			unsigned char buf[7];
-			acc = RFIFOL(fd,2);
-			sex = RFIFOB(fd,6);
-			if (acc > 0) {
-				for(i = 0; i < AUTH_FIFO_SIZE; i++) {
-					if (auth_fifo[i].account_id == acc)	
-						auth_fifo[i].sex = sex;
-				}
-				for (i = 0; i < char_num; i++) {
-					if (char_dat[i].status.account_id == acc) {
-						int jobclass = char_dat[i].status.class_;
-						char_dat[i].status.sex = sex;
-						if (jobclass == JOB_BARD || jobclass == JOB_DANCER ||
-						    jobclass == JOB_CLOWN || jobclass == JOB_GYPSY ||
-						    jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) {
-							// job modification
-							if (jobclass == JOB_BARD || jobclass == JOB_DANCER) {
-								char_dat[i].status.class_ = (sex) ? JOB_BARD : JOB_DANCER;
-							} else if (jobclass == JOB_CLOWN || jobclass == JOB_GYPSY) {
-								char_dat[i].status.class_ = (sex) ? JOB_CLOWN : JOB_GYPSY;
-							} else if (jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) {
-								char_dat[i].status.class_ = (sex) ? JOB_BABY_BARD : JOB_BABY_DANCER;
-							}
-							// remove specifical skills of classes 19, 4020 and 4042
-							for(j = 315; j <= 322; j++) {
-								if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) {
-									if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv)
-										char_dat[i].status.skill_point = USHRT_MAX;
-									else
-										char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv;
-									char_dat[i].status.skill[j].id = 0;
-									char_dat[i].status.skill[j].lv = 0;
-								}
-							}
-							// remove specifical skills of classes 20, 4021 and 4043
-							for(j = 323; j <= 330; j++) {
-								if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) {
-									if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv)
-										char_dat[i].status.skill_point = USHRT_MAX;
-									else
-										char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv;
-
-									char_dat[i].status.skill[j].id = 0;
-									char_dat[i].status.skill[j].lv = 0;
-								}
+
+			int acc = RFIFOL(fd,2);
+			int sex = RFIFOB(fd,6);
+			RFIFOSKIP(fd,7);
+
+			if( acc > 0 )
+			{
+				struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
+				if( node != NULL )
+					node->sex = sex;
+
+				ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == acc );
+				if( i < char_num )
+				{
+					int jobclass = char_dat[i].status.class_;
+					char_dat[i].status.sex = sex;
+					if (jobclass == JOB_BARD || jobclass == JOB_DANCER ||
+					    jobclass == JOB_CLOWN || jobclass == JOB_GYPSY ||
+					    jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) {
+						// job modification
+						if (jobclass == JOB_BARD || jobclass == JOB_DANCER) {
+							char_dat[i].status.class_ = (sex) ? JOB_BARD : JOB_DANCER;
+						} else if (jobclass == JOB_CLOWN || jobclass == JOB_GYPSY) {
+							char_dat[i].status.class_ = (sex) ? JOB_CLOWN : JOB_GYPSY;
+						} else if (jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) {
+							char_dat[i].status.class_ = (sex) ? JOB_BABY_BARD : JOB_BABY_DANCER;
+						}
+						// remove specifical skills of classes 19, 4020 and 4042
+						for(j = 315; j <= 322; j++) {
+							if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) {
+								if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv)
+									char_dat[i].status.skill_point = USHRT_MAX;
+								else
+									char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv;
+								char_dat[i].status.skill[j].id = 0;
+								char_dat[i].status.skill[j].lv = 0;
 							}
 						}
-						// to avoid any problem with equipment and invalid sex, equipment is unequiped.
-						for (j = 0; j < MAX_INVENTORY; j++) {
-							if (char_dat[i].status.inventory[j].nameid && char_dat[i].status.inventory[j].equip)
-								char_dat[i].status.inventory[j].equip = 0;
+						// remove specifical skills of classes 20, 4021 and 4043
+						for(j = 323; j <= 330; j++) {
+							if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) {
+								if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv)
+									char_dat[i].status.skill_point = USHRT_MAX;
+								else
+									char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv;
+
+								char_dat[i].status.skill[j].id = 0;
+								char_dat[i].status.skill[j].lv = 0;
+							}
 						}
-						char_dat[i].status.weapon = 0;
-						char_dat[i].status.shield = 0;
-						char_dat[i].status.head_top = 0;
-						char_dat[i].status.head_mid = 0;
-						char_dat[i].status.head_bottom = 0;
-
-						if (char_dat[i].status.guild_id)	//If there is a guild, update the guild_member data [Skotlex]
-							inter_guild_sex_changed(char_dat[i].status.guild_id, acc, char_dat[i].status.char_id, sex);
 					}
+					// to avoid any problem with equipment and invalid sex, equipment is unequiped.
+					for (j = 0; j < MAX_INVENTORY; j++) {
+						if (char_dat[i].status.inventory[j].nameid && char_dat[i].status.inventory[j].equip)
+							char_dat[i].status.inventory[j].equip = 0;
+					}
+					char_dat[i].status.weapon = 0;
+					char_dat[i].status.shield = 0;
+					char_dat[i].status.head_top = 0;
+					char_dat[i].status.head_mid = 0;
+					char_dat[i].status.head_bottom = 0;
+
+					if (char_dat[i].status.guild_id)	//If there is a guild, update the guild_member data [Skotlex]
+						inter_guild_sex_changed(char_dat[i].status.guild_id, acc, char_dat[i].status.char_id, sex);
 				}
 				// disconnect player if online on char-server
 				disconnect_player(acc);
@@ -2140,8 +2143,6 @@ int parse_fromlogin(int fd)
 			WBUFL(buf,2) = acc;
 			WBUFB(buf,6) = sex;
 			mapif_sendall(buf, 7);
-
-			RFIFOSKIP(fd,7);
 		}
 		break;
 
@@ -2318,38 +2319,39 @@ int parse_fromlogin(int fd)
 		}
 		break;
 
-		//Login server request to kick a character out. [Skotlex]
+		// Login server request to kick a character out. [Skotlex]
 		case 0x2734:
 			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.
-				if (character->server > -1)
+			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);
-				} else { //Manual kick from char server.
+						character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
+				}
+				else
+				{// Manual kick from char server.
 					struct char_session_data *tsd;
 					int i;
-					for(i = 0; i < fd_max; i++) {
-						if (session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid)
-						{
-							WFIFOHEAD(i,3);
-							WFIFOW(i,0) = 0x81;
-							WFIFOB(i,2) = 2; // "Someone has already logged in with this id"
-							WFIFOSET(i,3);
-							break;
-						}
+					ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
+					if( i < fd_max )
+					{
+						WFIFOHEAD(i,3);
+						WFIFOW(i,0) = 0x81;
+						WFIFOB(i,2) = 2; // "Someone has already logged in with this id"
+						WFIFOSET(i,3);
+						set_eof(i);
 					}
-					if (i == fd_max) //Shouldn't happen, but just in case.
+					else //Shouldn't happen, but just in case.
 						set_char_offline(99, aid);
 				}
 			}
-			RFIFOSKIP(fd,6);
 		}
 		break;
 		
@@ -2798,26 +2800,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;
+
+			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);
+
+			// 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, account_id);
 
-			if (auth_fifo_pos >= AUTH_FIFO_SIZE)
-				auth_fifo_pos = 0;
-
-			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++;
 			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"
@@ -3204,7 +3217,7 @@ int parse_char(int fd)
 		{
 			struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
 			if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex]
-				set_char_offline(99,sd->account_id);
+				set_char_offline(-1,sd->account_id);
 			if( data != NULL && data->fd == fd)
 				data->fd = -1;
 		}
@@ -3224,24 +3237,27 @@ 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 GM_value;
+
 			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);
 
-			int GM_value;
 			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;
 			}
+
 			if( (GM_value = isGM(account_id)) != 0 )
 				ShowInfo("Account Logged On; Account ID: %d (GM level %d).\n", account_id, GM_value);
 			else
@@ -3263,17 +3279,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
@@ -3281,7 +3298,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);
@@ -3291,17 +3308,17 @@ int parse_char(int fd)
 				}
 			}
 		}
-
-			RFIFOSKIP(fd,17);
 		break;
 
 		// char select
 		case 0x66:
 			FIFOSD_CHECK(3);
 		{
-			int slot = RFIFOB(fd,2);
 			struct mmo_charstatus *cd;
+			uint32 subnet_map_ip;
+			struct auth_node* node;
 
+			int slot = RFIFOB(fd,2);
 			RFIFOSKIP(fd,3);
 
 			// if we activated email creation and email is default email
@@ -3369,33 +3386,8 @@ int parse_char(int fd)
 				cd->last_point.map = j;
 			}
 
-			//Send player to map
-			WFIFOHEAD(fd,28);
-			WFIFOW(fd,0) = 0x71;
-			WFIFOL(fd,2) = cd->char_id;
-			mapindex_getmapname_ext(mapindex_id2name(cd->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);
-		}
-			ShowInfo("Character selection '%s' (account: %d, slot: %d).\n", cd->name, sd->account_id, ch);
-
-			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 = cd->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);
@@ -3409,19 +3401,43 @@ int parse_char(int fd)
 				break;
 			}
 
-			//Send auth to server.
-			WFIFOHEAD(map_fd, 20 + sizeof(struct mmo_charstatus));
+			//Send player to map
+			WFIFOHEAD(fd,28);
+			WFIFOW(fd,0) = 0x71;
+			WFIFOL(fd,2) = cd->char_id;
+			mapindex_getmapname_ext(mapindex_id2name(cd->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);
+
+			ShowInfo("Character selection '%s' (account: %d, slot: %d).\n", cd->name, sd->account_id, ch);
+
+			//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), cd, sizeof(struct mmo_charstatus));
 			WFIFOSET(map_fd, WFIFOW(map_fd,2));
 
+			// create temporary auth entry
+			CREATE(node, struct auth_node, 1);
+			node->account_id = sd->account_id;
+			node->char_id = cd->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);
+
 			set_char_online(i, cd->char_id, cd->account_id);
-			auth_fifo_pos++;
 		}
 		break;
 
@@ -4158,6 +4174,7 @@ void do_final(void)
 	online_char_db->clear(online_char_db, NULL); //clean the db...
 	create_online_files();
 	online_char_db->destroy(online_char_db, NULL); //dispose the db...
+	auth_db->destroy(auth_db, NULL);
 	
 	if(gm_account) aFree(gm_account);
 	if(char_dat) aFree(char_dat);
@@ -4219,6 +4236,7 @@ int do_init(int argc, char **argv)
 	char_log("The char-server starting...\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_init();
 	char_read_fame_list(); //Read fame lists.

+ 5 - 5
src/char/inter.c

@@ -8,6 +8,7 @@
 #include "../common/malloc.h"
 #include "../common/lock.h"
 #include "../common/showmsg.h"
+#include "../common/strlib.h"
 #include "char.h"
 #include "inter.h"
 #include "int_party.h"
@@ -480,14 +481,13 @@ static struct WisData* mapif_create_whisper(int fd, char* src, char* dst, char*
 }
 
 // Wisp/page request to send
-int mapif_parse_WisRequest(int fd) {
+int mapif_parse_WisRequest(int fd)
+{
 	struct mmo_charstatus* char_status;
 	struct WisData* wd;
 	char name[NAME_LENGTH];
 	int fd2;
 
-	RFIFOHEAD(fd);
-
 	if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) {
 		ShowWarning("inter: Wis message size too long.\n");
 		return 0;
@@ -496,8 +496,8 @@ int mapif_parse_WisRequest(int fd) {
 		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]
+
 	// search if character exists before to ask all map-servers
 	char_status = search_character_byname(name);
 	if (char_status == NULL)

+ 118 - 104
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.

+ 2 - 2
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) )

+ 0 - 9
src/login/login.c

@@ -1152,15 +1152,6 @@ int parse_fromchar(int fd)
 
 				//ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip);
 
-				struct online_login_data* od = (struct online_login_data*)idb_get(online_db, account_id);
-
-				//Leave info in online data DB [Kevin]
-				if(od->waiting_disconnect != -1)
-				{
-					delete_timer(od->waiting_disconnect, waiting_disconnect_timer);
-					od->waiting_disconnect = -1;
-				}
-
 				// each auth entry can only be used once
 				idb_remove(auth_db, account_id);
 

+ 2 - 11
src/login_sql/login.c

@@ -668,8 +668,8 @@ int parse_fromchar(int fd)
 			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);
 			char sex = sex_num2str(RFIFOB(fd,14));
 			uint32 ip_ = ntohl(RFIFOL(fd,15));
 			RFIFOSKIP(fd,19);
@@ -685,15 +685,6 @@ int parse_fromchar(int fd)
 				uint32 expiration_time;
 				char email[40];
 
-				struct online_login_data* od = (struct online_login_data*)idb_get(online_db, account_id);
-
-				//Leave info in online data DB [Kevin]
-				if(od->waiting_disconnect != -1)
-				{
-					delete_timer(od->waiting_disconnect, waiting_disconnect_timer);
-					od->waiting_disconnect = -1;
-				}
-
 				// each auth entry can only be used once
 				idb_remove(auth_db, account_id);
 

+ 4 - 2
src/map/chrif.c

@@ -111,12 +111,14 @@ struct auth_node* chrif_search(int account_id)
 	return (struct auth_node*)idb_get(auth_db, account_id);
 }
 
-struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state state) {
+struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state state)
+{
 	struct auth_node *node = chrif_search(account_id);
 	return (node && node->char_id == char_id && node->state == state)?node:NULL;
 }
 
-bool chrif_auth_delete(int account_id, int char_id, enum sd_state state) {
+bool chrif_auth_delete(int account_id, int char_id, enum sd_state state)
+{
 	struct auth_node *node;
 	if ((node=chrif_auth_check(account_id, char_id, state)))
 	{