static int chrif_reconnect(DBKey key,void *data,va_list ap) { struct auth_node *node=(struct auth_node*)data; switch (node->state) { case ST_LOGIN: if (node->sd && node->char_dat == NULL) { //Since there is no way to request the char auth, make it fail. pc_authfail(node->sd); chrif_char_offline_nsd(node->account_id, node->char_id); chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); } break; case ST_LOGOUT: //Re-send final save chrif_save(node->sd, 1); break; case ST_MAPCHANGE: { //Re-send map-change request. struct map_session_data *sd = node->sd; uint32 ip; uint16 port; if(map_mapname2ipport(sd->mapindex,&ip,&port)==0) chrif_changemapserver(sd, ip, port); else //too much lag/timeout is the closest explanation for this error. clif_authfail_fd(sd->fd, 3); break; } } return 0; }
/*========================================== * new auth system [Kevin] *------------------------------------------*/ void chrif_authreq(struct map_session_data *sd) { struct auth_node *node= chrif_search(sd->bl.id); if(!node) { //data from char server has not arrived yet. chrif_sd_to_auth(sd, ST_LOGIN); return; } if(node->state == ST_LOGIN && node->char_dat && node->account_id == sd->status.account_id && node->char_id == sd->status.char_id && node->login_id1 == sd->login_id1) { //auth ok if (!pc_authok(sd, node->login_id2, node->connect_until_time, node->char_dat)) { chrif_char_offline(sd); //Set client offline chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); } else { //char_dat no longer needed, but player auth is not completed yet. aFree(node->char_dat); node->char_dat = NULL; node->sd = sd; chrif_char_online(sd); //Set client online } } else { //auth failed pc_authfail(sd); chrif_char_offline(sd); //Set client offline chrif_auth_delete(sd->status.account_id, sd->status.char_id, ST_LOGIN); } return; }
/*========================================== * マップ鯖間移動ack *------------------------------------------ */ static int chrif_changemapserverack(Session *, const Packet_Fixed<0x2b06>& fixed) { dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(fixed.account_id)); if (sd == nullptr || sd->status_key.char_id != fixed.char_id) return -1; // I am fairly certain that this is not possible if (fixed.error == 1) { if (battle_config.error_log) PRINTF("map server change failed.\n"_fmt); pc_authfail(sd->status_key.account_id); return 0; } MapName mapname = fixed.map_name; uint16_t x = fixed.x; uint16_t y = fixed.y; IP4Address ip = fixed.map_ip; uint16_t port = fixed.map_port; clif_changemapserver(sd, mapname, x, y, ip, port); return 0; }
/*========================================== * new auth system [Kevin] *------------------------------------------*/ void chrif_authreq(struct map_session_data *sd) { struct auth_node *auth_data; auth_data=idb_get(auth_db, sd->bl.id); if(auth_data) { if(auth_data->char_dat && auth_data->account_id== sd->bl.id && auth_data->login_id1 == sd->login_id1) { //auth ok pc_authok(sd, auth_data->login_id2, auth_data->connect_until_time, auth_data->char_dat); } else { //auth failed pc_authfail(sd); chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. } if (auth_data->char_dat) aFree(auth_data->char_dat); idb_remove(auth_db, sd->bl.id); } else { //data from char server has not arrived yet. auth_data = aCalloc(1,sizeof(struct auth_node)); auth_data->sd = sd; auth_data->fd = sd->fd; auth_data->account_id = sd->bl.id; auth_data->login_id1 = sd->login_id1; auth_data->node_created = gettick(); uidb_put(auth_db, sd->bl.id, auth_data); } return; }
//character selected, insert into auth db void chrif_authok(int fd) { struct auth_node *auth_data; TBL_PC* sd; //Check if we don't already have player data in our server //(prevents data that is to be saved from being overwritten by //this received status data if this auth is later successful) [Skotlex] if ((sd = map_id2sd(RFIFOL(fd, 4))) != NULL) { struct mmo_charstatus *status = (struct mmo_charstatus *)RFIFOP(fd, 20); //Auth check is because this could be the very same sd that is waiting char-server authorization. if (sd->state.auth && sd->status.char_id == status->char_id) return; } if ((auth_data =uidb_get(auth_db, RFIFOL(fd, 4))) != NULL) { //Is the character already awaiting authorization? if (auth_data->sd) { //First, check to see if the session data still exists (avoid dangling pointers) if(session[auth_data->fd] && session[auth_data->fd]->session_data == auth_data->sd) { if (auth_data->char_dat == NULL && auth_data->account_id == RFIFOL(fd, 4) && auth_data->login_id1 == RFIFOL(fd, 8)) { //Auth Ok pc_authok(auth_data->sd, RFIFOL(fd, 16), RFIFOL(fd, 12), (struct mmo_charstatus*)RFIFOP(fd, 20)); } else { //Auth Failed pc_authfail(auth_data->sd); chrif_char_offline(auth_data->sd); //Set him offline, the char server likely has it set as online already. } } //else: Character no longer exists, just go through. } //Delete the data of this node... if (auth_data->char_dat) aFree (auth_data->char_dat); uidb_remove(auth_db, RFIFOL(fd, 4)); return; } // Awaiting for client to connect. auth_data = (struct auth_node *)aCalloc(1,sizeof(struct auth_node)); auth_data->char_dat = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus)); auth_data->account_id=RFIFOL(fd, 4); auth_data->login_id1=RFIFOL(fd, 8); auth_data->connect_until_time=RFIFOL(fd, 12); auth_data->login_id2=RFIFOL(fd, 16); memcpy(auth_data->char_dat,RFIFOP(fd, 20),sizeof(struct mmo_charstatus)); auth_data->node_created=gettick(); uidb_put(auth_db, RFIFOL(fd, 4), auth_data); }
//character selected, insert into auth db void chrif_authok(int fd) { 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 if( RFIFOW(fd,2) - 20 != sizeof(struct mmo_charstatus) ) { ShowError("chrif_authok: Data size mismatch! %d != %d\n", RFIFOW(fd,2) - 20, sizeof(struct mmo_charstatus)); return; } //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) return; if ((node = chrif_search(account_id))) { //Is the character already awaiting authorization? if (node->state != ST_LOGIN) return; //character in logout phase, do not touch that data. if (node->sd) { sd = node->sd; if(node->char_dat == NULL && node->account_id == account_id && node->char_id == char_id && node->login_id1 == RFIFOL(fd, 8)) { //Auth Ok if (pc_authok(sd, RFIFOL(fd, 16), RFIFOL(fd, 12), status)) { chrif_char_online(sd); return; } } else { //Auth Failed pc_authfail(sd); } chrif_char_offline(sd); //Set client offline chrif_auth_delete(account_id, char_id, ST_LOGIN); return; } //When we receive double login info and the client has not connected yet, //discard the older one and keep the new one. chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); } // Awaiting for client to connect. node = ers_alloc(auth_db_ers, struct auth_node); memset(node, 0, sizeof(struct auth_node)); node->char_dat = (struct mmo_charstatus *) aMalloc(sizeof(struct mmo_charstatus)); node->account_id=account_id; node->char_id=char_id; node->login_id1=RFIFOL(fd, 8); node->connect_until_time=RFIFOL(fd, 12); node->login_id2=RFIFOL(fd, 16); memcpy(node->char_dat,status,sizeof(struct mmo_charstatus)); node->node_created=gettick(); idb_put(auth_db, account_id, node); }
/*========================================== * Auth confirmation ack *------------------------------------------*/ void chrif_authok(int fd) { int account_id, group_id, char_id; uint32 login_id1,login_id2; time_t expiration_time; struct mmo_charstatus* status; struct auth_node *node; bool changing_mapservers; TBL_PC* sd; //Check if both servers agree on the struct's size if( RFIFOW(fd,2) - 25 != sizeof(struct mmo_charstatus) ) { ShowError("chrif_authok: Data size mismatch! %d != %d\n", RFIFOW(fd,2) - 25, sizeof(struct mmo_charstatus)); return; } account_id = RFIFOL(fd,4); login_id1 = RFIFOL(fd,8); login_id2 = RFIFOL(fd,12); expiration_time = (time_t)(int32)RFIFOL(fd,16); group_id = RFIFOL(fd,20); changing_mapservers = (RFIFOB(fd,24)); status = (struct mmo_charstatus*)RFIFOP(fd,25); 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 ) return; if ( ( node = chrif_search(account_id) ) == NULL ) return; // should not happen if ( node->state != ST_LOGIN ) return; //character in logout phase, do not touch that data. if ( node->sd == NULL ) { /* //When we receive double login info and the client has not connected yet, //discard the older one and keep the new one. chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); */ return; // should not happen } sd = node->sd; if( runflag == MAPSERVER_ST_RUNNING && node->char_dat == NULL && node->account_id == account_id && node->char_id == char_id && node->login_id1 == login_id1 ) { //Auth Ok if (pc_authok(sd, login_id2, expiration_time, group_id, status, changing_mapservers)) return; } else { //Auth Failed pc_authfail(sd); } chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. chrif_auth_delete(account_id, char_id, ST_LOGIN); }
/*========================================== * *------------------------------------------ */ static void chrif_parse(Session *s) { assert (s == char_session); RecvResult rv = RecvResult::Complete; uint16_t packet_id; while (rv == RecvResult::Complete && packet_peek_id(s, &packet_id)) { switch (packet_id) { case 0x2af9: { Packet_Fixed<0x2af9> fixed; rv = recv_fpacket<0x2af9, 3>(s, fixed); if (rv != RecvResult::Complete) break; chrif_connectack(s, fixed); break; } case 0x2afa: { Packet_Fixed<0x2afa> fixed; rv = recv_fpacket<0x2afa, 10>(s, fixed); if (rv != RecvResult::Complete) break; ladmin_itemfrob(s, fixed); break; } case 0x2afb: { Packet_Fixed<0x2afb> fixed; rv = recv_fpacket<0x2afb, 27>(s, fixed); if (rv != RecvResult::Complete) break; chrif_sendmapack(s, fixed); break; } case 0x2afd: { Packet_Payload<0x2afd> payload; rv = recv_ppacket<0x2afd>(s, payload); if (rv != RecvResult::Complete) break; AccountId id = payload.account_id; int login_id2 = payload.login_id2; TimeT connect_until_time = payload.connect_until; short tmw_version = payload.packet_tmw_version; CharKey st_key = payload.char_key; CharData st_data = payload.char_data; pc_authok(id, login_id2, connect_until_time, tmw_version, &st_key, &st_data); break; } case 0x2afe: { Packet_Fixed<0x2afe> fixed; rv = recv_fpacket<0x2afe, 6>(s, fixed); if (rv != RecvResult::Complete) break; pc_authfail(fixed.account_id); break; } case 0x2b00: { Packet_Fixed<0x2b00> fixed; rv = recv_fpacket<0x2b00, 6>(s, fixed); if (rv != RecvResult::Complete) break; map_setusers(fixed.users); break; } case 0x2b03: { Packet_Fixed<0x2b03> fixed; rv = recv_fpacket<0x2b03, 7>(s, fixed); if (rv != RecvResult::Complete) break; clif_charselectok(account_to_block(fixed.account_id)); break; } case 0x2b04: { Packet_Head<0x2b04> head; std::vector<Packet_Repeat<0x2b04>> repeat; rv = recv_vpacket<0x2b04, 10, 16>(s, head, repeat); if (rv != RecvResult::Complete) break; chrif_recvmap(s, head, repeat); break; } case 0x2b06: { Packet_Fixed<0x2b06> fixed; rv = recv_fpacket<0x2b06, 44>(s, fixed); if (rv != RecvResult::Complete) break; chrif_changemapserverack(s, fixed); break; } case 0x2b0b: { Packet_Fixed<0x2b0b> fixed; rv = recv_fpacket<0x2b0b, 10>(s, fixed); if (rv != RecvResult::Complete) break; chrif_changedgm(s, fixed); break; } case 0x2b0d: { Packet_Fixed<0x2b0d> fixed; rv = recv_fpacket<0x2b0d, 7>(s, fixed); if (rv != RecvResult::Complete) break; chrif_changedsex(s, fixed); break; } case 0x2b0f: { Packet_Fixed<0x2b0f> fixed; rv = recv_fpacket<0x2b0f, 34>(s, fixed); if (rv != RecvResult::Complete) break; chrif_char_ask_name_answer(s, fixed); break; } case 0x2b11: { Packet_Head<0x2b11> head; std::vector<Packet_Repeat<0x2b11>> repeat; rv = recv_vpacket<0x2b11, 8, 36>(s, head, repeat); if (rv != RecvResult::Complete) break; chrif_accountreg2(s, head, repeat); break; } case 0x2b12: { Packet_Fixed<0x2b12> fixed; rv = recv_fpacket<0x2b12, 10>(s, fixed); if (rv != RecvResult::Complete) break; chrif_divorce(fixed.char_id, fixed.partner_id); break; } case 0x2b13: { Packet_Fixed<0x2b13> fixed; rv = recv_fpacket<0x2b13, 6>(s, fixed); if (rv != RecvResult::Complete) break; chrif_accountdeletion(s, fixed); break; } case 0x2b14: { Packet_Fixed<0x2b14> fixed; rv = recv_fpacket<0x2b14, 11>(s, fixed); if (rv != RecvResult::Complete) break; chrif_accountban(s, fixed); break; } case 0x2b15: { std::vector<Packet_Repeat<0x2b15>> repeat; rv = recv_packet_repeatonly<0x2b15, 4, 5>(s, repeat); if (rv != RecvResult::Complete) break; chrif_recvgmaccounts(s, repeat); break; } default: { RecvResult r = intif_parse(s, packet_id); if (r == RecvResult::Complete) break; if (r == RecvResult::Incomplete) return; if (battle_config.error_log) PRINTF("chrif_parse : unknown packet %d %d\n"_fmt, s, packet_id); s->set_eof(); return; } } } if (rv == RecvResult::Error) s->set_eof(); }