loginchrif.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "loginchrif.hpp"
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "../common/showmsg.hpp" //show notice
  7. #include "../common/socket.hpp" //wfifo session
  8. #include "../common/strlib.hpp" //safeprint
  9. #include "../common/timer.hpp" //difftick
  10. #include "account.hpp"
  11. #include "login.hpp"
  12. #include "loginlog.hpp"
  13. //early declaration
  14. void logchrif_on_disconnect(int id);
  15. /**
  16. * Packet send to all char-servers, except one. (wos: without our self)
  17. * @param sfd: fd to discard sending to
  18. * @param buf: packet to send in form of an array buffer
  19. * @param len: size of packet
  20. * @return : the number of char-serv the packet was sent to
  21. */
  22. int logchrif_sendallwos(int sfd, uint8* buf, size_t len) {
  23. int i, c;
  24. for( i = 0, c = 0; i < ARRAYLENGTH(ch_server); ++i ) {
  25. int fd = ch_server[i].fd;
  26. if( session_isValid(fd) && fd != sfd ){
  27. WFIFOHEAD(fd,len);
  28. memcpy(WFIFOP(fd,0), buf, len);
  29. WFIFOSET(fd,len);
  30. ++c;
  31. }
  32. }
  33. return c;
  34. }
  35. /**
  36. * Timered function to synchronize ip addresses.
  37. * Requesting all char to update their registered ip and transmit their new ip.
  38. * Performed each ip_sync_interval.
  39. * @param tid: timer id
  40. * @param tick: tick of execution
  41. * @param id: unused
  42. * @param data: unused
  43. * @return 0
  44. */
  45. TIMER_FUNC(logchrif_sync_ip_addresses){
  46. uint8 buf[2];
  47. ShowInfo("IP Sync in progress...\n");
  48. WBUFW(buf,0) = 0x2735;
  49. logchrif_sendallwos(-1, buf, 2);
  50. return 0;
  51. }
  52. /// Parsing handlers
  53. /**
  54. * Request from char-server to authenticate an account.
  55. * @param fd: fd to parse from (char-serv)
  56. * @param id: id of char-serv
  57. * @param ip: char-serv ip (used for info)
  58. * @return 0 not enough info transmitted, 1 success
  59. */
  60. int logchrif_parse_reqauth(int fd, int id,char* ip){
  61. if( RFIFOREST(fd) < 23 )
  62. return 0;
  63. else{
  64. uint32 account_id = RFIFOL(fd,2);
  65. uint32 login_id1 = RFIFOL(fd,6);
  66. uint32 login_id2 = RFIFOL(fd,10);
  67. uint8 sex = RFIFOB(fd,14);
  68. //uint32 ip_ = ntohl(RFIFOL(fd,15));
  69. int request_id = RFIFOL(fd,19);
  70. RFIFOSKIP(fd,23);
  71. struct auth_node* node = login_get_auth_node( account_id );
  72. if( runflag == LOGINSERVER_ST_RUNNING &&
  73. node != nullptr &&
  74. node->account_id == account_id &&
  75. node->login_id1 == login_id1 &&
  76. node->login_id2 == login_id2 &&
  77. node->sex == sex_num2str(sex) /*&&
  78. node->ip == ip_*/ ){// found
  79. //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip);
  80. // send ack
  81. WFIFOHEAD(fd,21);
  82. WFIFOW(fd,0) = 0x2713;
  83. WFIFOL(fd,2) = account_id;
  84. WFIFOL(fd,6) = login_id1;
  85. WFIFOL(fd,10) = login_id2;
  86. WFIFOB(fd,14) = sex;
  87. WFIFOB(fd,15) = 0;// ok
  88. WFIFOL(fd,16) = request_id;
  89. WFIFOB(fd,20) = node->clienttype;
  90. WFIFOSET(fd,21);
  91. // each auth entry can only be used once
  92. login_remove_auth_node( account_id );
  93. }else{// authentication not found
  94. ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", ch_server[id].name, account_id, ip);
  95. WFIFOHEAD(fd,21);
  96. WFIFOW(fd,0) = 0x2713;
  97. WFIFOL(fd,2) = account_id;
  98. WFIFOL(fd,6) = login_id1;
  99. WFIFOL(fd,10) = login_id2;
  100. WFIFOB(fd,14) = sex;
  101. WFIFOB(fd,15) = 1;// auth failed
  102. WFIFOL(fd,16) = request_id;
  103. WFIFOB(fd,20) = 0;
  104. WFIFOSET(fd,21);
  105. }
  106. }
  107. return 1;
  108. }
  109. /**
  110. * Receive a request to update user count for char-server identified by id.
  111. * @param fd: fd to parse from (char-serv)
  112. * @param id: id of char-serv
  113. * @return 0 not enough info transmitted, 1 success
  114. */
  115. int logchrif_parse_ackusercount(int fd, int id){
  116. if( RFIFOREST(fd) < 6 )
  117. return 0;
  118. else{
  119. int users = RFIFOL(fd,2);
  120. RFIFOSKIP(fd,6);
  121. // how many users on world? (update)
  122. if( ch_server[id].users != users ){
  123. ShowStatus("set users %s : %d\n", ch_server[id].name, users);
  124. ch_server[id].users = users;
  125. }
  126. }
  127. return 1;
  128. }
  129. /**
  130. * Transmit account data to char_server
  131. * S 2717 aid.W email.40B exp_time.L group_id.B char_slot.B birthdate.11B pincode.5B pincode_change.L
  132. * isvip.1B char_vip.1B max_billing.1B (tot 75)
  133. * @return -1 : account not found, 1:sucess
  134. */
  135. int logchrif_send_accdata(int fd, uint32 aid) {
  136. struct mmo_account acc;
  137. time_t expiration_time = 0;
  138. char email[40] = "";
  139. int group_id = 0;
  140. char birthdate[10+1] = "";
  141. char pincode[PINCODE_LENGTH+1];
  142. char isvip = false;
  143. uint8 char_slots = MIN_CHARS, char_vip = 0, char_billing = 0;
  144. AccountDB* accounts = login_get_accounts_db();
  145. memset(pincode,0,PINCODE_LENGTH+1);
  146. if( !accounts->load_num(accounts, &acc, aid) )
  147. return -1;
  148. else {
  149. safestrncpy(email, acc.email, sizeof(email));
  150. expiration_time = acc.expiration_time;
  151. group_id = acc.group_id;
  152. safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
  153. safestrncpy(pincode, acc.pincode, sizeof(pincode));
  154. #ifdef VIP_ENABLE
  155. char_vip = login_config.vip_sys.char_increase;
  156. if( acc.vip_time > time(NULL) ) {
  157. isvip = true;
  158. char_slots = login_config.char_per_account + char_vip;
  159. } else
  160. char_slots = login_config.char_per_account;
  161. char_billing = MAX_CHAR_BILLING; //TODO create a config for this
  162. #endif
  163. }
  164. WFIFOHEAD(fd,75);
  165. WFIFOW(fd,0) = 0x2717;
  166. WFIFOL(fd,2) = aid;
  167. safestrncpy(WFIFOCP(fd,6), email, 40);
  168. WFIFOL(fd,46) = (uint32)expiration_time;
  169. WFIFOB(fd,50) = (unsigned char)group_id;
  170. WFIFOB(fd,51) = char_slots;
  171. safestrncpy(WFIFOCP(fd,52), birthdate, 10+1);
  172. safestrncpy(WFIFOCP(fd,63), pincode, 4+1 );
  173. WFIFOL(fd,68) = (uint32)acc.pincode_change;
  174. WFIFOB(fd,72) = isvip;
  175. WFIFOB(fd,73) = char_vip;
  176. WFIFOB(fd,74) = char_billing;
  177. WFIFOSET(fd,75);
  178. return 1;
  179. }
  180. /**
  181. * Transmit vip specific data to char-serv (will be transfered to mapserv)
  182. * @param fd
  183. * @param acc
  184. * @param flag 0x1: VIP, 0x2: GM, 0x4: Show rates on player
  185. * @param mapfd
  186. */
  187. int logchrif_sendvipdata(int fd, struct mmo_account* acc, unsigned char flag, int mapfd) {
  188. #ifdef VIP_ENABLE
  189. WFIFOHEAD(fd,19);
  190. WFIFOW(fd,0) = 0x2743;
  191. WFIFOL(fd,2) = acc->account_id;
  192. WFIFOL(fd,6) = (int)acc->vip_time;
  193. WFIFOB(fd,10) = flag;
  194. WFIFOL(fd,11) = acc->group_id; //new group id
  195. WFIFOL(fd,15) = mapfd; //link to mapserv
  196. WFIFOSET(fd,19);
  197. logchrif_send_accdata(fd,acc->account_id); //refresh char with new setting
  198. #endif
  199. return 1;
  200. }
  201. /**
  202. * Receive a request for account data reply by sending all mmo_account information.
  203. * @param fd: fd to parse from (char-serv)
  204. * @param id: id of char-serv
  205. * @param ip: char-serv ip (used for info)
  206. * @return 0 not enough info transmitted, 1 success
  207. */
  208. int logchrif_parse_reqaccdata(int fd, int id, char *ip){
  209. if( RFIFOREST(fd) < 6 )
  210. return 0;
  211. else {
  212. uint32 aid = RFIFOL(fd,2);
  213. RFIFOSKIP(fd,6);
  214. if( logchrif_send_accdata(fd,aid) < 0 )
  215. ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", ch_server[id].name, aid, ip);
  216. }
  217. return 1;
  218. }
  219. /**
  220. * Ping request from char-server to send a reply.
  221. * @param fd: fd to parse from (char-serv)
  222. * @return 1 success
  223. */
  224. int logchrif_parse_keepalive(int fd){
  225. RFIFOSKIP(fd,2);
  226. WFIFOHEAD(fd,2);
  227. WFIFOW(fd,0) = 0x2718;
  228. WFIFOSET(fd,2);
  229. return 1;
  230. }
  231. /**
  232. * Map server send information to change an email of an account via char-server.
  233. * 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  234. * @param fd: fd to parse from (char-serv)
  235. * @param id: id of char-serv
  236. * @param ip: char-serv ip (used for info)
  237. * @return 0 not enough info transmitted, 1 success
  238. */
  239. int logchrif_parse_reqchangemail(int fd, int id, char* ip){
  240. if (RFIFOREST(fd) < 86)
  241. return 0;
  242. else{
  243. struct mmo_account acc;
  244. AccountDB* accounts = login_get_accounts_db();
  245. char actual_email[40];
  246. char new_email[40];
  247. uint32 account_id = RFIFOL(fd,2);
  248. safestrncpy(actual_email, RFIFOCP(fd,6), 40);
  249. safestrncpy(new_email, RFIFOCP(fd,46), 40);
  250. RFIFOSKIP(fd, 86);
  251. if( e_mail_check(actual_email) == 0 )
  252. ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", ch_server[id].name, account_id, ip);
  253. else if( e_mail_check(new_email) == 0 )
  254. ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", ch_server[id].name, account_id, ip);
  255. else if( strcmpi(new_email, "a@a.com") == 0 )
  256. ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", ch_server[id].name, account_id, ip);
  257. else if( !accounts->load_num(accounts, &acc, account_id) )
  258. ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", ch_server[id].name, account_id, ip);
  259. else if( strcmpi(acc.email, actual_email) != 0 )
  260. ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", ch_server[id].name, account_id, acc.userid, acc.email, actual_email, ip);
  261. else{
  262. safestrncpy(acc.email, new_email, 40);
  263. ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", ch_server[id].name, account_id, acc.userid, new_email, ip);
  264. // Save
  265. accounts->save(accounts, &acc);
  266. }
  267. }
  268. return 1;
  269. }
  270. /**
  271. * Receiving an account state update request from a map-server (relayed via char-server).
  272. * @param fd: fd to parse from (char-serv)
  273. * @param id: id of char-serv
  274. * @param ip: char-serv ip (used for info)
  275. * @return 0 not enough info transmitted, 1 success
  276. * TODO seems pretty damn close to logchrif_parse_reqbanacc
  277. */
  278. int logchrif_parse_requpdaccstate(int fd, int id, char* ip){
  279. if (RFIFOREST(fd) < 10)
  280. return 0;
  281. else{
  282. struct mmo_account acc;
  283. uint32 account_id = RFIFOL(fd,2);
  284. unsigned int state = RFIFOL(fd,6);
  285. AccountDB* accounts = login_get_accounts_db();
  286. RFIFOSKIP(fd,10);
  287. if( !accounts->load_num(accounts, &acc, account_id) )
  288. ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", ch_server[id].name, account_id, state, ip);
  289. else if( acc.state == state )
  290. ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", ch_server[id].name, account_id, state, ip);
  291. else{
  292. ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", ch_server[id].name, account_id, state, ip);
  293. acc.state = state;
  294. // Save
  295. accounts->save(accounts, &acc);
  296. // notify other servers
  297. if (state != 0){
  298. uint8 buf[11];
  299. WBUFW(buf,0) = 0x2731;
  300. WBUFL(buf,2) = account_id;
  301. WBUFB(buf,6) = 0; // 0: change of state, 1: ban
  302. WBUFL(buf,7) = state; // status or final date of a banishment
  303. logchrif_sendallwos(-1, buf, 11);
  304. }
  305. }
  306. }
  307. return 1;
  308. }
  309. /**
  310. * Receiving a ban request from map-server via char-server.
  311. * @param fd: fd to parse from (char-serv)
  312. * @param id: id of char-serv
  313. * @param ip: char-serv ip (used for info)
  314. * @return 0 not enough info transmitted, 1 success
  315. * TODO check logchrif_parse_requpdaccstate for possible merge
  316. */
  317. int logchrif_parse_reqbanacc(int fd, int id, char* ip){
  318. if (RFIFOREST(fd) < 10)
  319. return 0;
  320. else{
  321. struct mmo_account acc;
  322. AccountDB* accounts = login_get_accounts_db();
  323. uint32 account_id = RFIFOL(fd,2);
  324. int timediff = RFIFOL(fd,6);
  325. RFIFOSKIP(fd,10);
  326. if( !accounts->load_num(accounts, &acc, account_id) )
  327. ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", ch_server[id].name, account_id, ip);
  328. else{
  329. time_t timestamp;
  330. if (acc.unban_time == 0 || acc.unban_time < time(NULL))
  331. timestamp = time(NULL); // new ban
  332. else
  333. timestamp = acc.unban_time; // add to existing ban
  334. timestamp += timediff;
  335. if (timestamp == -1)
  336. ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", ch_server[id].name, account_id, ip);
  337. else if( timestamp <= time(NULL) || timestamp == 0 )
  338. ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", ch_server[id].name, account_id, ip);
  339. else{
  340. uint8 buf[11];
  341. char tmpstr[24];
  342. timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format);
  343. ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %s, ip: %s).\n", ch_server[id].name, account_id, tmpstr, ip);
  344. acc.unban_time = timestamp;
  345. // Save
  346. accounts->save(accounts, &acc);
  347. WBUFW(buf,0) = 0x2731;
  348. WBUFL(buf,2) = account_id;
  349. WBUFB(buf,6) = 1; // 0: change of status, 1: ban
  350. WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment
  351. logchrif_sendallwos(-1, buf, 11);
  352. }
  353. }
  354. }
  355. return 1;
  356. }
  357. /**
  358. * Receiving a sex change request (sex is reversed).
  359. * @param fd: fd to parse from (char-serv)
  360. * @param id: id of char-serv
  361. * @param ip: char-serv ip (used for info)
  362. * @return 0 not enough info transmitted, 1 success
  363. */
  364. int logchrif_parse_reqchgsex(int fd, int id, char* ip){
  365. if( RFIFOREST(fd) < 6 )
  366. return 0;
  367. else{
  368. struct mmo_account acc;
  369. AccountDB* accounts = login_get_accounts_db();
  370. uint32 account_id = RFIFOL(fd,2);
  371. RFIFOSKIP(fd,6);
  372. if( !accounts->load_num(accounts, &acc, account_id) )
  373. ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", ch_server[id].name, account_id, ip);
  374. else if( acc.sex == 'S' )
  375. ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", ch_server[id].name, account_id, ip);
  376. else{
  377. unsigned char buf[7];
  378. char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender
  379. ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", ch_server[id].name, account_id, sex, ip);
  380. acc.sex = sex;
  381. // Save
  382. accounts->save(accounts, &acc);
  383. // announce to other servers
  384. WBUFW(buf,0) = 0x2723;
  385. WBUFL(buf,2) = account_id;
  386. WBUFB(buf,6) = sex_str2num(sex);
  387. logchrif_sendallwos(-1, buf, 7);
  388. }
  389. }
  390. return 1;
  391. }
  392. /**
  393. * We receive account_reg2 from a char-server, and we send them to other char-servers.
  394. * @param fd: fd to parse from (char-serv)
  395. * @param id: id of char-serv
  396. * @param ip: char-serv ip (used for info)
  397. * @return 0 not enough info transmitted, 1 success
  398. */
  399. int logchrif_parse_upd_global_accreg(int fd, int id, char* ip){
  400. if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) )
  401. return 0;
  402. else{
  403. struct mmo_account acc;
  404. AccountDB* accounts = login_get_accounts_db();
  405. uint32 account_id = RFIFOL(fd,4);
  406. if( !accounts->load_num(accounts, &acc, account_id) )
  407. ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", ch_server[id].name, account_id, ip);
  408. else
  409. mmo_save_global_accreg(accounts,fd,account_id,RFIFOL(fd, 8));
  410. RFIFOSKIP(fd,RFIFOW(fd,2));
  411. }
  412. return 1;
  413. }
  414. /**
  415. * Receiving an unban request from map-server via char-server.
  416. * @param fd: fd to parse from (char-serv)
  417. * @param id: id of char-serv
  418. * @param ip: char-serv ip (used for info)
  419. * @return 0 not enough info transmitted, 1 success
  420. */
  421. int logchrif_parse_requnbanacc(int fd, int id, char* ip){
  422. if( RFIFOREST(fd) < 6 )
  423. return 0;
  424. else{
  425. struct mmo_account acc;
  426. AccountDB* accounts = login_get_accounts_db();
  427. uint32 account_id = RFIFOL(fd,2);
  428. RFIFOSKIP(fd,6);
  429. if( !accounts->load_num(accounts, &acc, account_id) )
  430. ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", ch_server[id].name, account_id, ip);
  431. else if( acc.unban_time == 0 )
  432. ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", ch_server[id].name, account_id, ip);
  433. else{
  434. ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", ch_server[id].name, account_id, ip);
  435. acc.unban_time = 0;
  436. accounts->save(accounts, &acc);
  437. }
  438. }
  439. return 1;
  440. }
  441. /**
  442. * Set account_id to online.
  443. * @author [Wizputer]
  444. * @param fd: fd to parse from (char-serv)
  445. * @param id: id of char-serv
  446. * @return 0 not enough info transmitted, 1 success
  447. */
  448. int logchrif_parse_setacconline(int fd, int id){
  449. if( RFIFOREST(fd) < 6 )
  450. return 0;
  451. login_add_online_user(id, RFIFOL(fd,2));
  452. RFIFOSKIP(fd,6);
  453. return 1;
  454. }
  455. /**
  456. * Set account_id to offline.
  457. * @author [Wizputer]
  458. * @param fd: fd to parse from (char-serv)
  459. * @return 0 not enough info transmitted, 1 success
  460. */
  461. int logchrif_parse_setaccoffline(int fd){
  462. if( RFIFOREST(fd) < 6 )
  463. return 0;
  464. login_remove_online_user(RFIFOL(fd,2));
  465. RFIFOSKIP(fd,6);
  466. return 1;
  467. }
  468. /**
  469. * Receive list of all online accounts.
  470. * @author [Skotlex]
  471. * @param fd: fd to parse from (char-serv)
  472. * @param id: id of char-serv
  473. * @return 0 not enough info transmitted, 1 success
  474. */
  475. int logchrif_parse_updonlinedb(int fd, int id){
  476. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  477. return 0;
  478. else{
  479. //Set all chars from this char-server offline first
  480. login_online_db_setoffline( id );
  481. for( uint32 i = 0, users = RFIFOW(fd, 4); i < users; i++) {
  482. uint32 aid = RFIFOL(fd,6+i*4);
  483. login_add_online_user( id, aid );
  484. }
  485. RFIFOSKIP(fd,RFIFOW(fd,2));
  486. }
  487. return 1;
  488. }
  489. /**
  490. * Request account_reg2 for a character.
  491. * @param fd: fd to parse from (char-serv)
  492. * @return 0 not enough info transmitted, 1 success
  493. */
  494. int logchrif_parse_req_global_accreg(int fd){
  495. if (RFIFOREST(fd) < 10)
  496. return 0;
  497. else{
  498. AccountDB* accounts = login_get_accounts_db();
  499. uint32 account_id = RFIFOL(fd,2);
  500. uint32 char_id = RFIFOL(fd,6);
  501. RFIFOSKIP(fd,10);
  502. mmo_send_global_accreg(accounts,fd,account_id,char_id);
  503. }
  504. return 1;
  505. }
  506. /**
  507. * Received new charip from char-serv, update information.
  508. * @param fd: char-serv file descriptor
  509. * @param id: char-serv id
  510. * @return 0 not enough info transmitted, 1 success
  511. */
  512. int logchrif_parse_updcharip(int fd, int id){
  513. if( RFIFOREST(fd) < 6 )
  514. return 0;
  515. ch_server[id].ip = ntohl(RFIFOL(fd,2));
  516. ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(ch_server[id].ip));
  517. RFIFOSKIP(fd,6);
  518. return 1;
  519. }
  520. /**
  521. * Request to set all accounts offline.
  522. * @param fd: fd to parse from (char-serv)
  523. * @param id: id of char-serv (char-serv)
  524. * @return 1 success
  525. */
  526. int logchrif_parse_setalloffline(int fd, int id){
  527. ShowInfo("Setting accounts from char-server %d offline.\n", id);
  528. login_online_db_setoffline( id );
  529. RFIFOSKIP(fd,2);
  530. return 1;
  531. }
  532. #if PACKETVER_SUPPORTS_PINCODE
  533. /**
  534. * Request to change PIN Code for an account.
  535. * @param fd: fd to parse from (char-serv)
  536. * @return 0 fail (packet does not have enough data), 1 success
  537. */
  538. int logchrif_parse_updpincode(int fd){
  539. if( RFIFOREST(fd) < 8 + PINCODE_LENGTH+1 )
  540. return 0;
  541. else{
  542. struct mmo_account acc;
  543. AccountDB* accounts = login_get_accounts_db();
  544. if( accounts->load_num(accounts, &acc, RFIFOL(fd,4) ) ){
  545. strncpy( acc.pincode, RFIFOCP(fd,8), PINCODE_LENGTH+1 );
  546. acc.pincode_change = time( NULL );
  547. accounts->save(accounts, &acc);
  548. }
  549. RFIFOSKIP(fd,8 + PINCODE_LENGTH+1);
  550. }
  551. return 1;
  552. }
  553. /**
  554. * PIN Code was incorrectly entered too many times.
  555. * @param fd: fd to parse from (char-serv)
  556. * @return 0 fail (packet does not have enough data), 1 success (continue parsing)
  557. */
  558. int logchrif_parse_pincode_authfail(int fd){
  559. if( RFIFOREST(fd) < 6 )
  560. return 0;
  561. else{
  562. struct mmo_account acc;
  563. AccountDB* accounts = login_get_accounts_db();
  564. if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
  565. struct online_login_data* ld = login_get_online_user( acc.account_id );
  566. if( ld == nullptr ){
  567. return 0;
  568. }
  569. login_log( host2ip(acc.last_ip), acc.userid, 100, "PIN Code check failed" );
  570. }
  571. login_remove_online_user(acc.account_id);
  572. RFIFOSKIP(fd,6);
  573. }
  574. return 1;
  575. }
  576. #endif
  577. /**
  578. * Received a vip data reqest from char
  579. * type is the query to perform
  580. * 0x1 : Select info and update old_groupid
  581. * 0x2 : VIP duration is changed by atcommand or script
  582. * 0x8 : First request on player login
  583. * @param fd link to charserv
  584. * @return 0 missing data, 1 succeeded
  585. */
  586. int logchrif_parse_reqvipdata(int fd) {
  587. #ifdef VIP_ENABLE
  588. if( RFIFOREST(fd) < 15 )
  589. return 0;
  590. else { //request vip info
  591. struct mmo_account acc;
  592. AccountDB* accounts = login_get_accounts_db();
  593. int aid = RFIFOL(fd,2);
  594. int8 flag = RFIFOB(fd,6);
  595. int32 timediff = RFIFOL(fd,7);
  596. int mapfd = RFIFOL(fd,11);
  597. RFIFOSKIP(fd,15);
  598. if( accounts->load_num(accounts, &acc, aid ) ) {
  599. time_t now = time(NULL);
  600. time_t vip_time = acc.vip_time;
  601. bool isvip = false;
  602. if( acc.group_id > login_config.vip_sys.group ) { //Don't change group if it's higher.
  603. logchrif_sendvipdata(fd,&acc,0x2|((flag&0x8)?0x4:0),mapfd);
  604. return 1;
  605. }
  606. if( flag&2 ) {
  607. if(!vip_time)
  608. vip_time = now; //new entry
  609. vip_time += timediff; // set new duration
  610. }
  611. if( now < vip_time ) { //isvip
  612. if(acc.group_id != login_config.vip_sys.group) //only upd this if we're not vip already
  613. acc.old_group = acc.group_id;
  614. acc.group_id = login_config.vip_sys.group;
  615. acc.char_slots = login_config.char_per_account + login_config.vip_sys.char_increase;
  616. isvip = true;
  617. } else { //expired or @vip -xx
  618. vip_time = 0;
  619. if(acc.group_id == login_config.vip_sys.group) //prevent alteration in case account wasn't registered as vip yet
  620. acc.group_id = acc.old_group;
  621. acc.old_group = 0;
  622. acc.char_slots = login_config.char_per_account;
  623. }
  624. acc.vip_time = vip_time;
  625. accounts->save(accounts,&acc);
  626. if( flag&1 )
  627. logchrif_sendvipdata(fd,&acc,((isvip)?0x1:0)|((flag&0x8)?0x4:0),mapfd);
  628. }
  629. }
  630. #endif
  631. return 1;
  632. }
  633. /**
  634. * IA 0x2720
  635. * Get account info that asked by inter/char-server
  636. */
  637. int logchrif_parse_accinfo(int fd) {
  638. if( RFIFOREST(fd) < 19 )
  639. return 0;
  640. else {
  641. int map_fd = RFIFOL(fd, 2), u_fd = RFIFOL(fd, 6), u_aid = RFIFOL(fd, 10), account_id = RFIFOL(fd, 14);
  642. int8 type = RFIFOB(fd, 18);
  643. AccountDB* accounts = login_get_accounts_db();
  644. struct mmo_account acc;
  645. RFIFOSKIP(fd,19);
  646. // Send back the result to char-server
  647. if (accounts->load_num(accounts, &acc, account_id)) {
  648. int len = 122 + NAME_LENGTH;
  649. //ShowInfo("Found account info for %d, requested by %d\n", account_id, u_aid);
  650. WFIFOHEAD(fd, len);
  651. WFIFOW(fd, 0) = 0x2721;
  652. WFIFOL(fd, 2) = map_fd;
  653. WFIFOL(fd, 6) = u_fd;
  654. WFIFOL(fd, 10) = u_aid;
  655. WFIFOL(fd, 14) = account_id;
  656. WFIFOB(fd, 18) = (1<<type); // success
  657. WFIFOL(fd, 19) = acc.group_id;
  658. WFIFOL(fd, 23) = acc.logincount;
  659. WFIFOL(fd, 27) = acc.state;
  660. safestrncpy(WFIFOCP(fd, 31), acc.email, 40);
  661. safestrncpy(WFIFOCP(fd, 71), acc.last_ip, 16);
  662. safestrncpy(WFIFOCP(fd, 87), acc.lastlogin, 24);
  663. safestrncpy(WFIFOCP(fd, 111), acc.birthdate, 11);
  664. safestrncpy(WFIFOCP(fd, 122), acc.userid, NAME_LENGTH);
  665. WFIFOSET(fd, len);
  666. }
  667. else {
  668. //ShowInfo("Cannot found account info for %d, requested by %d\n", account_id, u_aid);
  669. WFIFOHEAD(fd, 19);
  670. WFIFOW(fd, 0) = 0x2721;
  671. WFIFOL(fd, 2) = map_fd;
  672. WFIFOL(fd, 6) = u_fd;
  673. WFIFOL(fd, 10) = u_aid;
  674. WFIFOL(fd, 14) = account_id;
  675. WFIFOB(fd, 18) = 0; // failed
  676. WFIFOSET(fd, 19);
  677. }
  678. }
  679. return 1;
  680. }
  681. /**
  682. * Entry point from char-server to log-server.
  683. * Function that checks incoming command, then splits it to the correct handler.
  684. * @param fd: file descriptor to parse, (link to char-serv)
  685. * @return 0=invalid server,marked for disconnection,unknow packet; 1=success
  686. */
  687. int logchrif_parse(int fd){
  688. int cid; //char-serv id
  689. uint32 ipl;
  690. char ip[16];
  691. ARR_FIND( 0, ARRAYLENGTH(ch_server), cid, ch_server[cid].fd == fd );
  692. if( cid == ARRAYLENGTH(ch_server) ){// not a char server
  693. ShowDebug("logchrif_parse: Disconnecting invalid session #%d (is not a char-server)\n", fd);
  694. set_eof(fd);
  695. do_close(fd);
  696. return 0;
  697. }
  698. if( session[fd]->flag.eof ){
  699. do_close(fd);
  700. ch_server[cid].fd = -1;
  701. logchrif_on_disconnect(cid);
  702. return 0;
  703. }
  704. ipl = ch_server[cid].ip;
  705. ip2str(ipl, ip);
  706. while( RFIFOREST(fd) >= 2 ){
  707. int next = 1; // 0: avoid processing followup packets (prev was probably incomplete) packet, 1: Continue parsing
  708. uint16 command = RFIFOW(fd,0);
  709. switch( command ){
  710. case 0x2712: next = logchrif_parse_reqauth(fd, cid, ip); break;
  711. case 0x2714: next = logchrif_parse_ackusercount(fd, cid); break;
  712. case 0x2716: next = logchrif_parse_reqaccdata(fd, cid, ip); break;
  713. case 0x2719: next = logchrif_parse_keepalive(fd); break;
  714. case 0x2720: next = logchrif_parse_accinfo(fd); break; //@accinfo from inter-server
  715. case 0x2722: next = logchrif_parse_reqchangemail(fd,cid,ip); break;
  716. case 0x2724: next = logchrif_parse_requpdaccstate(fd,cid,ip); break;
  717. case 0x2725: next = logchrif_parse_reqbanacc(fd,cid,ip); break;
  718. case 0x2727: next = logchrif_parse_reqchgsex(fd,cid,ip); break;
  719. case 0x2728: next = logchrif_parse_upd_global_accreg(fd,cid,ip); break;
  720. case 0x272a: next = logchrif_parse_requnbanacc(fd,cid,ip); break;
  721. case 0x272b: next = logchrif_parse_setacconline(fd,cid); break;
  722. case 0x272c: next = logchrif_parse_setaccoffline(fd); break;
  723. case 0x272d: next = logchrif_parse_updonlinedb(fd,cid); break;
  724. case 0x272e: next = logchrif_parse_req_global_accreg(fd); break;
  725. case 0x2736: next = logchrif_parse_updcharip(fd,cid); break;
  726. case 0x2737: next = logchrif_parse_setalloffline(fd,cid); break;
  727. #if PACKETVER_SUPPORTS_PINCODE
  728. case 0x2738: next = logchrif_parse_updpincode(fd); break;
  729. case 0x2739: next = logchrif_parse_pincode_authfail(fd); break;
  730. #endif
  731. case 0x2742: next = logchrif_parse_reqvipdata(fd); break; //Vip sys
  732. default:
  733. ShowError("logchrif_parse: Unknown packet 0x%x from a char-server! Disconnecting!\n", command);
  734. set_eof(fd);
  735. return 0;
  736. } // switch
  737. if (next == 0)
  738. return 0;
  739. } // while
  740. return 1; //or 0
  741. }
  742. /// Constructor destructor and signal handlers
  743. /**
  744. * Initializes a server structure.
  745. * @param id: id of char-serv (should be >0, FIXME)
  746. */
  747. void logchrif_server_init(int id) {
  748. memset(&ch_server[id], 0, sizeof(ch_server[id]));
  749. ch_server[id].fd = -1;
  750. }
  751. /**
  752. * Destroys a server structure.
  753. * @param id: id of char-serv (should be >0, FIXME)
  754. */
  755. void logchrif_server_destroy(int id){
  756. if( ch_server[id].fd != -1 ) {
  757. do_close(ch_server[id].fd);
  758. ch_server[id].fd = -1;
  759. }
  760. }
  761. /**
  762. * Resets all the data related to a server.
  763. * Actually destroys then recreates the struct.
  764. * @param id: id of char-serv (should be >0, FIXME)
  765. */
  766. void logchrif_server_reset(int id) {
  767. login_online_db_setoffline(id); //Set all chars from this char server to offline.
  768. logchrif_server_destroy(id);
  769. logchrif_server_init(id);
  770. }
  771. /**
  772. * Called when the connection to Char Server is disconnected.
  773. * @param id: id of char-serv (should be >0, FIXME)
  774. */
  775. void logchrif_on_disconnect(int id) {
  776. ShowStatus("Char-server '%s' has disconnected.\n", ch_server[id].name);
  777. logchrif_server_reset(id);
  778. }
  779. /**
  780. * loginchrif constructor
  781. * Initialisation, function called at start of the login-serv.
  782. */
  783. void do_init_loginchrif(void){
  784. int i;
  785. for( i = 0; i < ARRAYLENGTH(ch_server); ++i )
  786. logchrif_server_init(i);
  787. // add timer to detect ip address change and perform update
  788. if (login_config.ip_sync_interval) {
  789. add_timer_func_list(logchrif_sync_ip_addresses, "sync_ip_addresses");
  790. add_timer_interval(gettick() + login_config.ip_sync_interval, logchrif_sync_ip_addresses, 0, 0, login_config.ip_sync_interval);
  791. }
  792. }
  793. /**
  794. * Signal handler
  795. * This function attempts to properly close the server when an interrupt signal is received.
  796. * current signal catch : SIGTERM, SIGINT
  797. */
  798. void do_shutdown_loginchrif(void){
  799. int id;
  800. for( id = 0; id < ARRAYLENGTH(ch_server); ++id )
  801. logchrif_server_reset(id);
  802. }
  803. /**
  804. * loginchrif destructor
  805. * dealloc..., function called at exit of the login-serv
  806. */
  807. void do_final_loginchrif(void){
  808. int i;
  809. for( i = 0; i < ARRAYLENGTH(ch_server); ++i )
  810. logchrif_server_destroy(i);
  811. }