Ver Fonte

* Quick&dirty reversal of the inter-server behaviour introduced in r3255/r3256:
- the behaviour enabled a desynch between the char-server and the map-server
- now the map-server asks the char-server to authenticate the auth info (the char-server doesn't send the auth info immediatelly)

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

FlavioJS há 17 anos atrás
pai
commit
49aac80ed6
4 ficheiros alterados com 224 adições e 14 exclusões
  1. 4 0
      Changelog-Trunk.txt
  2. 76 0
      src/char/char.c
  3. 83 1
      src/char_sql/char.c
  4. 61 13
      src/map/chrif.c

+ 4 - 0
Changelog-Trunk.txt

@@ -4,6 +4,10 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 2008/04/13
+	* Quick&dirty reversal of the inter-server behaviour introduced in r3255/r3256:
+	- the behaviour enabled a desynch between the char-server and the map-server
+	- now the map-server asks the char-server to authenticate the auth info
+	  (the char-server doesn't send the auth info immediatelly)
 	* Changes to the configure script: [FlavioJS]
 	- clarified how --with-zlib is used
 	- added --enable-packetver to set the PACKETVER define (used often enough 

+ 76 - 0
src/char/char.c

@@ -2838,12 +2838,16 @@ int parse_frommap(int fd)
 			//Tell the new map server about this player using Kevin's new auth packet. [Skotlex]
 			if (map_fd >= 0 && session[map_fd] && char_data) 
 			{	//Send the map server the auth of this player.
+				struct auth_node* node;
+
 				//Update the "last map" as this is where the player must be spawned on the new map server.
 				char_data->last_point.map = RFIFOW(fd,18);
 				char_data->last_point.x = RFIFOW(fd,20);
 				char_data->last_point.y = RFIFOW(fd,22);
 				char_data->sex = RFIFOB(fd,30);
 
+#if 0
+				// the map-server must request it [FlavioJS]
 				WFIFOHEAD(map_fd, 20 + sizeof(struct mmo_charstatus));
 				WFIFOW(map_fd,0) = 0x2afd;
 				WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus);
@@ -2853,6 +2857,18 @@ int parse_frommap(int fd)
 				WFIFOL(map_fd,12) = (unsigned long)0; //TODO: expiration_time, how do I figure it out right now?
 				memcpy(WFIFOP(map_fd,20), char_data, sizeof(struct mmo_charstatus));
 				WFIFOSET(map_fd, WFIFOW(map_fd,2));
+#endif
+
+				// create temporary auth entry
+				CREATE(node, struct auth_node, 1);
+				node->account_id = RFIFOL(fd,2);
+				node->char_id = RFIFOL(fd,14);
+				node->login_id1 = RFIFOL(fd,6);
+				node->login_id2 = RFIFOL(fd,10);
+				node->sex = RFIFOB(fd,30);
+				node->expiration_time = 0; // FIXME
+				node->ip = ntohl(RFIFOL(fd,31));
+				idb_put(auth_db, RFIFOL(fd,2), node);
 
 				data = (struct online_char_data*)idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
 				data->char_id = char_data->char_id;
@@ -3111,6 +3127,63 @@ int parse_frommap(int fd)
 			RFIFOSKIP(fd,2);
 		break;
 
+		case 0x2b26: // auth request from map-server
+			if (RFIFOREST(fd) < 19)
+				return 0;
+
+		{
+			int account_id;
+			int char_id;
+			int login_id1;
+			char sex;
+			uint32 ip;
+			struct auth_node* node;
+			struct mmo_charstatus* cd;
+
+			account_id = RFIFOL(fd,2);
+			char_id    = RFIFOL(fd,6);
+			login_id1  = RFIFOL(fd,10);
+			sex        = RFIFOB(fd,14);
+			ip         = ntohl(RFIFOL(fd,15));
+			RFIFOSKIP(fd,19);
+
+			node = (struct auth_node*)idb_get(auth_db, account_id);
+			cd = search_character(account_id, char_id);
+			if( node != NULL && cd != NULL &&
+				node->account_id == account_id &&
+				node->char_id == char_id &&
+				node->login_id1 == login_id1 &&
+				node->sex == sex &&
+				node->ip == ip )
+			{// auth ok
+				WFIFOHEAD(fd,20 + sizeof(struct mmo_charstatus));
+				WFIFOW(fd,0) = 0x2afd;
+				WFIFOW(fd,2) = 20 + sizeof(struct mmo_charstatus);
+				WFIFOL(fd,4) = account_id;
+				WFIFOL(fd,8) = login_id1;
+				WFIFOL(fd,12) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
+				WFIFOL(fd,16) = node->login_id2;
+				memcpy(WFIFOP(fd,20), cd, sizeof(struct mmo_charstatus));
+				WFIFOSET(fd, WFIFOW(fd,2));
+
+				// only use the auth once and mark user online
+				idb_remove(auth_db, account_id);
+				set_char_online(id, account_id, char_id);
+			}
+			else
+			{// auth failed
+				WFIFOHEAD(fd,19);
+				WFIFOW(fd,0) = 0x2b27;
+				WFIFOL(fd,2) = account_id;
+				WFIFOL(fd,6) = char_id;
+				WFIFOL(fd,10) = login_id1;
+				WFIFOB(fd,14) = sex;
+				WFIFOL(fd,15) = htonl(ip);
+				WFIFOSET(fd,19);
+			}
+		}
+		break;
+
 		case 0x2736: // ip address update
 			if (RFIFOREST(fd) < 6) return 0;
 			server[id].ip = ntohl(RFIFOL(fd, 2));
@@ -3398,6 +3471,8 @@ int parse_char(int fd)
 
 			ShowInfo("Character selection '%s' (account: %d, slot: %d).\n", cd->name, sd->account_id, ch);
 
+#if 0
+			// The server must request it [FlavioJS]
 			//Send auth ok to map server
 			WFIFOHEAD(map_fd,20 + sizeof(struct mmo_charstatus));
 			WFIFOW(map_fd,0) = 0x2afd;
@@ -3408,6 +3483,7 @@ int parse_char(int fd)
 			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));
+#endif
 
 			// create temporary auth entry
 			CREATE(node, struct auth_node, 1);

+ 83 - 1
src/char_sql/char.c

@@ -2532,17 +2532,21 @@ int parse_frommap(int fd)
 			if (char_data == NULL) 
 			{	//Really shouldn't happen.
 				mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true);
-				char_data = &char_dat;
+				char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
 			}
 			//Tell the new map server about this player using Kevin's new auth packet. [Skotlex]
 			if (map_fd >= 0 && session[map_fd] && char_data) 
 			{	//Send the map server the auth of this player.
+				struct auth_node* node;
+
 				//Update the "last map" as this is where the player must be spawned on the new map server.
 				char_data->last_point.map = RFIFOW(fd,18);
 				char_data->last_point.x = RFIFOW(fd,20);
 				char_data->last_point.y = RFIFOW(fd,22);
 				char_data->sex = RFIFOB(fd,30);
 
+#if 0
+				// the map-server must request it [FlavioJS]
 				WFIFOHEAD(map_fd, 20 + sizeof(struct mmo_charstatus));
 				WFIFOW(map_fd,0) = 0x2afd;
 				WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus);
@@ -2552,6 +2556,18 @@ int parse_frommap(int fd)
 				WFIFOL(map_fd,12) = (unsigned long)0; //TODO: expiration_time, how do I figure it out right now?
 				memcpy(WFIFOP(map_fd,20), char_data, sizeof(struct mmo_charstatus));
 				WFIFOSET(map_fd, WFIFOW(map_fd,2));
+#endif
+
+				// create temporary auth entry
+				CREATE(node, struct auth_node, 1);
+				node->account_id = RFIFOL(fd,2);
+				node->char_id = RFIFOL(fd,14);
+				node->login_id1 = RFIFOL(fd,6);
+				node->login_id2 = RFIFOL(fd,10);
+				node->sex = RFIFOB(fd,30);
+				node->expiration_time = 0; // FIXME
+				node->ip = ntohl(RFIFOL(fd,31));
+				idb_put(auth_db, RFIFOL(fd,2), node);
 
 				data = (struct online_char_data*)idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
 				data->char_id = char_data->char_id;
@@ -2852,6 +2868,69 @@ int parse_frommap(int fd)
 			RFIFOSKIP(fd,2);
 		break;
 
+		case 0x2b26: // auth request from map-server
+			if (RFIFOREST(fd) < 19)
+				return 0;
+
+		{
+			int account_id;
+			int char_id;
+			int login_id1;
+			char sex;
+			uint32 ip;
+			struct auth_node* node;
+			struct mmo_charstatus* cd;
+			struct mmo_charstatus char_dat;
+
+			account_id = RFIFOL(fd,2);
+			char_id    = RFIFOL(fd,6);
+			login_id1  = RFIFOL(fd,10);
+			sex        = RFIFOB(fd,14);
+			ip         = ntohl(RFIFOL(fd,15));
+			RFIFOSKIP(fd,19);
+
+			node = (struct auth_node*)idb_get(auth_db, account_id);
+			cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
+			if( cd == NULL )
+			{	//Really shouldn't happen.
+				mmo_char_fromsql(char_id, &char_dat, true);
+				cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
+			}
+			if( node != NULL && cd != NULL &&
+				node->account_id == account_id &&
+				node->char_id == char_id &&
+				node->login_id1 == login_id1 &&
+				node->sex == sex &&
+				node->ip == ip )
+			{// auth ok
+				WFIFOHEAD(fd,20 + sizeof(struct mmo_charstatus));
+				WFIFOW(fd,0) = 0x2afd;
+				WFIFOW(fd,2) = 20 + sizeof(struct mmo_charstatus);
+				WFIFOL(fd,4) = account_id;
+				WFIFOL(fd,8) = login_id1;
+				WFIFOL(fd,12) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
+				WFIFOL(fd,16) = node->login_id2;
+				memcpy(WFIFOP(fd,20), cd, sizeof(struct mmo_charstatus));
+				WFIFOSET(fd, WFIFOW(fd,2));
+
+				// only use the auth once and mark user online
+				idb_remove(auth_db, account_id);
+				set_char_online(id, account_id, char_id);
+			}
+			else
+			{// auth failed
+				WFIFOHEAD(fd,19);
+				WFIFOW(fd,0) = 0x2b27;
+				WFIFOL(fd,2) = account_id;
+				WFIFOL(fd,6) = char_id;
+				WFIFOL(fd,10) = login_id1;
+				WFIFOB(fd,14) = sex;
+				WFIFOL(fd,15) = htonl(ip);
+				WFIFOSET(fd,19);
+			}
+		}
+		break;
+
 		case 0x2736: // ip address update
 			if (RFIFOREST(fd) < 6) return 0;
 			server[id].ip = ntohl(RFIFOL(fd, 2));
@@ -3139,6 +3218,8 @@ int parse_char(int fd)
 			WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
 			WFIFOSET(fd,28);
 
+#if 0
+			// The server must request it [FlavioJS]
 			//Send auth ok to map server
 			WFIFOHEAD(map_fd,20 + sizeof(struct mmo_charstatus));
 			WFIFOW(map_fd,0) = 0x2afd;
@@ -3149,6 +3230,7 @@ int parse_char(int fd)
 			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));
+#endif
 
 			// create temporary auth entry
 			CREATE(node, struct auth_node, 1);

+ 61 - 13
src/map/chrif.c

@@ -37,7 +37,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
 	 6,30,-1,-1,86, 7,44,34,	// 2b08-2b0f: U->2b08, U->2b09, F->2b0a, F->2b0b, U->2b0c, U->2b0d, U->2b0e, U->2b0f
 	11,10,10, 6,11,-1,266,10,	// 2b10-2b17: U->2b10, U->2b11, U->2b12, U->2b13, U->2b14, U->2b15, U->2b16, U->2b17
 	 2,10, 2,-1,-1,-1, 2, 7,	// 2b18-2b1f: U->2b18, U->2b19, U->2b1a, U->2b1b, U->2b1c, U->2b1d, U->2b1e, U->2b1f
-	-1,10, 8, 2, 2,14,-1,-1,	// 2b20-2b27: U->2b20, U->2b21, U->2b22, U->2b23, U->2b24, U->2b25, F->2b26, F->2b27
+	-1,10, 8, 2, 2,14,19,19,	// 2b20-2b27: U->2b20, U->2b21, U->2b22, U->2b23, U->2b24, U->2b25, F->2b26, F->2b27
 };
 
 //Used Packets:
@@ -46,7 +46,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
 //2afa: Outgoing, chrif_sendmap -> 'sending our maps'
 //2afb: Incoming, chrif_sendmapack -> 'Maps received successfully / or not ..'
 //2afc: Outgoing, chrif_scdata_request -> request sc_data for pc_authok'ed char. <- new command reuses previous one.
-//2afd: Incoming, chrif_authok -> 'character selected, add to auth db'
+//2afd: Incoming, chrif_authok -> 'client authentication ok'
 //2afe: Outgoing, send_usercount_tochar -> 'sends player count of this map server to charserver'
 //2aff: Outgoing, send_users_tochar -> 'sends all actual connected character ids to charserver'
 //2b00: Incoming, map_setusers -> 'set the actual usercount? PACKET.2B COUNT.L.. ?' (not sure)
@@ -87,8 +87,8 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
 //2b23: Outgoing, chrif_keepalive. charserver ping.
 //2b24: Incoming, chrif_keepalive_ack. charserver ping reply.
 //2b25: Incoming, chrif_deadopt -> 'Removes baby from Father ID and Mother ID'
-//2b26: FREE
-//2b27: FREE
+//2b26: Outgoing, chrif_authreq -> 'client authentication request'
+//2b27: Incoming, chrif_authfail -> 'client authentication failed'
 
 int chrif_connected = 0;
 int char_fd = 0; //Using 0 instead of -1 is safer against crashes. [Skotlex]
@@ -384,7 +384,7 @@ int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port)
 	WFIFOL(char_fd,24) = htonl(ip);
 	WFIFOW(char_fd,28) = htons(port);
 	WFIFOB(char_fd,30) = sd->status.sex;
-	WFIFOL(char_fd,31) = 0; // sd's IP, not used anymore
+	WFIFOL(char_fd,31) = htonl(session[sd->fd]->client_addr);
 	WFIFOSET(char_fd,35);
 	return 0;
 }
@@ -517,6 +517,14 @@ void chrif_authreq(struct map_session_data *sd)
 
 	if(!node) {
 		//data from char server has not arrived yet.
+		WFIFOHEAD(char_fd,19);
+		WFIFOW(char_fd,0) = 0x2b26;
+		WFIFOL(char_fd,2) = sd->status.account_id;
+		WFIFOL(char_fd,6) = sd->status.char_id;
+		WFIFOL(char_fd,10) = sd->login_id1;
+		WFIFOB(char_fd,14) = sd->status.sex;
+		WFIFOL(char_fd,15) = htonl(session[sd->fd]->client_addr);
+		WFIFOSET(char_fd,19);
 		chrif_sd_to_auth(sd, ST_LOGIN);
 		return;
 	}
@@ -550,10 +558,13 @@ void chrif_authreq(struct map_session_data *sd)
 //character selected, insert into auth db
 void chrif_authok(int fd)
 {
+	int account_id;
+	uint32 login_id1;
+	time_t expiration_time;
+	uint32 login_id2;
+	struct mmo_charstatus* status;
+	int char_id;
 	struct auth_node *node;
-	int account_id = RFIFOL(fd, 4);
-	struct mmo_charstatus *status = (struct mmo_charstatus *)RFIFOP(fd, 20);
-	int char_id = status->char_id;
 	TBL_PC* sd;
 
 	//Check if both servers agree on the struct's size
@@ -563,6 +574,13 @@ void chrif_authok(int fd)
 		return;
 	}
 
+	account_id = RFIFOL(fd,4);
+	login_id1 = RFIFOL(fd,8);
+	expiration_time = (time_t)(int32)RFIFOL(fd,12);
+	login_id2 = RFIFOL(fd,16);
+	status = (struct mmo_charstatus*)RFIFOP(fd,20);
+	char_id = status->char_id;
+
 	//Check if we don't already have player data in our server
 	//Causes problems if the currently connected player tries to quit or this data belongs to an already connected player which is trying to re-auth.
 	if ((sd = map_id2sd(account_id)) != NULL)
@@ -578,9 +596,9 @@ void chrif_authok(int fd)
 			if(node->char_dat == NULL &&
 				node->account_id == account_id &&
 				node->char_id == char_id &&
-				node->login_id1 == RFIFOL(fd, 8))
+				node->login_id1 == login_id1 )
 			{ //Auth Ok
-				if (pc_authok(sd, RFIFOL(fd, 16), RFIFOL(fd, 12), status))
+				if (pc_authok(sd, login_id2, expiration_time, status))
 				{
 					chrif_char_online(sd);
 					return;
@@ -604,14 +622,43 @@ void chrif_authok(int fd)
 
 	node->account_id=account_id;
 	node->char_id=char_id;
-	node->login_id1=RFIFOL(fd, 8);
-	node->expiration_time=RFIFOL(fd, 12);
-	node->login_id2=RFIFOL(fd, 16);
+	node->login_id1=login_id1;
+	node->expiration_time=expiration_time;
+	node->login_id2=login_id2;
 	memcpy(node->char_dat,status,sizeof(struct mmo_charstatus));
 	node->node_created=gettick();
 	idb_put(auth_db, account_id, node);
 }
 
+// client authentication failed
+void chrif_authfail(int fd)
+{
+	int account_id;
+	int char_id;
+	uint32 login_id1;
+	char sex;
+	uint32 ip;
+	struct auth_node* node;
+
+	account_id = RFIFOL(fd,2);
+	char_id    = RFIFOL(fd,6);
+	login_id1  = RFIFOL(fd,10);
+	sex        = RFIFOB(fd,14);
+	ip         = ntohl(RFIFOL(fd,15));
+
+	node = chrif_search(account_id);
+	if( node != NULL &&
+		node->account_id == account_id &&
+		node->char_id == char_id &&
+		node->login_id1 == login_id1 &&
+		node->sex == sex &&
+		node->state == ST_LOGIN )
+	{// found a match
+		clif_authfail_fd(node->fd, 0);
+		chrif_auth_delete(account_id, char_id, ST_LOGIN);
+	}
+}
+
 int auth_db_cleanup_sub(DBKey key,void *data,va_list ap)
 {
 	struct auth_node *node=(struct auth_node*)data;
@@ -1443,6 +1490,7 @@ int chrif_parse(int fd)
 		case 0x2b22: chrif_updatefamelist_ack(fd); break;
 		case 0x2b24: chrif_keepalive_ack(fd); break;
 		case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
+		case 0x2b27: chrif_authfail(fd); break;
 		default:
 			ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd);
 			set_eof(fd);