avls_communication.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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. //------------------
  163. load_avls_config();
  164. configure_signal_handlers(argv[0]);
  165. maintain_ipc_hub_connect(argv[0]);
  166. //Register our default keep-up-with-system status callbacks
  167. register_system_status_callbacks();
  168. while( exit_request_status == EXIT_REQUEST_NONE )
  169. {
  170. time_t now = time(NULL);
  171. int sync_threshold = 0;
  172. RESET_WATCHDOG();
  173. //DEBUG
  174. printf("[%lli] avls: heartbeat\n", get_usec_time());
  175. //DEBUG
  176. if(hup_request_status)
  177. {
  178. load_avls_config();
  179. hup_request_status = 0;
  180. }
  181. maintain_ipc_hub_connect(argv[0]);
  182. if(server_fd < 0) //If we don't have a connection to the sync server...
  183. {
  184. if( (now - last_sync_attempt) > DEFAULT_CONNECT_RETRY ) //See if it is time to try again
  185. {
  186. if( tunnel_is_up() ) //and if the tunnel thinks it is up
  187. {
  188. server_fd = connect_to_avls_server(); //if so, try again...
  189. // printf("server_fd = %d\n", server_fd);
  190. if(server_fd >= 0) //if it worked
  191. {
  192. last_sync_attempt = 0;
  193. }
  194. else
  195. {
  196. last_sync_attempt = now;
  197. }
  198. }
  199. }
  200. }
  201. nfds=0;
  202. //-----------------------------------------------
  203. //
  204. // Figure out what our time threshold is to transmit
  205. // a message based on whether we're moving or still.
  206. //
  207. //-----------------------------------------------
  208. if(gps_stat.velocity > MOTION_THRESHOLD) //See if the bus is in motion...
  209. {
  210. sync_threshold = avls_motion_interval; //if so, we want to send AVLS chirps at higher rate
  211. }
  212. else
  213. {
  214. sync_threshold = avls_still_interval; //if not, we send them at a lower default rate
  215. }
  216. if(server_fd >= 0) //---------- If we have an active connection to the AVLS server through the tunnel
  217. {
  218. fds[nfds].fd = server_fd; //Add it to the list of things we must poll()
  219. fds[nfds].events = 0;
  220. // See if we have gone long enough to need to transmit a message AND have valid GPS data to transmit
  221. if( ((now - last_sync_attempt) > sync_threshold) && gps_stat.gps_good )
  222. {
  223. fds[nfds].events |= POLLOUT; //If so, ask poll to see if we have buffer space to transmit one
  224. }
  225. nfds++; //either way, add this FD to the poll() list.
  226. }
  227. else //---------- Otherwise, if we have no connection to the AVLS server
  228. {
  229. // See if it is time to transmit an offline chirp AND we have valid GPS data to transmit
  230. if( ((now - last_offline_chirp) > sync_threshold) && gps_stat.gps_good )
  231. {
  232. if(send_offline_chirp() == 0) //If so, stick one in the diagnostic log at DEBUG priority
  233. {
  234. last_offline_chirp = now; //Remember that we've done so if it worked.
  235. }
  236. }
  237. }
  238. if(commhub_fd >= 0)
  239. {
  240. fds[nfds].fd = commhub_fd;
  241. fds[nfds].events = POLLIN;
  242. nfds++;
  243. }
  244. if(nfds > 0)
  245. {
  246. poll_return = poll(fds, nfds, POLL_TIMEOUT);
  247. }
  248. else
  249. {
  250. usleep(POLL_TIMEOUT * 1000);
  251. poll_return = 0;
  252. }
  253. // printf("Poll returns %d (of %d)\n", poll_return, nfds);
  254. // for(i=0; i < nfds; i++)
  255. // {
  256. // printf("\t%d: fd=%d ev=%d rev=%d\n", i, fds[i].fd, fds[i].events, fds[i].revents);
  257. // }
  258. if(poll_return <= 0)
  259. {
  260. continue;
  261. }
  262. for(i=0; i < nfds; i++)
  263. {
  264. // printf("Processing Poll Result %d\n",i);
  265. if( fds[i].fd == server_fd )
  266. {
  267. //If we've lost connection, break this loop and poll all over again
  268. if(fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
  269. {
  270. close(server_fd);
  271. server_fd = -1;
  272. break;
  273. }
  274. if(fds[i].revents & POLLOUT)
  275. {
  276. //sent a query here...
  277. // printf("Trying to write to server...\n");
  278. read_return = send_avls_chirp(server_fd);
  279. //and then update our last sync attempt time
  280. last_sync_attempt = now;
  281. if(read_return < 0)
  282. {
  283. close(server_fd);
  284. server_fd = -1;
  285. break;
  286. }
  287. }
  288. }
  289. else if( fds[i].fd == commhub_fd )
  290. {
  291. //If we've lost connection, break this loop and poll all over again
  292. if(fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
  293. {
  294. close(commhub_fd);
  295. commhub_fd = -1;
  296. break;
  297. }
  298. if(fds[i].revents & POLLIN)
  299. {
  300. // printf("Trying to read from hub...\n");
  301. read_return = get_message(commhub_fd, &incoming_msg);
  302. if( read_return < 0 )
  303. {
  304. close(commhub_fd);
  305. commhub_fd = -1;
  306. break;
  307. }
  308. process_message(&incoming_msg); //This passes the received message through the callback list
  309. }
  310. }
  311. }
  312. }
  313. return 0;
  314. }