loginchrif.c 30 KB

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