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