pass_communication.c 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553
  1. /*
  2. * Copyright (c) 2019 Clementine Computing LLC.
  3. *
  4. * This file is part of PopuFare.
  5. *
  6. * PopuFare is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * PopuFare is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include <sys/socket.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <sys/un.h>
  24. #include <netinet/in.h>
  25. #include <arpa/inet.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <unistd.h>
  29. #include <errno.h>
  30. #include <poll.h>
  31. #include <time.h>
  32. #include <zlib.h>
  33. #include "../common/common_defs.h"
  34. #include "../commhub/commhub.h"
  35. #include "../commhub/client_utils.h"
  36. #include "passdb_slim.h"
  37. #include "rules.h"
  38. #include "rfid_decoder.h"
  39. // --------------------- DEBUG -----------------------------
  40. int g_debug_flag = 0;
  41. #include <stdarg.h>
  42. void debug_print_file(char *fn, char *msg, ... )
  43. {
  44. va_list p_arg;
  45. FILE *fp;
  46. va_start(p_arg, msg);
  47. if ( !(fp = fopen(fn, "a")) ) return;
  48. vfprintf(fp, msg, p_arg);
  49. fclose(fp);
  50. va_end(p_arg);
  51. }
  52. // --------------------- DEBUG -----------------------------
  53. //----------GLOBAL STATE VARIABLES
  54. int flush_in_progress = 0; //This flag is used to tell if there is a flush in progress
  55. time_t last_sync_attempt = 0; //Time of the last sync attempt in seconds since epoch
  56. time_t last_sync_ack = 0; //Time of the last ack from the server (update, delete, or nop)
  57. int commhub_fd = -1; //File descriptor of our connection to the comm hub
  58. int server_fd = -1; //File descriptor of our connection to the sync server
  59. int zflush_in_progress = 0;
  60. void *zflush_data = NULL;
  61. int zflush_data_size = 0;
  62. int zflush_idx = 0;
  63. time_t last_piu_update = 0; //Last PIU status update
  64. pass_status real_pass_status = {0};
  65. int update_piu_status_message(int busy)
  66. {
  67. struct message_record outgoing;
  68. time_t now = time(NULL);
  69. struct tm t;
  70. char *status = "READY";
  71. int am_pm;
  72. int hour;
  73. if(busy)
  74. {
  75. status = "BUSY";
  76. }
  77. else
  78. {
  79. if( real_pass_status.flush_status == FLUSH_STATUS_APPLY )
  80. {
  81. status = "APPLY";
  82. }
  83. else if(real_pass_status.flush_status == FLUSH_STATUS_WRITE)
  84. {
  85. status = "SAVING";
  86. }
  87. else if( !rules_loaded() ||
  88. (real_pass_status.flush_status == FLUSH_STATUS_LEGACY) ||
  89. (real_pass_status.flush_status == FLUSH_STATUS_DOWNLOAD) )
  90. {
  91. status = "LOADING";
  92. }
  93. else if( !driver_stat.logged_in_driver )
  94. {
  95. status = "SEE DRIVER";
  96. }
  97. }
  98. if(commhub_fd >= 0)
  99. {
  100. localtime_r(&now, &t);
  101. if( (t.tm_hour < 12) )
  102. {
  103. am_pm = 0;
  104. if(t.tm_hour == 0)
  105. {
  106. hour = 12;
  107. }
  108. else
  109. {
  110. hour = t.tm_hour;
  111. }
  112. }
  113. else
  114. {
  115. am_pm = 1;
  116. if(t.tm_hour == 12)
  117. {
  118. hour = 12;
  119. }
  120. else
  121. {
  122. hour = t.tm_hour - 12;
  123. }
  124. }
  125. format_piu_message(&outgoing, 0, 0, 0, "%d/%d %d:%02d %s %s", t.tm_mon + 1, t.tm_mday, hour, t.tm_min, am_pm?"PM":"AM", status);
  126. send_message(commhub_fd, &outgoing);
  127. if(real_pass_status.flush_status == FLUSH_STATUS_DOWNLOAD)
  128. {
  129. format_piu_message(&outgoing, 1, 0, 0, "Downloading %d%%", real_pass_status.progress_indicator);
  130. send_message(commhub_fd, &outgoing);
  131. }
  132. else if(real_pass_status.flush_status == FLUSH_STATUS_APPLY)
  133. {
  134. format_piu_message(&outgoing, 1, 0, 0, "Applying %d%%", real_pass_status.progress_indicator);
  135. send_message(commhub_fd, &outgoing);
  136. }
  137. else if(real_pass_status.flush_status == FLUSH_STATUS_WRITE)
  138. {
  139. format_piu_message(&outgoing, 1, 0, 0, "Saving Database");
  140. send_message(commhub_fd, &outgoing);
  141. }
  142. else
  143. {
  144. format_piu_message(&outgoing, 1, 0, 0, "");
  145. send_message(commhub_fd, &outgoing);
  146. }
  147. }
  148. return 0;
  149. }
  150. //This function attempts to connect to the pass server...
  151. int connect_to_pass_server()
  152. {
  153. int fd;
  154. int retval;
  155. struct sockaddr_in addr;
  156. fd = socket(PF_INET, SOCK_STREAM, 0);
  157. if(fd < 0)
  158. return -1;
  159. addr.sin_family = AF_INET;
  160. addr.sin_port = htons(PASS_SERVER_PORT);
  161. inet_aton(PASS_SERVER_IP, &addr.sin_addr);
  162. retval = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
  163. if(retval < 0)
  164. {
  165. close(fd);
  166. return -2;
  167. }
  168. return fd;
  169. }
  170. int do_database_flush(passdb_slim_context *ctx)
  171. {
  172. int retval;
  173. //Detach from the current pass database
  174. detach_from_passdb(ctx);
  175. //Format a new database file...
  176. //format_new_passdb();
  177. format_new_passdbs();
  178. retval = attach_to_passdb(ctx);
  179. if( DB_FAIL(retval) ) //If we fail to attach to our new database
  180. {
  181. fprintf(stderr, "Error (%d) attaching to pass database during flush attempt\n", retval); //report failure
  182. return retval;
  183. }
  184. else //Otherwise, report success.
  185. {
  186. printf("Pass database flushed!\n");
  187. return 0;
  188. }
  189. }
  190. int send_query_message(int fd, passdb_slim_context *ctx)
  191. {
  192. char query[LINE_BUFFER_SIZE] = {0};
  193. int i, n;
  194. int retval;
  195. if(fd < 0)
  196. return -1;
  197. n = sprintf(query, "QUERY\t%llu\n", ctx->seq);
  198. // printf("Sending: \"%s\"\n", query);
  199. i = 0;
  200. while(i < n)
  201. {
  202. retval = send(fd, query + i, n - i, 0);
  203. if(retval <= 0)
  204. return -1;
  205. i += retval;
  206. }
  207. return 0;
  208. }
  209. int send_flushreq_message(int fd)
  210. {
  211. char query[LINE_BUFFER_SIZE] = {0};
  212. int i, n;
  213. int retval;
  214. if(fd < 0)
  215. return -1;
  216. n = sprintf(query, "QUERY\t0\n");
  217. // printf("Sending: \"%s\"\n", query);
  218. i = 0;
  219. while(i < n)
  220. {
  221. retval = send(fd, query + i, n - i, 0);
  222. if(retval <= 0)
  223. return -1;
  224. i += retval;
  225. }
  226. return 0;
  227. }
  228. // This function sends our local buspass state structure (real_pass_status) to other modules if either the force flag is set,
  229. //or if it differs from the last one received from the IPC hub.
  230. //
  231. // This function returns:
  232. //
  233. // < 0 Failure in communication (IPC socket is down...)
  234. // == 0 No news to send (force was not set and our status has not changed)
  235. // == 1 News was successfully sent.
  236. //
  237. // This is useful because often the next thing we want to do after sending a status update is update the display on the
  238. // PIU, but we only want to do that when the update represents a meaningful change which the user will notice (so as not
  239. // to flood that serial port with redundant change notifications).
  240. //
  241. int send_pass_state(int force)
  242. {
  243. struct message_record outgoing_msg;
  244. int retval;
  245. // Only actually perform the send if EITHER: The force flag has been set, OR the status message we are sending
  246. //differs from the last status message we received from ourselves via the IPC hub (which should model what other
  247. //modules think out status currently is).
  248. if(force || memcmp(&real_pass_status, &pass_stat, sizeof(real_pass_status)))
  249. {
  250. prepare_message(&outgoing_msg, MAILBOX_PASS_STATUS, &real_pass_status, sizeof(real_pass_status));
  251. retval = send_message(commhub_fd,&outgoing_msg);
  252. return (retval < 0)?retval:1;
  253. }
  254. return 0;
  255. }
  256. // This function updates our local buspass state structure (real_pass_status) from the internal state of other data structures
  257. //and using the two parameters (flush_status (see ../commhub/commhub.h for values) and a progress indicater (in percent),
  258. //a copy of our local status to other modules if it differs from the last state (using the send_pass_state() function above).
  259. int update_pass_state(int flush_status, int progress)
  260. {
  261. real_pass_status.progress_indicator = 0;
  262. switch(flush_status)
  263. {
  264. case FLUSH_STATUS_DOWNLOAD: //This means we're in the process of downloading a ZFLUSH dataset
  265. real_pass_status.flush_status = FLUSH_STATUS_DOWNLOAD;
  266. if(progress == 0) //if no progress indicator number is supplied
  267. {
  268. if(zflush_data_size != 0) //and it is possible to calculate
  269. {
  270. //use our download count / expected size to calculate a percentage
  271. real_pass_status.progress_indicator = (100 * zflush_idx) / zflush_data_size;
  272. }
  273. }
  274. else //if a progress indicator is supplied, simnply use it...
  275. {
  276. real_pass_status.progress_indicator = progress;
  277. }
  278. break;
  279. case FLUSH_STATUS_APPLY: //In the case of APPLY, WRITE, or LEGACY, just take the progress number on faith
  280. case FLUSH_STATUS_WRITE:
  281. case FLUSH_STATUS_LEGACY:
  282. {
  283. real_pass_status.flush_status = flush_status;
  284. real_pass_status.progress_indicator = progress;
  285. }
  286. break;
  287. default: //Otherwise, just let the other modules know we're feeling normal today...
  288. real_pass_status.flush_status = FLUSH_STATUS_NORMAL;
  289. break;
  290. }
  291. //inform other modules of any changes...
  292. return send_pass_state(0);
  293. }
  294. int do_zflush(passdb_slim_context *ctx, void *data, int len);
  295. //Cleanup after (or abort in progress) a ZFLUSH attempt
  296. int zflush_cleanup()
  297. {
  298. zflush_idx = 0;
  299. flush_in_progress = 0;
  300. zflush_in_progress = 0;
  301. zflush_data_size = 0;
  302. if(zflush_data)
  303. {
  304. free(zflush_data);
  305. }
  306. zflush_data = NULL;
  307. return 0;
  308. }
  309. int handle_pass_update_request(char *line, passdb_slim_context *ctx, int sync)
  310. {
  311. rider_record foo = {0};
  312. char buffer[LINE_BUFFER_SIZE];
  313. int input_idx = 0;
  314. int eol = 0;
  315. //Extract the first tab-delimited field from the input line...
  316. input_idx += get_field(buffer, line + input_idx, sizeof(buffer), &eol);
  317. //If that field is blank, then we ignore this line
  318. if( buffer[0] == '\0' )
  319. {
  320. return 0;
  321. }
  322. if (g_debug_flag)
  323. {
  324. printf("# request received '%s'\n", buffer);
  325. }
  326. if( !strcasecmp(buffer, "UPDATE") ) //========================================== UPDATE
  327. {
  328. if (g_debug_flag)
  329. {
  330. printf("# UPDATE request received '%s'\n", buffer);
  331. }
  332. //------------------------------------------------------------------ seq
  333. if( eol )
  334. {
  335. fprintf(stderr, "UPDATE: Premature end of line!\n");
  336. return -1;
  337. }
  338. //Get the next field (this should be sequence number...)
  339. input_idx += get_field(buffer, line + input_idx, sizeof(buffer), &eol);
  340. foo.seq = strtoull(buffer, NULL, 10);
  341. if( foo.seq == 0 )
  342. {
  343. fprintf(stderr, "UPDATE: Blank or zero sequence number not allowed!\n");
  344. return -1;
  345. }
  346. //------------------------------------------------------------------ ID
  347. if( eol )
  348. {
  349. fprintf(stderr, "UPDATE: Premature end of line!\n");
  350. return -1;
  351. }
  352. //Get the next field (this should be Rider ID...)
  353. input_idx += get_field(buffer, line + input_idx, sizeof(buffer), &eol);
  354. foo.id = strtoull(buffer, NULL, 10);
  355. if( foo.id == 0 )
  356. {
  357. fprintf(stderr, "UPDATE: Blank or zero rider ID not allowed!\n");
  358. return -1;
  359. }
  360. //------------------------------------------------------------------ Magstripe
  361. if( eol )
  362. {
  363. fprintf(stderr, "UPDATE: Premature end of line!\n");
  364. return -1;
  365. }
  366. //Get the next field (this should be the Magstripe Value...)
  367. input_idx += get_field(foo.magstripe_value, line + input_idx, sizeof(foo.magstripe_value), &eol);
  368. //------------------------------------------------------------------ RFID
  369. if( eol )
  370. {
  371. fprintf(stderr, "UPDATE: Premature end of line!\n");
  372. return -1;
  373. }
  374. //Get the next field (this should be the RFID Value...)
  375. input_idx += get_field(foo.rfid_value, line + input_idx, sizeof(foo.rfid_value), &eol);
  376. //------------------------------------------------------------------ Rule Name
  377. if( eol )
  378. {
  379. fprintf(stderr, "UPDATE: Premature end of line!\n");
  380. return -1;
  381. }
  382. //Get the next field (this should be the Rule Name...)
  383. input_idx += get_field(foo.rule_name, line + input_idx, sizeof(foo.rule_name), &eol);
  384. //------------------------------------------------------------------ Rule Parameter
  385. if( eol )
  386. {
  387. fprintf(stderr, "UPDATE: Premature end of line!\n");
  388. return -1;
  389. }
  390. //Get the next field (this should be the Rule Parameter...)
  391. input_idx += get_field(foo.rule_param, line + input_idx, sizeof(foo.rule_param), &eol);
  392. //If we have extra fields, that's BAD NEWS!
  393. if( !eol )
  394. {
  395. fprintf(stderr, "UPDATE: Too many fields!\n");
  396. return -1;
  397. }
  398. //If everything else is okay, go ahead and update our local database
  399. last_sync_ack = time(NULL);
  400. return update_rider(ctx, &foo, sync); //returning the status of that operation
  401. }
  402. else if( !strcasecmp(buffer, "DELETE") ) //========================================== DELETE
  403. {
  404. //------------------------------------------------------------------ seq
  405. if( eol )
  406. {
  407. fprintf(stderr, "DELETE: Premature end of line!\n");
  408. return -1;
  409. }
  410. //Get the next field (this should be sequence number...)
  411. input_idx += get_field(buffer, line + input_idx, sizeof(buffer), &eol);
  412. foo.seq = strtoull(buffer, NULL, 10);
  413. if( foo.seq == 0 )
  414. {
  415. fprintf(stderr, "DELETE: Blank or zero sequence number not allowed!\n");
  416. return -1;
  417. }
  418. //------------------------------------------------------------------ ID
  419. if( eol )
  420. {
  421. fprintf(stderr, "DELETE: Premature end of line!\n");
  422. return -1;
  423. }
  424. //Get the next field (this should be Rider ID...)
  425. input_idx += get_field(buffer, line + input_idx, sizeof(buffer), &eol);
  426. foo.id = strtoull(buffer, NULL, 10);
  427. if( foo.id == 0 )
  428. {
  429. fprintf(stderr, "DELETE: Blank or zero rider ID not allowed!\n");
  430. return -1;
  431. }
  432. //If we have extra fields, that's BAD NEWS!
  433. if( !eol )
  434. {
  435. fprintf(stderr, "DELETE: Too many fields!\n");
  436. return -1;
  437. }
  438. //If everything else is okay, go ahead and update our local database
  439. last_sync_ack = time(NULL);
  440. return delete_rider(ctx, &foo, sync); //returning the status of that operation
  441. }
  442. else if( !strcasecmp(buffer, "FLUSH") ) //========================================== FLUSH
  443. {
  444. // DEBUG
  445. printf("DEBUG: FLUSH RECEIVED\n");
  446. flush_in_progress = 1;
  447. if(update_pass_state(FLUSH_STATUS_LEGACY, 0) > 0)
  448. {
  449. update_piu_status_message(0);
  450. }
  451. fprintf(stderr, "Legacy Flush Requested!\n");
  452. last_sync_ack = time(NULL);
  453. return do_database_flush(ctx);
  454. }
  455. else if( !strcasecmp(buffer, "FLUSHDONE") ) //========================================== FLUSHDONE
  456. {
  457. // DEBUG
  458. printf("DEBUG: FLUSHDONE RECEIVED\n");
  459. flush_in_progress = 0;
  460. if(update_pass_state(FLUSH_STATUS_NORMAL, 0) > 0)
  461. {
  462. update_piu_status_message(0);
  463. }
  464. fprintf(stderr, "Legacy Flush Done!\n");
  465. last_sync_ack = time(NULL);
  466. return 0;
  467. }
  468. else if( !strcasecmp(buffer, "ZFLUSH") ) //========================================== FLUSH
  469. {
  470. // DEBUG
  471. printf("DEBUG: ZFLUSH RECEIVED\n");
  472. //------------------------------------------------------------------ seq
  473. if( eol )
  474. {
  475. fprintf(stderr, "ZFLUSH: Premature end of line!\n");
  476. return -1;
  477. }
  478. //Get the next field (this should be sequence number...)
  479. input_idx += get_field(buffer, line + input_idx, sizeof(buffer), &eol);
  480. zflush_data_size = strtoull(buffer, NULL, 10);
  481. zflush_data = malloc(zflush_data_size);
  482. if(zflush_data == NULL)
  483. {
  484. fprintf(stderr, "Can't malloc %d bytes for ZFLUSH!\n", zflush_data_size);
  485. return FAIL_MEM;
  486. }
  487. printf("ZFLUSH: Downloading %d bytes.\n", zflush_data_size);
  488. zflush_idx = 0;
  489. zflush_in_progress = 1;
  490. flush_in_progress = 1;
  491. if(update_pass_state(FLUSH_STATUS_DOWNLOAD, 0) > 0) //Let update_pass_state() calculate our download percentage
  492. {
  493. update_piu_status_message(0);
  494. }
  495. last_sync_ack = time(NULL);
  496. return 0;
  497. }
  498. else if( !strcasecmp(buffer, "ZFLUSHDONE") ) //========================================== FLUSHDONE
  499. {
  500. // DEBUG
  501. printf("DEBUG: ZFLUSHDONE RECEIVED\n");
  502. fprintf(stderr, "ZFlush applying...\n");
  503. if(update_pass_state(FLUSH_STATUS_APPLY, 0) > 0) //Mark that we're starting an apply operation
  504. {
  505. update_piu_status_message(0);
  506. }
  507. do_zflush(ctx, zflush_data, zflush_data_size);
  508. zflush_cleanup();
  509. if(update_pass_state(FLUSH_STATUS_NORMAL, 0) > 0)
  510. {
  511. update_piu_status_message(0);
  512. }
  513. fprintf(stderr, "ZFlush Done!\n");
  514. //DEBUG
  515. fprintf(stderr, "CONSISTENCY CHECK: %i\n" , passdb_slim_consistency_check( ctx ) );
  516. last_sync_ack = time(NULL);
  517. return 0;
  518. }
  519. else if( !strcasecmp(buffer, "NOP") ) //========================================== NOP (this just updates ACK time)
  520. {
  521. last_sync_ack = time(NULL);
  522. return 0;
  523. }
  524. else
  525. {
  526. fprintf(stderr, "Unrecognized command: %s\n", buffer);
  527. return -1;
  528. }
  529. }
  530. int do_zflush(passdb_slim_context *ctx, void *data, int len)
  531. {
  532. char line[LINE_BUFFER_SIZE] = {0};
  533. z_stream foo = {0};
  534. int zretval;
  535. int retval;
  536. int i,j,k;
  537. int nout;
  538. struct message_record incoming_msg;
  539. foo.zalloc = Z_NULL;
  540. foo.zfree = Z_NULL;
  541. foo.opaque = Z_NULL;
  542. foo.next_in = zflush_data;
  543. foo.avail_in = zflush_data_size;
  544. foo.next_out = (void *)line;
  545. foo.avail_out = sizeof(line);
  546. foo.total_out = 0;
  547. // printf("do_zflush(%p, %p, %d)\n", ctx, data, len);
  548. retval = inflateInit(&foo);
  549. if(retval != Z_OK)
  550. {
  551. fprintf(stderr, "inflateInit failed: Zlib error %d\n", retval);
  552. return FAIL_DATABASE;
  553. }
  554. retval = do_database_flush(ctx);
  555. if( DB_FAIL(retval) )
  556. {
  557. fprintf(stderr, "Database failure during ZFLUSH while performing flush\n");
  558. return retval;
  559. }
  560. do
  561. {
  562. RESET_WATCHDOG();
  563. //Respond to PING messages from the supervisor process lest we get killed off too early...
  564. while(message_socket_status(commhub_fd, MSG_RECV) & MSG_RECV)
  565. {
  566. if(get_message(commhub_fd, &incoming_msg) >= 0)
  567. {
  568. process_message(&incoming_msg);
  569. }
  570. }
  571. zretval = inflate(&foo, Z_NO_FLUSH);
  572. if( (zretval == Z_NEED_DICT) || (zretval == Z_DATA_ERROR) || (zretval == Z_MEM_ERROR) || (zretval == Z_STREAM_ERROR) )
  573. {
  574. fprintf(stderr, "Error inflating data: Zlib error %d\n", zretval);
  575. inflateEnd(&foo);
  576. return FAIL_DATABASE;
  577. }
  578. //The number of output bytes generated is the size of the buffer - number of free bytes
  579. nout = sizeof(line) - foo.avail_out;
  580. // printf("-- %d output bytes\n", nout);
  581. j = 0;
  582. //Scan through this buffer looking for EOL characters
  583. for(i=0; i < nout; i++)
  584. {
  585. if(line[i] == '\n') //if we've found one
  586. {
  587. line[i] = '\0'; //make it a terminating nul
  588. //DEBUG
  589. //printf("DEBUG: ZFLUSH->%s\n", line + j);
  590. //handle our pass update
  591. #ifdef ZFLUSH_SLOW_BUT_SAFE
  592. //In slow but safe mode, we msync() (or write()) the memory page containing each record after each update.
  593. //This is hell on the flash, and it takes a long time, but it means that we cannot POSSIBLY write a lower
  594. //sequence number record to the physical storage media before having physically written all previous
  595. //sequence numbers in the batch.
  596. retval = handle_pass_update_request(line + j, ctx, 1);
  597. #else
  598. //In fast mode, we apply all of our update to the memory window without calling msync() or write(), and then
  599. //(see below) when we're done rewriting the mmap()'d window for the local database, then we make one call
  600. //to msync() or write() and splat it all down to flash at once. This gets us a better compression ratio
  601. //on the large chunks of file (like the Cornell passes) which change infrequently and it produces less
  602. //filesystem fragmentation, but it means that it is theoretically possible for a power event to cause a
  603. //partial write to corrupt the local database (requiring a new flush). That being said, when running on
  604. //top of JFFS2, this should cause file truncation, which will be easily detectable and trigger another
  605. //flush request next time the application comes up.
  606. retval = handle_pass_update_request(line + j, ctx, 0);
  607. #endif
  608. if( DB_FAIL(retval) )
  609. {
  610. inflateEnd(&foo);
  611. fprintf(stderr, "Database failure during ZFLUSH while processing line \"%s\"\n", line + j);
  612. return retval;
  613. }
  614. //mark the first character of the next line
  615. j = i + 1;
  616. }
  617. }
  618. //k will be equal to the number of leftover bytes
  619. k = i - j;
  620. // printf("-- i = %d j = %d k = %d\n", i, j, k);
  621. //copy those leftovers back to the beginning
  622. for(i = 0; i < k; i++)
  623. {
  624. line[i] = line[j + i];
  625. }
  626. //and update our output buffer structure
  627. foo.next_out = (void *)(line + k);
  628. foo.avail_out = sizeof(line) - k;
  629. if(foo.avail_out == 0)
  630. {
  631. fprintf(stderr, "Line too long in decompressed ZFLUSH data!\n");
  632. inflateEnd(&foo);
  633. return FAIL_DATABASE;
  634. }
  635. // Update the other modules with our status (APPLY) and a progress indicator based on the amount of compressed data
  636. //read as a percentage of the total ZFLUSH data blob.
  637. if(update_pass_state(FLUSH_STATUS_APPLY, (foo.total_in * 100) / zflush_data_size) > 0)
  638. {
  639. update_piu_status_message(0);
  640. }
  641. } while(zretval != Z_STREAM_END);
  642. inflateEnd(&foo);
  643. //In fast mode, we have to ensure that we write our big block of changes back to secondary storage all at once
  644. #ifndef ZFLUSH_SLOW_BUT_SAFE
  645. if(update_pass_state(FLUSH_STATUS_WRITE, 0) > 0) //Let the other modules know we're performing the final write...
  646. {
  647. update_piu_status_message(0);
  648. }
  649. fprintf(stderr, "Doing one-shot file write...\n");
  650. // This resets the watchdog timer for a double-long timeframe (120 seconds these days...) allowing the write to be
  651. //slow as dirt (this is rarely needed, but if the flash was badly fragmented it can take some time to coalesce free
  652. //blocks and possibly perform some erase cycles.
  653. RESET_WATCHDOG_LONG(2);
  654. // This calls msync() if we're working with a non-broken implementation of mmap() (i.e. non-jffs2) or write()
  655. //to take our updated state from RAM and save it to the underlying file.
  656. sync_all_riders(ctx);
  657. fprintf(stderr, "Done.\n");
  658. #endif
  659. // After completing a ZFLUSH operation, we want to hang up on the server (and reconnect asap). The server should
  660. //also hang up on us after completing transmission of a ZFLUSH dataset. This effectively clears the buffers going both
  661. //ways which prevents tha case where a high communication (or server-side database) lag causes two "QUERY 0" messages
  662. //to be issued in a row, the first one triggering (correctly) a ZFLUSH which will be completed, then the server will read
  663. //the second (now obsolete) "QUERY 0" message and respond to it with another (now just useless and annoying) ZFLUSH.
  664. close(server_fd); //We just do a rude close... The server does a proper shutdown(fd, 2), and the FIN will have reached
  665. //us LONG before we execute this...
  666. server_fd = -1; //Mark the TCP connection to the server as dead so we flush buffers and restart the connection next
  667. //time through the loop.
  668. return 0;
  669. }
  670. //callback handles MAILBOX_UPDATE_PASSES
  671. message_callback_return handle_update_passes_message(struct message_record *msg, void *param)
  672. {
  673. //flag our last sync attempt as NEVER
  674. last_sync_attempt = 0;
  675. return MESSAGE_HANDLED_CONT;
  676. }
  677. //callback handles MAILBOX_FLUSH_PASSES
  678. message_callback_return handle_flush_passes_message(struct message_record *msg, void *param)
  679. {
  680. //DEBUG
  681. printf("DEBUG: hanlde_flush_passes_message server_fd %i, tunnel_is_up() %i real_pass_stats.flush_stats %i ==? (FLUSH_STATUS_NORMAL %i)\n",
  682. server_fd, tunnel_is_up(), real_pass_status.flush_status, FLUSH_STATUS_NORMAL
  683. );
  684. //We only want to allow a FLUSH_PASSES request to go through if the following conditions are met:
  685. if( (server_fd >= 0) && //1: We have a connection to the server
  686. (tunnel_is_up()) && //2: That connection is real (i.e. the SSH tunnel is in a known good state)
  687. (real_pass_status.flush_status == FLUSH_STATUS_NORMAL) //3: we are not currently in the middle of doing a flush...
  688. )
  689. {
  690. send_flushreq_message(server_fd);
  691. }
  692. return MESSAGE_HANDLED_CONT;
  693. }
  694. //callback handles MAILBOX_STATUS_REQUEST
  695. message_callback_return handle_status_request_message(struct message_record *msg, void *param)
  696. {
  697. // If we're responding to a status request message, we have to force a send even if it seems redundant because odds are
  698. //the requesting module just came on line and has no current status data for us.
  699. send_pass_state(1);
  700. return MESSAGE_HANDLED_CONT;
  701. }
  702. int reject_unknown_card(char *cred)
  703. {
  704. struct message_record bill_msg;
  705. struct message_record user_msg;
  706. struct message_record rider_msg;
  707. format_piu_message(&rider_msg, 1, PIU_PRIORITY_FARE, PASSENGER_MESSAGE_DURATION, "%s %s", REJECT_STR, "UNKNOWN CARD");
  708. format_driver_message(&user_msg, LOGLEVEL_REJECT, "Unknown card");
  709. format_billing_message(&bill_msg, REJECT_STR, "UNKNOWN-CARD", "", "Unknown card", cred, 0, 0);
  710. if(commhub_fd >= 0)
  711. {
  712. send_message(commhub_fd, &bill_msg);
  713. send_message(commhub_fd, &user_msg);
  714. send_message(commhub_fd, &rider_msg);
  715. return 0;
  716. }
  717. else
  718. {
  719. return -1;
  720. }
  721. }
  722. #ifdef REJECT_IF_NO_DRIVER
  723. int reject_no_driver()
  724. {
  725. struct message_record user_msg;
  726. struct message_record rider_msg;
  727. format_piu_message(&rider_msg, 1, PIU_PRIORITY_FARE, PASSENGER_MESSAGE_DURATION, "%s", "SEE DRIVER");
  728. format_driver_message(&user_msg, LOGLEVEL_REJECT, "Not Logged In!");
  729. if(commhub_fd >= 0)
  730. {
  731. send_message(commhub_fd, &user_msg);
  732. send_message(commhub_fd, &rider_msg);
  733. return 0;
  734. }
  735. else
  736. {
  737. return -1;
  738. }
  739. }
  740. #endif
  741. message_callback_return handle_token_mag_message(struct message_record *msg, void *param)
  742. {
  743. int idx;
  744. char cred[LINE_BUFFER_SIZE] = {0};
  745. passdb_slim_context *ctx = (passdb_slim_context *)param;
  746. if(!ctx)
  747. return MESSAGE_HANDLED_CONT;
  748. update_piu_status_message(1);
  749. #ifdef REJECT_IF_NO_DRIVER
  750. if( (driver_stat.logged_in_driver <= 0) || (stop_stat.paddle <= 0) )
  751. {
  752. reject_no_driver();
  753. return MESSAGE_HANDLED_CONT;
  754. }
  755. #endif
  756. idx = smart_find_mag(ctx, (char *)msg->payload, cred);
  757. if(idx < 0)
  758. {
  759. reject_unknown_card(cred);
  760. }
  761. else
  762. {
  763. process_rider(ctx, idx, cred);
  764. }
  765. return MESSAGE_HANDLED_CONT;
  766. }
  767. message_callback_return handle_token_rfid_message(struct message_record *msg, void *param)
  768. {
  769. int idx;
  770. char cred[LINE_BUFFER_SIZE] = {0};
  771. passdb_slim_context *ctx = (passdb_slim_context *)param;
  772. if(!ctx)
  773. return MESSAGE_HANDLED_CONT;
  774. update_piu_status_message(1);
  775. #ifdef REJECT_IF_NO_DRIVER
  776. if( (driver_stat.logged_in_driver <= 0) || (stop_stat.paddle <= 0) )
  777. {
  778. reject_no_driver();
  779. return MESSAGE_HANDLED_CONT;
  780. }
  781. #endif
  782. idx = smart_find_rf(ctx, (char *)msg->payload, cred);
  783. if(idx < 0)
  784. {
  785. reject_unknown_card(cred);
  786. }
  787. else
  788. {
  789. process_rider(ctx, idx, cred);
  790. }
  791. return MESSAGE_HANDLED_CONT;
  792. }
  793. message_callback_return update_anti_passback_cache(struct message_record *msg, void *param)
  794. {
  795. apb_flush_if_needed();
  796. return MESSAGE_HANDLED_CONT;
  797. }
  798. message_callback_return handle_rule_call(struct message_record *msg, void *param)
  799. {
  800. process_driver_rulecall( (driver_rulecall *)msg->payload );
  801. return MESSAGE_HANDLED_CONT;
  802. }
  803. message_callback_return handle_pulse_callback(struct message_record *msg, void *param)
  804. {
  805. passdb_slim_context *ctx = (passdb_slim_context *)param;
  806. int n;
  807. n = ctx->n_one_cred + ctx->n_two_cred + ctx->n_spillover;
  808. fprintf(stderr, "PASSDB_PULSE: EQ# %i active %i (%i,%i,%i) [a%i,f%i] b(%i,%i,%i) rule(%i/%i)\n",
  809. get_equip_num(), n,
  810. ctx->n_one_cred, ctx->n_two_cred, ctx->n_spillover ,
  811. ctx->num_active, ctx->num_free,
  812. ctx->n_one_cred_bank, ctx->n_two_cred_bank, ctx->n_spillover_bank ,
  813. ctx->ruleparam_db->n, RULEPARAM_DB_MAX
  814. );
  815. return MESSAGE_HANDLED_CONT;
  816. }
  817. message_callback_return handle_consistency_check_callback(struct message_record *msg, void *param)
  818. {
  819. int r;
  820. passdb_slim_context *ctx = (passdb_slim_context *)param;
  821. r = passdb_slim_consistency_check( ctx );
  822. fprintf(stderr, "PASSDB_CONSIST: %i %s\n", r, (r==1) ? "(ok)" : "FAIL" );
  823. return MESSAGE_HANDLED_CONT;
  824. }
  825. void maintain_ipc_hub_connect(char *progname)
  826. {
  827. struct message_record outgoing_msg;
  828. if(commhub_fd < 0) //if we have no connection to the communication hub
  829. {
  830. commhub_fd = connect_to_message_server(progname); //try and get one
  831. // printf("commhub_fd = %d\n", commhub_fd);
  832. if(commhub_fd >= 0) //if it worked
  833. {
  834. //Subscribe to the command mailboxes we act on
  835. prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_TOKEN_MAG, strlen(MAILBOX_TOKEN_MAG));
  836. send_message(commhub_fd,&outgoing_msg);
  837. prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_TOKEN_RFID, strlen(MAILBOX_TOKEN_RFID));
  838. send_message(commhub_fd,&outgoing_msg);
  839. prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_FLUSH_PASSES, strlen(MAILBOX_FLUSH_PASSES));
  840. send_message(commhub_fd,&outgoing_msg);
  841. prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_UPDATE_PASSES, strlen(MAILBOX_UPDATE_PASSES));
  842. send_message(commhub_fd,&outgoing_msg);
  843. prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_RULE_CALL, strlen(MAILBOX_RULE_CALL));
  844. send_message(commhub_fd,&outgoing_msg);
  845. // NEW
  846. prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_PASSDB_CONSISTENCY, strlen(MAILBOX_PASSDB_CONSISTENCY));
  847. send_message(commhub_fd,&outgoing_msg);
  848. prepare_message(&outgoing_msg, MAILBOX_SUBSCRIBE, MAILBOX_PASSDB_PULSE, strlen(MAILBOX_PASSDB_PULSE));
  849. send_message(commhub_fd,&outgoing_msg);
  850. //Subscribe to the relevant status management mailboxes
  851. subscribe_to_default_messages(commhub_fd);
  852. //Request updated status information...
  853. prepare_message(&outgoing_msg, MAILBOX_STATUS_REQUEST, "", 0);
  854. send_message(commhub_fd,&outgoing_msg);
  855. }
  856. }
  857. }
  858. int main(int argc, char **argv)
  859. {
  860. struct pollfd fds[2];
  861. int nfds = 0;
  862. int poll_return = 0;
  863. int read_return = 0;
  864. int i;
  865. struct message_record incoming_msg;
  866. char input_line[LINE_BUFFER_SIZE] = {0};
  867. int input_idx = 0;
  868. int checked_idx = 0;
  869. passdb_slim_context ctx = {0};
  870. //------------------
  871. if (argc > 1)
  872. if (strncmp(argv[1], "-d", 4)==0)
  873. g_debug_flag = 1;
  874. if (g_debug_flag)
  875. {
  876. printf("# DEBUGGING on\n");
  877. }
  878. configure_signal_handlers(argv[0]);
  879. maintain_ipc_hub_connect(argv[0]);
  880. read_return = attach_to_passdb(&ctx);
  881. if( read_return < 0 )
  882. {
  883. fprintf(stderr, "Database is missing or corrupt. Attempting to format new database.\n");
  884. //read_return = format_new_passdb();
  885. read_return = format_new_passdbs();
  886. if( read_return < 0 )
  887. {
  888. fprintf(stderr, "Database cannot be created. Aborting!\n");
  889. return -1;
  890. }
  891. else
  892. {
  893. read_return = attach_to_passdb(&ctx);
  894. if( read_return < 0 )
  895. {
  896. fprintf(stderr, "New database is ALSO missing or corrupt. Aborting.\n");
  897. return -1;
  898. }
  899. }
  900. }
  901. //Register our default keep-up-with-system status callbacks
  902. register_system_status_callbacks();
  903. //Add our module-specific callbacks
  904. register_dispatch_callback(MAILBOX_UPDATE_PASSES, CALLBACK_USER(1), handle_update_passes_message, NULL);
  905. register_dispatch_callback(MAILBOX_FLUSH_PASSES, CALLBACK_USER(2), handle_flush_passes_message, NULL);
  906. register_dispatch_callback(MAILBOX_STATUS_REQUEST, CALLBACK_USER(3), handle_status_request_message, NULL);
  907. register_dispatch_callback(MAILBOX_TOKEN_RFID, CALLBACK_USER(4), handle_token_rfid_message, &ctx);
  908. register_dispatch_callback(MAILBOX_TOKEN_MAG, CALLBACK_USER(5), handle_token_mag_message, &ctx);
  909. register_dispatch_callback(MAILBOX_RULE_CALL, CALLBACK_USER(6), handle_rule_call, &ctx);
  910. //Handle status updates which require us to check expiration of the anti-passback cache
  911. register_dispatch_callback(MAILBOX_GPS_STATUS, CALLBACK_USER(6), update_anti_passback_cache, NULL);
  912. register_dispatch_callback(MAILBOX_STOP_STATUS, CALLBACK_USER(7), update_anti_passback_cache, NULL);
  913. register_dispatch_callback(MAILBOX_PASSDB_CONSISTENCY, CALLBACK_USER(8), handle_consistency_check_callback, &ctx);
  914. register_dispatch_callback(MAILBOX_PASSDB_PULSE, CALLBACK_USER(9), handle_pulse_callback, &ctx);
  915. while( exit_request_status == EXIT_REQUEST_NONE )
  916. {
  917. time_t now = time(NULL);
  918. RESET_WATCHDOG();
  919. maintain_ipc_hub_connect(argv[0]);
  920. if( (now - last_piu_update) > 0)
  921. {
  922. update_piu_status_message(0);
  923. last_piu_update = now;
  924. }
  925. if(server_fd < 0) //If we don't have a connection to the sync server...
  926. {
  927. if( (now - last_sync_attempt) > DEFAULT_CONNECT_RETRY ) //See if it is time to try again
  928. {
  929. if( tunnel_is_up() ) //and if the tunnel thinks it is up
  930. {
  931. server_fd = connect_to_pass_server(); //if so, try again...
  932. // printf("server_fd = %d\n", server_fd);
  933. if(server_fd >= 0) //if it worked
  934. {
  935. input_idx = 0; //reset our buffer index
  936. last_sync_attempt = 0;
  937. zflush_cleanup();;
  938. }
  939. else
  940. {
  941. last_sync_attempt = now;
  942. }
  943. }
  944. }
  945. }
  946. if(!rules_loaded())
  947. {
  948. load_rules(RULES_FILE);
  949. }
  950. if(rfid_pattern_loaded() <= 0)
  951. {
  952. load_rfid_decode_patterns(RFID_PATTERN_FILE);
  953. }
  954. if(hup_request_status)
  955. {
  956. hup_request_status = 0;
  957. unload_rules();
  958. load_rules(RULES_FILE);
  959. load_rfid_decode_patterns(RFID_PATTERN_FILE);
  960. }
  961. nfds=0;
  962. if(server_fd >= 0)
  963. {
  964. fds[nfds].fd = server_fd;
  965. fds[nfds].events = POLLIN;
  966. if( (now - last_sync_attempt) > DEFAULT_PASS_SYNC_RETRY )
  967. {
  968. // printf("We want to sync...\n");
  969. fds[nfds].events |= POLLOUT;
  970. }
  971. nfds++;
  972. }
  973. if(commhub_fd >= 0)
  974. {
  975. fds[nfds].fd = commhub_fd;
  976. fds[nfds].events = POLLIN;
  977. nfds++;
  978. }
  979. if(nfds > 0)
  980. {
  981. poll_return = poll(fds, nfds, POLL_TIMEOUT);
  982. }
  983. else
  984. {
  985. usleep(POLL_TIMEOUT * 1000);
  986. poll_return = 0;
  987. }
  988. if(poll_return <= 0)
  989. {
  990. continue;
  991. }
  992. for(i=0; i < nfds; i++)
  993. {
  994. if( fds[i].fd == server_fd )
  995. {
  996. if(fds[i].revents & POLLIN) //If we just got some input...
  997. {
  998. if(zflush_in_progress) //And we're in the middle of downloading ZFLUSH data
  999. {
  1000. //Read it into our ZFLUSH buffer
  1001. read_return = recv(fds[i].fd, zflush_data + zflush_idx, zflush_data_size - zflush_idx, 0);
  1002. //If the socket has closed politely (0), or had an error other than EINTR...
  1003. if( (read_return == 0) || ((read_return < 0) && (errno != EINTR)) )
  1004. {
  1005. printf("Lost touch with server. This may be OK if we just finished downloading ZFLUSH data\n");
  1006. close(server_fd);
  1007. server_fd = -1;
  1008. break;
  1009. }
  1010. else
  1011. {
  1012. if(read_return > 0) //Otherwise, if we got some real data
  1013. {
  1014. zflush_idx += read_return; //advance our download pointer
  1015. //We want to let the update_pass_state() function compute our progress bar...
  1016. update_pass_state(FLUSH_STATUS_DOWNLOAD, 0);
  1017. update_piu_status_message(0);
  1018. last_sync_attempt = now; //remember our last sync time
  1019. if(zflush_idx == zflush_data_size) //if we've got the whole shebang...
  1020. {
  1021. //Flag that we're done downloading zflush blob and returning to command mode...
  1022. zflush_in_progress = 0;
  1023. // We don't have to do anything else about this, because the next thing we will hear
  1024. //from the server is ZFLUSHDONE which will cause us to apply our downloaded zflush data.
  1025. }
  1026. }
  1027. }
  1028. }
  1029. else //If we are not in the middle of a ZFLUSH
  1030. {
  1031. read_return = recv(fds[i].fd, input_line + input_idx, sizeof(input_line) - input_idx, 0);
  1032. //If the socket has closed politely (0), or had an error other than EINTR...
  1033. if( (read_return == 0) || ((read_return < 0) && (errno != EINTR)) )
  1034. {
  1035. printf("Lost touch with server.\n");
  1036. close(server_fd);
  1037. server_fd = -1;
  1038. break;
  1039. }
  1040. else
  1041. {
  1042. if(read_return > 0) //and we got some real data
  1043. {
  1044. input_idx += read_return; //advance our input index
  1045. do //loop through the data we've received...
  1046. {
  1047. if(zflush_in_progress) //if we have begun a ZFLUSH at some point,
  1048. {
  1049. if(input_idx >= zflush_data_size)
  1050. {
  1051. int j,k;
  1052. memcpy(zflush_data, input_line, zflush_data_size);
  1053. zflush_idx = zflush_data_size;
  1054. zflush_in_progress = 0;
  1055. k = input_idx - zflush_data_size;
  1056. for(j = 0; j < k; j++)
  1057. {
  1058. input_line[j] = input_line[j + zflush_data_size];
  1059. }
  1060. input_idx = j;
  1061. checked_idx = 0;
  1062. }
  1063. else
  1064. {
  1065. // Steal the rest of our input buffer and tack it on to the beginning of the zflush
  1066. //buffer. We do this because otherwise we'd have the beginning of the zflush data blob
  1067. //sitting around collecting dust in the line buffer and we'd download the rest into the
  1068. //zflush buffer and be unable to process it because the beginning would still be
  1069. //sitting around in this other buffer.
  1070. memcpy(zflush_data, input_line, input_idx);
  1071. zflush_idx = input_idx; //advance the zflush buffer index appropriately
  1072. checked_idx = input_idx = 0; //clear our line buffer index as it is now empty
  1073. last_sync_attempt = now; //mark our last sync time as now
  1074. //printf("Added %d leftover bytes to zflush_data\n", input_idx);
  1075. break; //break out of the do loop since we're done with our input buffer
  1076. }
  1077. }
  1078. //Advance until we either hit the end of the buffer, or we hit a line-terminator
  1079. while(checked_idx < input_idx)
  1080. {
  1081. if( (input_line[checked_idx] == '\r') || (input_line[checked_idx] == '\n') )
  1082. {
  1083. break;
  1084. }
  1085. else
  1086. {
  1087. checked_idx++;
  1088. }
  1089. }
  1090. //If we didn't hit the end of the input... (meaning we got a whole line...)
  1091. if(checked_idx != input_idx)
  1092. {
  1093. int j,k;
  1094. //Null terminate the line we got as a string...
  1095. input_line[checked_idx] = '\0';
  1096. //printf("Got Command \"%s\"\n", input_line);
  1097. // ------------ DEBUG -------------
  1098. //debug_print_file("/tmp/passdb.debug", "handling update request: '%s'\n", input_line);
  1099. // ------------ DEBUG -------------
  1100. if( handle_pass_update_request(input_line, &ctx, 1) < 0 )
  1101. {
  1102. // printf("Command Failed: \"%s\"\n", input_line);
  1103. // ------------ DEBUG -------------
  1104. //debug_print_file("/tmp/passdb.debug", " FAILED! '%s'\n", input_line);
  1105. // ------------ DEBUG -------------
  1106. }
  1107. else
  1108. {
  1109. real_pass_status.last_ack_time = now;
  1110. }
  1111. last_sync_attempt = now; //remember this server contact time
  1112. real_pass_status.last_sync_time = now; //add it to our passdb status
  1113. send_pass_state(0); //update other modules if this represents a change
  1114. // Now that we've done that, we can bump the rest of characters to the beginning
  1115. //of the next line...
  1116. k = input_idx - (checked_idx + 1);
  1117. //copy those characters the the beginning of the buffer...
  1118. for(j=0; j < k; j++)
  1119. {
  1120. input_line[j] = input_line[j + checked_idx + 1];
  1121. }
  1122. input_idx = j; //Move the index to point to the next free byte in the buffer
  1123. checked_idx = 0; // Move the 'checked' index to the beginning so that next time
  1124. //we start counting index 0 as the beginning of the next line when
  1125. //it is time to start scanning for EOL.
  1126. }
  1127. // If we have hit an overflow condition such that our buffer is full and no newline
  1128. //has been received, we want to hang up on the server and try again because something is
  1129. //seriously borked...
  1130. if(input_idx == sizeof(input_line))
  1131. {
  1132. // ------------ DEBUG -------------
  1133. //debug_print_file("/tmp/passdb.debug", " input overrun!\n");
  1134. // ------------ DEBUG -------------
  1135. fprintf(stderr, "Input overrun from server (line too long).\n");
  1136. close(server_fd);
  1137. server_fd = -1;
  1138. break;
  1139. }
  1140. } while(checked_idx < input_idx); // While we have unchecked data (that we have yet to check
  1141. //for containing an end-of-line.
  1142. }
  1143. }
  1144. }
  1145. }
  1146. else //Be sure we process all input before closing a remotely closed socket...
  1147. {
  1148. //If we've lost connection, break this loop and poll all over again
  1149. if(fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
  1150. {
  1151. printf("Lost touch with server.\n");
  1152. close(server_fd);
  1153. server_fd = -1;
  1154. break;
  1155. }
  1156. }
  1157. if(fds[i].revents & POLLOUT) //If we have flagged that we intend to send a query and poll says it's OK...
  1158. {
  1159. // printf("Trying to write to server...\n");
  1160. if(real_pass_status.flush_status == FLUSH_STATUS_NORMAL)
  1161. {
  1162. send_query_message(server_fd, &ctx);
  1163. real_pass_status.last_sync_time = now;
  1164. send_pass_state(0);
  1165. }
  1166. else
  1167. {
  1168. printf("Skipping query opportunity because we are mid-flush.\n");
  1169. }
  1170. //and then update our last sync attempt time
  1171. last_sync_attempt = now;
  1172. }
  1173. }
  1174. else if( fds[i].fd == commhub_fd )
  1175. {
  1176. //If we've lost connection, break this loop and poll all over again
  1177. if(fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
  1178. {
  1179. close(commhub_fd);
  1180. commhub_fd = -1;
  1181. break;
  1182. }
  1183. if(fds[i].revents & POLLIN)
  1184. {
  1185. // printf("Trying to read from hub...\n");
  1186. read_return = get_message(commhub_fd, &incoming_msg);
  1187. if( read_return < 0 )
  1188. {
  1189. close(commhub_fd);
  1190. commhub_fd = -1;
  1191. break;
  1192. }
  1193. // ------------ DEBUG -------------
  1194. //debug_print_file("/tmp/passdb.debug", "processing incoming_msg: '%s', '%s'\n",
  1195. // incoming_msg.header.mailbox_name, incoming_msg.payload);
  1196. // ------------ DEBUG -------------
  1197. process_message(&incoming_msg); //This passes the received message through the callback list
  1198. }
  1199. }
  1200. }
  1201. }
  1202. printf("Detatching from Pass Database\n");
  1203. detach_from_passdb(&ctx);
  1204. printf("Closing connections\n");
  1205. if(server_fd >= 0)
  1206. {
  1207. close(server_fd);
  1208. server_fd = -1;
  1209. }
  1210. if(commhub_fd >= 0)
  1211. {
  1212. close(commhub_fd);
  1213. server_fd = -1;
  1214. }
  1215. printf("Goodbye.\n");
  1216. return 0;
  1217. }