/* * 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 . * */ //Check to make sure we haven't already defined these things #ifndef _COMMHUB_API #define _COMMHUB_API (1) #define MSG_NO_ACTION (0) #define MSG_ERROR (-1) #define MSG_SEND (POLLOUT) #define MSG_RECV (POLLIN) #define TOTAL_MESSAGE_SIZE (0x1000) //Each message can be a maximum of 4K including header //This is the maximum lenght of a mailbox name (excluding the terminating NUL) //The mailbox name field will always be one longer than this value to accomodate the NUL. #define MAILBOX_NAME_MAX (31) //The message_header_record structure contains the timestamp, routing, and data size for a message //being passed either client->server or server->client struct message_header_record { long long int usec_time; //When the message was sent char mailbox_name[MAILBOX_NAME_MAX + 1]; //What mailbox was it sent to? unsigned int payload_length; //How many octets of the payload are populated? pid_t sender; //The PID of the sender int from_fd; //The file descriptor of the IPC socket the message came in on }; //This is convenient because it allows the total message length to be something sane including the header. #define MAX_PAYLOAD_LENGTH ((TOTAL_MESSAGE_SIZE - sizeof(char)) - sizeof(struct message_header_record)) #define MAX_MODULE_NAME_LENGTH (1024) //The message_record structure is what is passed from client to server to send a message out to a mailbox //The same structure is passed from the server to each client that has a subscription to the mailbox struct message_record { struct message_header_record header; unsigned char payload[MAX_PAYLOAD_LENGTH]; unsigned char nul; }; typedef struct message_record message; //This defines the number of supported client sockets. We will have to replace our flat lists with hashes or trees //long before we hit this limit. We would also need a hell of a lot more RAM than exists on a viper to have this //many meaningful processes #define NUM_SUPPORTED_CLIENTS (128) //The subscriber_record structure is a linear linked list of file descriptors represinting all of the //clients who have subscribed to any given mailbox struct subscriber_record { int clientfd; pid_t pid; char progname[MAX_MODULE_NAME_LENGTH]; struct subscriber_record *next; }; typedef struct subscriber_record subscriber; //The mailbox_record structure holds a mailbox name and a list of subscribers struct mailbox_record { char mailbox_name[MAILBOX_NAME_MAX + 1]; struct subscriber_record *clients; struct mailbox_record *next; }; //This function creates a connection to the message server and returns a file descriptor //the progname parameter should be passed argv[0] to make it easier for anybody listening //in on the server side to identify which module corresponds to which PID, but it is acceptable //to pass NULL if this information is not available or this functionality not desired. int connect_to_message_server(char *progname); //This function gets the number of microseconds since epoch for storing in message headers and //comparison to determine how timely a message is. long long int get_usec_time(); //This function does a non-blocking poll to determine if the message passing socket is //ready for input or output (depending on //since it is much more efficient to block on the entire list of your I/O file descriptors //and service any that cause you to unblock. // // Returns: MSG_NO_ACTION = no message // MSG_ERROR = fatal error (passed fd is no good) // // If the socket is ready, the return value will be // whatever combination of events specified in mask (MSG_SEND, MSG_RECV) // that is actually ready. // int message_socket_status(int message_socket_fd, int mask); //this function will pack a mailbox address and a payload into the supplied message structure and //set the correct timestamp. int prepare_message(struct message_record *target, char *mailbox, void *payload, unsigned int payload_len); //the send_message function will transmit a message and its header (trimmed to the specified payload length). //zero will be returned on success, -1 on failure. int send_message(int message_socket_fd, struct message_record *message); //the get_message function will receive a message from the opposite end of the socket and place it in the //supplied message structure incliding its header. -1 is returned on failure, 0 on success. int get_message(int message_socket_fd, struct message_record *message); //This is a utility function to get the number of microseconds since the epoch long long int get_usec_time(); //------------------------------------------------ SPECIAL MAILBOXES #define MAILBOX_HELLO "_HELLO" #define MAILBOX_SUBSCRIBE "_SUBSCRIBE" #define MAILBOX_UNSUBSCRIBE "_UNSUBSCRIBE" #define MAILBOX_BROADCAST "_BROADCAST" #define MAILBOX_WIRETAP "_WIRETAP" #define MAILBOX_ERROR "_ERROR" //------------------------------------------------ MAILBOXES USED FOR COMMUNICATION BETWEEN MODULES //--------- PROCESS STATUS RELATED #define MAILBOX_PING "_PING" //A process should ALWAYS respond to this message. The payload will be echoed back //in the PONG message, so sticking a unique identifier (or sequence number) in there may be useful #define MAILBOX_PONG "_PONG" //A PONG message is the appropriate respoonse to the above PING message. #define MAILBOX_EXIT "_EXIT" //A process should catch this message and make a graceful exit #define MAILBOX_HUP "_HUP" //A process should catch this and reload its config file //--------- SYSTEM STATUS RELATED #define MAILBOX_STATUS_REQUEST "STATUS_REQ" //Requests all modules report their status #define MAILBOX_PASS_STATUS "PASS_STATUS" //This message indicates the current passdb status. Payload is struct pass_status_struct #define MAILBOX_BILL_STATUS "BILL_STATUS" //This message indicates the current billdb status. Payload is struct bill_status_struct #define MAILBOX_DRIVER_STATUS "DRIVER_STATUS" //This message indicates the current driver login status. Payload is struct driver_status_struct #define MAILBOX_GPS_STATUS "GPS_STATUS" //This mailbox indicates that there is a new GPS datum available. Payload is struct gps_status_struct #define MAILBOX_STOP_STATUS "STOP_STATUS" //This mailbox indicates that there is a new bus stop arrival event. Payload is stop_status_struct //--------- ACTION MESSAGES #define MAILBOX_TOKEN_MAG "TOKEN_MAG" //A Magstripe has been presented. Parameter is the magstripe output #define MAILBOX_TOKEN_RFID "TOKEN_RFID" //An RFID card has been presented. Parameter is the RFID output #define MAILBOX_FLUSH_PASSES "FLUSH_PASSES" //A request has been made to flush the pass database #define MAILBOX_UPDATE_PASSES "UPDATE_PASSES" //A request has been made to try to update the pass database #define MAILBOX_DRIVER_NOTIFY "DRIVER_NOTIFY" //A message is being transmitted to the user #define MAILBOX_BILLING_LOG "BILLING_LOG" //A billing long entry is ready to dispatch #define MAILBOX_PIU_MESSAGE "PIU_MESSAGE" //A message to display on line 0 of the PIU. Payload is piu_message_struct #define MAILBOX_SET_PADDLE "SET_PADDLE" //A message to request a paddle change. Payload is set_paddle_req_struct #define MAILBOX_PADDLE_ACK "PADDLE_ACK" //A reply to the above message. Payload is the same, but with result field populated. #define MAILBOX_NEXT_STOP "NEXT_STOP" //Request to advance to the next stop on the paddle #define MAILBOX_PREV_STOP "PREV_STOP" //Request to advance to the previous stop on the paddle #define MAILBOX_RULE_CALL "RULE_CALL" //Request the passdb module to execute a rule. Payload is driver_rulecall_struct #define MAILBOX_VAULT_DROP "VAULT_DROP" //Request the cash vault drop #define MAILBOX_PASSDB_CONSISTENCY "PASSDB_CONSIST" //Have the passdb do a consistency check #define MAILBOX_PASSDB_PULSE "PASSDB_PULSE" //Generate a 'pulse' string to stderr //------------------------------------------------ MESSAGE BODY DATA STRUCTURES typedef struct gps_status_struct { //GPS location data double lat, lon, heading, velocity; //GPS Quality data int num_sats; //Number of sats in view int gps_good; //GPS fix considered valid time_t stamp; //System timestamp at last valid received fix time_t gpstime; //GPS timestamp from last valid received GPS time } gps_status; #define STOP_NAME_LEN (64) typedef struct stop_status_struct { //Paddle data int paddle; //Current stop data int route, trip, stop; double lat,lon; char stopname[STOP_NAME_LEN]; } stop_status; #define DRIVER_NAME_LEN (64) typedef struct driver_status_struct { //Information on the currently logged in driver int logged_in_driver; char driver_name[DRIVER_NAME_LEN]; //Information on the current equipment number int equip_num; } driver_status; #define PIU_PRIORITY_NOTIFY (100) #define PIU_PRIORITY_FARE (200) #define PIU_MESSAGE_LEN (64) //this is optimistic since our display is only 20 characters wide... typedef struct piu_message_struct { //If this message is of greater or equal priority than the currently displayed one, it will clobber it int priority; //Which line do we want to display this on? int line; //And for how long? 0 seconds = set default for that line int seconds; //And now for the actual message... char message[PIU_MESSAGE_LEN]; } piu_message; #define FLUSH_STATUS_NORMAL (0) //we are not in the process of a flush operation #define FLUSH_STATUS_LEGACY (1) //we are in the process of an old-style flush, pass checking won't work #define FLUSH_STATUS_DOWNLOAD (2) //we are in the process of downloading a ZFLUSH datablob, pass checking will work with old database #define FLUSH_STATUS_APPLY (3) //we are in the process of applying a downloaded ZFLUSH datablob, pass checking won't work #define FLUSH_STATUS_WRITE (4) //we are done applying, but waiting for the disk write to complete, pass checking won't work #define PASSDB_OPERABLE(x) ( ((x) == FLUSH_STATUS_NORMAL) || ((x) == FLUSH_STATUS_DOWNLOAD) ) typedef struct pass_status_struct { //This indicates what our flush status is int flush_status; //This is a generic progress bar counter, expected to be in the range of 0-100 (for percent). int progress_indicator; //Last server contact time_t last_sync_time; time_t last_ack_time; } pass_status; typedef struct bill_status_struct { //Last server contact time_t last_sync_time; time_t last_ack_time; //Number of undelivered billing / log messages bound for the server int unsynced_messages; } bill_status; typedef struct set_paddle_req_struct { int request; int result; } set_paddle_req; #define DRIVER_RULECALL_LEN (24) typedef struct driver_rulecall_struct { char rulename[DRIVER_RULECALL_LEN]; char ruleparam[DRIVER_RULECALL_LEN]; } driver_rulecall; #endif //#ifdef _TRANSIT_COMMHUB_API