avls_communication.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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 "../common/common_defs.h"
  33. #include "../commhub/commhub.h"
  34. #include "../commhub/client_utils.h"
  35. //----------GLOBAL STATE VARIABLES
  36. time_t last_sync_attempt = 0; //Time of the last normal chirp in seconds since epoch
  37. time_t last_offline_chirp = 0; //Time of the last offline chirp in seconds since epoch
  38. int commhub_fd = -1; //File descriptor of our connection to the comm hub
  39. int server_fd = -1; //File descriptor of our connection to the sync server
  40. int avls_motion_interval = AVLS_MOTION_INTERVAL;
  41. int avls_still_interval = AVLS_STILL_INTERVAL;
  42. int load_avls_config()
  43. {
  44. int retval;
  45. FILE *f;
  46. char line[LINE_BUFFER_SIZE];
  47. int still = 0, motion = 0;
  48. f = fopen(AVLS_CONFIG_FILE, "rb");
  49. if(f)
  50. {
  51. while( !feof(f) && fgets(line, LINE_BUFFER_SIZE - 1, f) )
  52. {
  53. retval = sscanf(line, "%d %d", &motion, &still);
  54. if(retval == 2)
  55. {
  56. avls_motion_interval = motion;
  57. avls_still_interval = still;
  58. //DEBUG
  59. fprintf(stderr, "#avls (motion %i, still %i) interval\n", avls_motion_interval, avls_still_interval);
  60. //DEBUG
  61. fclose(f);
  62. return 0;
  63. }
  64. }
  65. fclose(f);
  66. }
  67. return -1;
  68. }
  69. //This function attempts to connect to the pass server...
  70. int connect_to_avls_server()
  71. {
  72. int fd;
  73. int retval;
  74. struct sockaddr_in addr;
  75. fd = socket(PF_INET, SOCK_STREAM, 0);
  76. if(fd < 0)
  77. return -1;
  78. addr.sin_family = AF_INET;
  79. addr.sin_port = htons(AVLS_SERVER_PORT);
  80. inet_aton(AVLS_SERVER_IP, &addr.sin_addr);
  81. retval = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
  82. if(retval < 0)
  83. {
  84. close(fd);
  85. return -2;
  86. }
  87. return fd;
  88. }
  89. int construct_avls_chirp(char *chirp, int size)
  90. {
  91. int len = 0;
  92. len += snprintf(chirp + len, size - len, "%d\t", get_equip_num());
  93. len += snprintf(chirp + len, size - len, "%d\t", driver_stat.logged_in_driver);
  94. len += snprintf(chirp + len, size - len, "%d\t", stop_stat.paddle);
  95. len += snprintf(chirp + len, size - len, "%d\t", stop_stat.route);
  96. len += snprintf(chirp + len, size - len, "%d\t", stop_stat.trip);
  97. len += snprintf(chirp + len, size - len, "%d\t", stop_stat.stop);
  98. len += snprintf(chirp + len, size - len, "%d\t", (int)time(NULL));
  99. len += snprintf(chirp + len, size - len, "%f\t", gps_stat.lat);
  100. len += snprintf(chirp + len, size - len, "%f\t", gps_stat.lon);
  101. len += snprintf(chirp + len, size - len, "%f\t", gps_stat.heading);
  102. len += snprintf(chirp + len, size - len, "%f\n", gps_stat.velocity);
  103. return len;
  104. }
  105. int send_avls_chirp(int fd)
  106. {
  107. char chirp[1024] = {0};
  108. int len = 0;
  109. len = construct_avls_chirp(chirp, sizeof(chirp));
  110. if(send(fd, chirp, len, 0) != len)
  111. {
  112. return -1;
  113. }
  114. return 0;
  115. }
  116. int send_offline_chirp()
  117. {
  118. char chirp[1024] = {0};
  119. int len = 0;
  120. struct message_record outgoing_msg;
  121. len = construct_avls_chirp(chirp, sizeof(chirp));
  122. if(len >= sizeof(chirp))
  123. {
  124. chirp[sizeof(chirp) - 1] = '\0';
  125. }
  126. else
  127. {
  128. chirp[len]='\0';
  129. }
  130. format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "OFFLINE AVLS: %s", chirp);
  131. if(commhub_fd >= 0)
  132. {
  133. return send_message(commhub_fd, &outgoing_msg);
  134. }
  135. return -1;
  136. }
  137. void maintain_ipc_hub_connect(char *progname)
  138. {
  139. struct message_record outgoing_msg;
  140. if(commhub_fd < 0) //if we have no connection to the communication hub
  141. {
  142. commhub_fd = connect_to_message_server(progname); //try and get one
  143. // printf("commhub_fd = %d\n", commhub_fd);
  144. if(commhub_fd >= 0) //if it worked
  145. {
  146. //Subscribe to the relevant status management mailboxes
  147. subscribe_to_default_messages(commhub_fd);
  148. //Request updated status information...
  149. prepare_message(&outgoing_msg, MAILBOX_STATUS_REQUEST, "", 0);
  150. send_message(commhub_fd,&outgoing_msg);
  151. }
  152. }
  153. }
  154. int main(int argc, char **argv)
  155. {
  156. struct pollfd fds[2];
  157. int nfds = 0;
  158. int poll_return = 0;
  159. int read_return = 0;
  160. int i;
  161. struct message_record incoming_msg;
  162. long long int _usec_now, _usec_prv, _usec_del;
  163. _usec_del = 60000000;
  164. _usec_now = get_usec_time();
  165. _usec_prv = _usec_now;
  166. //------------------
  167. load_avls_config();
  168. configure_signal_handlers(argv[0]);
  169. maintain_ipc_hub_connect(argv[0]);
  170. //Register our default keep-up-with-system status callbacks
  171. register_system_status_callbacks();
  172. while( exit_request_status == EXIT_REQUEST_NONE )
  173. {
  174. time_t now = time(NULL);
  175. int sync_threshold = 0;
  176. RESET_WATCHDOG();
  177. //DEBUG
  178. _usec_now = get_usec_time();
  179. if ((_usec_now - _usec_prv) > _usec_del) {
  180. printf("[%lli] avls: heartbeat\n", get_usec_time());
  181. _usec_prv = _usec_now;
  182. }
  183. //DEBUG
  184. if(hup_request_status)
  185. {
  186. load_avls_config();
  187. hup_request_status = 0;
  188. }
  189. maintain_ipc_hub_connect(argv[0]);
  190. if(server_fd < 0) //If we don't have a connection to the sync server...
  191. {
  192. if( (now - last_sync_attempt) > DEFAULT_CONNECT_RETRY ) //See if it is time to try again
  193. {
  194. if( tunnel_is_up() ) //and if the tunnel thinks it is up
  195. {
  196. server_fd = connect_to_avls_server(); //if so, try again...
  197. // printf("server_fd = %d\n", server_fd);
  198. if(server_fd >= 0) //if it worked
  199. {
  200. last_sync_attempt = 0;
  201. }
  202. else
  203. {
  204. last_sync_attempt = now;
  205. }
  206. }
  207. }
  208. }
  209. nfds=0;
  210. //-----------------------------------------------
  211. //
  212. // Figure out what our time threshold is to transmit
  213. // a message based on whether we're moving or still.
  214. //
  215. //-----------------------------------------------
  216. if(gps_stat.velocity > MOTION_THRESHOLD) //See if the bus is in motion...
  217. {
  218. sync_threshold = avls_motion_interval; //if so, we want to send AVLS chirps at higher rate
  219. }
  220. else
  221. {
  222. sync_threshold = avls_still_interval; //if not, we send them at a lower default rate
  223. }
  224. if(server_fd >= 0) //---------- If we have an active connection to the AVLS server through the tunnel
  225. {
  226. fds[nfds].fd = server_fd; //Add it to the list of things we must poll()
  227. fds[nfds].events = 0;
  228. // See if we have gone long enough to need to transmit a message AND have valid GPS data to transmit
  229. if( ((now - last_sync_attempt) > sync_threshold) && gps_stat.gps_good )
  230. {
  231. fds[nfds].events |= POLLOUT; //If so, ask poll to see if we have buffer space to transmit one
  232. }
  233. nfds++; //either way, add this FD to the poll() list.
  234. }
  235. else //---------- Otherwise, if we have no connection to the AVLS server
  236. {
  237. // See if it is time to transmit an offline chirp AND we have valid GPS data to transmit
  238. if( ((now - last_offline_chirp) > sync_threshold) && gps_stat.gps_good )
  239. {
  240. if(send_offline_chirp() == 0) //If so, stick one in the diagnostic log at DEBUG priority
  241. {
  242. last_offline_chirp = now; //Remember that we've done so if it worked.
  243. }
  244. }
  245. }
  246. if(commhub_fd >= 0)
  247. {
  248. fds[nfds].fd = commhub_fd;
  249. fds[nfds].events = POLLIN;
  250. nfds++;
  251. }
  252. if(nfds > 0)
  253. {
  254. poll_return = poll(fds, nfds, POLL_TIMEOUT);
  255. }
  256. else
  257. {
  258. usleep(POLL_TIMEOUT * 1000);
  259. poll_return = 0;
  260. }
  261. // printf("Poll returns %d (of %d)\n", poll_return, nfds);
  262. // for(i=0; i < nfds; i++)
  263. // {
  264. // printf("\t%d: fd=%d ev=%d rev=%d\n", i, fds[i].fd, fds[i].events, fds[i].revents);
  265. // }
  266. if(poll_return <= 0)
  267. {
  268. continue;
  269. }
  270. for(i=0; i < nfds; i++)
  271. {
  272. // printf("Processing Poll Result %d\n",i);
  273. if( fds[i].fd == server_fd )
  274. {
  275. //If we've lost connection, break this loop and poll all over again
  276. if(fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
  277. {
  278. close(server_fd);
  279. server_fd = -1;
  280. break;
  281. }
  282. if(fds[i].revents & POLLOUT)
  283. {
  284. //sent a query here...
  285. // printf("Trying to write to server...\n");
  286. read_return = send_avls_chirp(server_fd);
  287. //and then update our last sync attempt time
  288. last_sync_attempt = now;
  289. if(read_return < 0)
  290. {
  291. close(server_fd);
  292. server_fd = -1;
  293. break;
  294. }
  295. }
  296. }
  297. else if( fds[i].fd == commhub_fd )
  298. {
  299. //If we've lost connection, break this loop and poll all over again
  300. if(fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
  301. {
  302. close(commhub_fd);
  303. commhub_fd = -1;
  304. break;
  305. }
  306. if(fds[i].revents & POLLIN)
  307. {
  308. // printf("Trying to read from hub...\n");
  309. read_return = get_message(commhub_fd, &incoming_msg);
  310. if( read_return < 0 )
  311. {
  312. close(commhub_fd);
  313. commhub_fd = -1;
  314. break;
  315. }
  316. process_message(&incoming_msg); //This passes the received message through the callback list
  317. }
  318. }
  319. }
  320. }
  321. return 0;
  322. }