| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- /*
- * Copyright (c) 2019 Clementine Computing LLC.
- *
- * This file is part of PopuFare.
- *
- * PopuFare is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * PopuFare is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
- *
- */
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/un.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <errno.h>
- #include <poll.h>
- #include <time.h>
- #include "../common/common_defs.h"
- #include "../commhub/commhub.h"
- #include "../commhub/client_utils.h"
- #define AVLS_COMMUNICATION_VERSION "2.1.1"
- //----------GLOBAL STATE VARIABLES
- time_t last_sync_attempt = 0; //Time of the last normal chirp in seconds since epoch
- time_t last_offline_chirp = 0; //Time of the last offline chirp in seconds since epoch
- int commhub_fd = -1; //File descriptor of our connection to the comm hub
- int server_fd = -1; //File descriptor of our connection to the sync server
- int avls_motion_interval = AVLS_MOTION_INTERVAL;
- int avls_still_interval = AVLS_STILL_INTERVAL;
- int load_avls_config()
- {
- int retval;
- FILE *f;
- char line[LINE_BUFFER_SIZE];
- int still = 0, motion = 0;
- f = fopen(AVLS_CONFIG_FILE, "rb");
- if(f)
- {
- while( !feof(f) && fgets(line, LINE_BUFFER_SIZE - 1, f) )
- {
- retval = sscanf(line, "%d %d", &motion, &still);
- if(retval == 2)
- {
- avls_motion_interval = motion;
- avls_still_interval = still;
- fclose(f);
- return 0;
- }
- }
- fclose(f);
- }
- return -1;
- }
- //This function attempts to connect to the pass server...
- int connect_to_avls_server()
- {
- int fd;
- int retval;
- struct sockaddr_in addr;
- fd = socket(PF_INET, SOCK_STREAM, 0);
- if(fd < 0)
- return -1;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(AVLS_SERVER_PORT);
- inet_aton(AVLS_SERVER_IP, &addr.sin_addr);
- retval = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
- if(retval < 0)
- {
- close(fd);
- return -2;
- }
- return fd;
- }
- int construct_avls_chirp(char *chirp, int size)
- {
- int len = 0;
- len += snprintf(chirp + len, size - len, "%d\t", get_equip_num());
- len += snprintf(chirp + len, size - len, "%d\t", driver_stat.logged_in_driver);
- len += snprintf(chirp + len, size - len, "%d\t", stop_stat.paddle);
- len += snprintf(chirp + len, size - len, "%d\t", stop_stat.route);
- len += snprintf(chirp + len, size - len, "%d\t", stop_stat.trip);
- len += snprintf(chirp + len, size - len, "%d\t", stop_stat.stop);
- len += snprintf(chirp + len, size - len, "%d\t", (int)time(NULL));
- len += snprintf(chirp + len, size - len, "%f\t", gps_stat.lat);
- len += snprintf(chirp + len, size - len, "%f\t", gps_stat.lon);
- len += snprintf(chirp + len, size - len, "%f\t", gps_stat.heading);
- len += snprintf(chirp + len, size - len, "%f\n", gps_stat.velocity);
- return len;
- }
- int send_avls_chirp(int fd)
- {
- char chirp[1024] = {0};
- int len = 0;
- len = construct_avls_chirp(chirp, sizeof(chirp));
- if(send(fd, chirp, len, 0) != len)
- {
- return -1;
- }
- return 0;
- }
- int send_offline_chirp()
- {
- char chirp[1024] = {0};
- int len = 0;
- struct message_record outgoing_msg;
- len = construct_avls_chirp(chirp, sizeof(chirp));
- if(len >= sizeof(chirp))
- {
- chirp[sizeof(chirp) - 1] = '\0';
- }
- else
- {
- chirp[len]='\0';
- }
- format_log_message(&outgoing_msg, LOGLEVEL_DEBUG, "OFFLINE AVLS: %s", chirp);
- if(commhub_fd >= 0)
- {
- return send_message(commhub_fd, &outgoing_msg);
- }
- return -1;
- }
- void maintain_ipc_hub_connect(char *progname)
- {
- struct message_record outgoing_msg;
- if(commhub_fd < 0) //if we have no connection to the communication hub
- {
- commhub_fd = connect_to_message_server(progname); //try and get one
- if(commhub_fd >= 0) //if it worked
- {
- //Subscribe to the relevant status management mailboxes
- subscribe_to_default_messages(commhub_fd);
- //Request updated status information...
- prepare_message(&outgoing_msg, MAILBOX_STATUS_REQUEST, "", 0);
- send_message(commhub_fd,&outgoing_msg);
- }
- }
- }
- int main(int argc, char **argv)
- {
- struct pollfd fds[2];
- int nfds = 0;
- int poll_return = 0;
- int read_return = 0;
- int i;
- struct message_record incoming_msg;
- #ifdef DEBUG_PRINT
- long long int _usec_now, _usec_prv, _usec_del;
- _usec_del = 60000000;
- _usec_now = get_usec_time();
- _usec_prv = _usec_now;
- #endif
- if ( (argc>1) && (
- (strncmp(argv[1], "-h", 3)==0) ||
- (strncmp(argv[1], "-v", 3)==0) ) ) {
- printf("avls_communication version: %s\n", AVLS_COMMUNICATION_VERSION);
- exit(0);
- }
- //------------------
- load_avls_config();
- // load current AVLS position from global state
- // (state.info file).
- //
- init_state_info();
- gps_stat.lat = state_info.lat;
- gps_stat.lon = state_info.lon;
- gps_stat.heading = state_info.heading;
- gps_stat.velocity = state_info.velocity;
- //------------------
- configure_signal_handlers(argv[0]);
- maintain_ipc_hub_connect(argv[0]);
- //Register our default keep-up-with-system status callbacks
- register_system_status_callbacks();
- while( exit_request_status == EXIT_REQUEST_NONE )
- {
- time_t now = time(NULL);
- int sync_threshold = 0;
- RESET_WATCHDOG();
- #ifdef DEBUG_PRINT
- _usec_now = get_usec_time();
- if ((_usec_now - _usec_prv) > _usec_del) {
- printf("[%lli] avls: heartbeat\n", get_usec_time());
- _usec_prv = _usec_now;
- }
- #endif
- if(hup_request_status)
- {
- load_avls_config();
- hup_request_status = 0;
- }
- maintain_ipc_hub_connect(argv[0]);
- if(server_fd < 0) //If we don't have a connection to the sync server...
- {
- if( (now - last_sync_attempt) > DEFAULT_CONNECT_RETRY ) //See if it is time to try again
- {
- if( tunnel_is_up() ) //and if the tunnel thinks it is up
- {
- server_fd = connect_to_avls_server(); //if so, try again...
- if(server_fd >= 0) //if it worked
- {
- last_sync_attempt = 0;
- }
- else
- {
- last_sync_attempt = now;
- }
- }
- }
- }
- nfds=0;
- //-----------------------------------------------
- //
- // Figure out what our time threshold is to transmit
- // a message based on whether we're moving or still.
- //
- //-----------------------------------------------
- if(gps_stat.velocity > MOTION_THRESHOLD) //See if the bus is in motion...
- {
- sync_threshold = avls_motion_interval; //if so, we want to send AVLS chirps at higher rate
- }
- else
- {
- sync_threshold = avls_still_interval; //if not, we send them at a lower default rate
- }
- if(server_fd >= 0) //---------- If we have an active connection to the AVLS server through the tunnel
- {
- fds[nfds].fd = server_fd; //Add it to the list of things we must poll()
- fds[nfds].events = 0;
- // See if we have gone long enough to need to transmit a message AND have valid GPS data to transmit
- if( ((now - last_sync_attempt) > sync_threshold) && gps_stat.gps_good )
- {
- fds[nfds].events |= POLLOUT; //If so, ask poll to see if we have buffer space to transmit one
- }
- nfds++; //either way, add this FD to the poll() list.
- }
- else //---------- Otherwise, if we have no connection to the AVLS server
- {
- // See if it is time to transmit an offline chirp AND we have valid GPS data to transmit
- if( ((now - last_offline_chirp) > sync_threshold) && gps_stat.gps_good )
- {
- if(send_offline_chirp() == 0) //If so, stick one in the diagnostic log at DEBUG priority
- {
- last_offline_chirp = now; //Remember that we've done so if it worked.
- }
- }
- }
- if(commhub_fd >= 0)
- {
- fds[nfds].fd = commhub_fd;
- fds[nfds].events = POLLIN;
- nfds++;
- }
- if(nfds > 0)
- {
- poll_return = poll(fds, nfds, POLL_TIMEOUT);
- }
- else
- {
- usleep(POLL_TIMEOUT * 1000);
- poll_return = 0;
- }
- if(poll_return <= 0)
- {
- continue;
- }
- for(i=0; i < nfds; i++)
- {
- if( fds[i].fd == server_fd )
- {
- //If we've lost connection, break this loop and poll all over again
- if(fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
- {
- close(server_fd);
- server_fd = -1;
- break;
- }
- if(fds[i].revents & POLLOUT)
- {
- //sent a query here...
- read_return = send_avls_chirp(server_fd);
- //and then update our last sync attempt time
- last_sync_attempt = now;
- if(read_return < 0)
- {
- close(server_fd);
- server_fd = -1;
- break;
- }
- }
- }
- else if( fds[i].fd == commhub_fd )
- {
- //If we've lost connection, break this loop and poll all over again
- if(fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
- {
- close(commhub_fd);
- commhub_fd = -1;
- break;
- }
- if(fds[i].revents & POLLIN)
- {
- read_return = get_message(commhub_fd, &incoming_msg);
- if( read_return < 0 )
- {
- close(commhub_fd);
- commhub_fd = -1;
- break;
- }
- process_message(&incoming_msg); //This passes the received message through the callback list
- }
- }
- }
- }
- return 0;
- }
|