12b15cb3dSCy Schubert /* 22b15cb3dSCy Schubert * refclock_gpsdjson.c - clock driver as GPSD JSON client 32b15cb3dSCy Schubert * Juergen Perlinger (perlinger@ntp.org) 42b15cb3dSCy Schubert * Feb 11, 2014 for the NTP project. 52b15cb3dSCy Schubert * The contents of 'html/copyright.html' apply. 62b15cb3dSCy Schubert * 72b15cb3dSCy Schubert * Heavily inspired by refclock_nmea.c 82b15cb3dSCy Schubert * 9276da39aSCy Schubert * Special thanks to Gary Miller and Hal Murray for their comments and 10276da39aSCy Schubert * ideas. 11276da39aSCy Schubert * 122b15cb3dSCy Schubert * Note: This will currently NOT work with Windows due to some 132b15cb3dSCy Schubert * limitations: 142b15cb3dSCy Schubert * 152b15cb3dSCy Schubert * - There is no GPSD for Windows. (There is an unofficial port to 162b15cb3dSCy Schubert * cygwin, but Windows is not officially supported.) 172b15cb3dSCy Schubert * 18276da39aSCy Schubert * - To work properly, this driver needs PPS and TPV/TOFF sentences 19276da39aSCy Schubert * from GPSD. I don't see how the cygwin port should deal with the 20276da39aSCy Schubert * PPS signal. 212b15cb3dSCy Schubert * 222b15cb3dSCy Schubert * - The device name matching must be done in a different way for 232b15cb3dSCy Schubert * Windows. (Can be done with COMxx matching, as done for NMEA.) 242b15cb3dSCy Schubert * 252b15cb3dSCy Schubert * Apart from those minor hickups, once GPSD has been fully ported to 26276da39aSCy Schubert * Windows, there's no reason why this should not work there ;-) If this 27276da39aSCy Schubert * is ever to happen at all is a different question. 28276da39aSCy Schubert * 29276da39aSCy Schubert * --------------------------------------------------------------------- 30276da39aSCy Schubert * 31276da39aSCy Schubert * This driver works slightly different from most others, as the PPS 32276da39aSCy Schubert * information (if available) is also coming from GPSD via the data 33276da39aSCy Schubert * connection. This makes using both the PPS data and the serial data 34276da39aSCy Schubert * easier, but OTOH it's not possible to use the ATOM driver to feed a 35276da39aSCy Schubert * raw PPS stream to the core of NTPD. 36276da39aSCy Schubert * 37276da39aSCy Schubert * To go around this, the driver can use a secondary clock unit 38276da39aSCy Schubert * (units>=128) that operate in tandem with the primary clock unit 39276da39aSCy Schubert * (unit%128). The primary clock unit does all the IO stuff and data 40276da39aSCy Schubert * decoding; if a a secondary unit is attached to a primary unit, this 41276da39aSCy Schubert * secondary unit is feed with the PPS samples only and can act as a PPS 42276da39aSCy Schubert * source to the clock selection. 43276da39aSCy Schubert * 44276da39aSCy Schubert * The drawback is that the primary unit must be present for the 45276da39aSCy Schubert * secondary unit to work. 46276da39aSCy Schubert * 47276da39aSCy Schubert * This design is a compromise to reduce the IO load for both NTPD and 48276da39aSCy Schubert * GPSD; it also ensures that data is transmitted and evaluated only 49276da39aSCy Schubert * once on the side of NTPD. 50276da39aSCy Schubert * 51276da39aSCy Schubert * --------------------------------------------------------------------- 52276da39aSCy Schubert * 53276da39aSCy Schubert * trouble shooting hints: 54276da39aSCy Schubert * 55276da39aSCy Schubert * Enable and check the clock stats. Check if there are bad replies; 56276da39aSCy Schubert * there should be none. If there are actually bad replies, then the 57276da39aSCy Schubert * driver cannot parse all JSON records from GPSD, and some record 58276da39aSCy Schubert * types are vital for the operation of the driver. This indicates a 59276da39aSCy Schubert * problem on the protocol level. 60276da39aSCy Schubert * 61276da39aSCy Schubert * When started on the command line with a debug level >= 2, the 62276da39aSCy Schubert * driver dumps the raw received data and the parser input to 63276da39aSCy Schubert * stdout. Since the debug level is global, NTPD starts to create a 64276da39aSCy Schubert * *lot* of output. It makes sense to pipe it through '(f)grep 65276da39aSCy Schubert * GPSD_JSON' before writing the result to disk. 66276da39aSCy Schubert * 67276da39aSCy Schubert * A bit less intrusive is using netcat or telnet to connect to GPSD 68276da39aSCy Schubert * and snoop what NTPD would get. If you try this, you have to send a 69276da39aSCy Schubert * WATCH command to GPSD: 70276da39aSCy Schubert * 71276da39aSCy Schubert * ?WATCH={"device":"/dev/gps0","enable":true,"json":true,"pps":true};<CRLF> 72276da39aSCy Schubert * 73276da39aSCy Schubert * should show you what GPSD has to say to NTPD. Replace "/dev/gps0" 74276da39aSCy Schubert * with the device link used by GPSD, if necessary. 752b15cb3dSCy Schubert */ 762b15cb3dSCy Schubert 77276da39aSCy Schubert 782b15cb3dSCy Schubert #ifdef HAVE_CONFIG_H 792b15cb3dSCy Schubert #include <config.h> 802b15cb3dSCy Schubert #endif 812b15cb3dSCy Schubert 822b15cb3dSCy Schubert #include "ntp_types.h" 832b15cb3dSCy Schubert 842b15cb3dSCy Schubert #if defined(REFCLOCK) && defined(CLOCK_GPSDJSON) && !defined(SYS_WINNT) 852b15cb3dSCy Schubert 862b15cb3dSCy Schubert /* ===================================================================== 87276da39aSCy Schubert * Get the little JSMN library directly into our guts. Use the 'parent 88276da39aSCy Schubert * link' feature for maximum speed. 892b15cb3dSCy Schubert */ 90276da39aSCy Schubert #define JSMN_PARENT_LINKS 912b15cb3dSCy Schubert #include "../libjsmn/jsmn.c" 922b15cb3dSCy Schubert 932b15cb3dSCy Schubert /* ===================================================================== 94276da39aSCy Schubert * JSON parsing stuff 95276da39aSCy Schubert */ 96276da39aSCy Schubert 97276da39aSCy Schubert #define JSMN_MAXTOK 350 98276da39aSCy Schubert #define INVALID_TOKEN (-1) 99276da39aSCy Schubert 100276da39aSCy Schubert typedef struct json_ctx { 101276da39aSCy Schubert char * buf; 102276da39aSCy Schubert int ntok; 103276da39aSCy Schubert jsmntok_t tok[JSMN_MAXTOK]; 104276da39aSCy Schubert } json_ctx; 105276da39aSCy Schubert 106276da39aSCy Schubert typedef int tok_ref; 107276da39aSCy Schubert 108276da39aSCy Schubert /* Not all targets have 'long long', and not all of them have 'strtoll'. 109276da39aSCy Schubert * Sigh. We roll our own integer number parser. 110276da39aSCy Schubert */ 111276da39aSCy Schubert #ifdef HAVE_LONG_LONG 112276da39aSCy Schubert typedef signed long long int json_int; 113276da39aSCy Schubert typedef unsigned long long int json_uint; 114276da39aSCy Schubert #define JSON_INT_MAX LLONG_MAX 115276da39aSCy Schubert #define JSON_INT_MIN LLONG_MIN 116276da39aSCy Schubert #else 117276da39aSCy Schubert typedef signed long int json_int; 118276da39aSCy Schubert typedef unsigned long int json_uint; 119276da39aSCy Schubert #define JSON_INT_MAX LONG_MAX 120276da39aSCy Schubert #define JSON_INT_MIN LONG_MIN 121276da39aSCy Schubert #endif 122276da39aSCy Schubert 123276da39aSCy Schubert /* ===================================================================== 1242b15cb3dSCy Schubert * header stuff we need 1252b15cb3dSCy Schubert */ 1262b15cb3dSCy Schubert 1272b15cb3dSCy Schubert #include <netdb.h> 1282b15cb3dSCy Schubert #include <unistd.h> 1292b15cb3dSCy Schubert #include <fcntl.h> 1302b15cb3dSCy Schubert #include <string.h> 1312b15cb3dSCy Schubert #include <ctype.h> 132276da39aSCy Schubert #include <math.h> 1332b15cb3dSCy Schubert 1342b15cb3dSCy Schubert #include <sys/types.h> 1352b15cb3dSCy Schubert #include <sys/socket.h> 1362b15cb3dSCy Schubert #include <sys/stat.h> 1372b15cb3dSCy Schubert #include <netinet/tcp.h> 1382b15cb3dSCy Schubert 1392b15cb3dSCy Schubert #if defined(HAVE_SYS_POLL_H) 1402b15cb3dSCy Schubert # include <sys/poll.h> 1412b15cb3dSCy Schubert #elif defined(HAVE_SYS_SELECT_H) 1422b15cb3dSCy Schubert # include <sys/select.h> 1432b15cb3dSCy Schubert #else 1442b15cb3dSCy Schubert # error need poll() or select() 1452b15cb3dSCy Schubert #endif 1462b15cb3dSCy Schubert 1472b15cb3dSCy Schubert #include "ntpd.h" 1482b15cb3dSCy Schubert #include "ntp_io.h" 1492b15cb3dSCy Schubert #include "ntp_unixtime.h" 1502b15cb3dSCy Schubert #include "ntp_refclock.h" 1512b15cb3dSCy Schubert #include "ntp_stdlib.h" 1522b15cb3dSCy Schubert #include "ntp_calendar.h" 1532b15cb3dSCy Schubert #include "timespecops.h" 1542b15cb3dSCy Schubert 155276da39aSCy Schubert /* get operation modes from mode word. 156276da39aSCy Schubert 157276da39aSCy Schubert * + SERIAL (default) evaluates only serial time information ('STI') as 158276da39aSCy Schubert * provided by TPV and TOFF records. TPV evaluation suffers from a 159276da39aSCy Schubert * bigger jitter than TOFF, sine it does not contain the receive time 160276da39aSCy Schubert * from GPSD and therefore the receive time of NTPD must be 161276da39aSCy Schubert * substituted for it. The network latency makes this a second rate 162276da39aSCy Schubert * guess. 163276da39aSCy Schubert * 164276da39aSCy Schubert * If TOFF records are detected in the data stream, the timing 165276da39aSCy Schubert * information is gleaned from this record -- it contains the local 166276da39aSCy Schubert * receive time stamp from GPSD and therefore eliminates the 167276da39aSCy Schubert * transmission latency between GPSD and NTPD. The timing information 168276da39aSCy Schubert * from TPV is ignored once a TOFF is detected or expected. 169276da39aSCy Schubert * 170276da39aSCy Schubert * TPV is still used to check the fix status, so the driver can stop 171276da39aSCy Schubert * feeding samples when GPSD says that the time information is 172276da39aSCy Schubert * effectively unreliable. 173276da39aSCy Schubert * 174276da39aSCy Schubert * + STRICT means only feed clock samples when a valid STI/PPS pair is 175276da39aSCy Schubert * available. Combines the reference time from STI with the pulse time 176276da39aSCy Schubert * from PPS. Masks the serial data jitter as long PPS is available, 177276da39aSCy Schubert * but can rapidly deteriorate once PPS drops out. 178276da39aSCy Schubert * 179276da39aSCy Schubert * + AUTO tries to use STI/PPS pairs if available for some time, and if 180276da39aSCy Schubert * this fails for too long switches back to STI only until the PPS 181276da39aSCy Schubert * signal becomes available again. See the HTML docs for this driver 182276da39aSCy Schubert * about the gotchas and why this is not the default. 183276da39aSCy Schubert */ 184276da39aSCy Schubert #define MODE_OP_MASK 0x03 185276da39aSCy Schubert #define MODE_OP_STI 0 186276da39aSCy Schubert #define MODE_OP_STRICT 1 187276da39aSCy Schubert #define MODE_OP_AUTO 2 188276da39aSCy Schubert #define MODE_OP_MAXVAL 2 189276da39aSCy Schubert #define MODE_OP_MODE(x) ((x) & MODE_OP_MASK) 190276da39aSCy Schubert 1912b15cb3dSCy Schubert #define PRECISION (-9) /* precision assumed (about 2 ms) */ 1922b15cb3dSCy Schubert #define PPS_PRECISION (-20) /* precision assumed (about 1 us) */ 1932b15cb3dSCy Schubert #define REFID "GPSD" /* reference id */ 1942b15cb3dSCy Schubert #define DESCRIPTION "GPSD JSON client clock" /* who we are */ 1952b15cb3dSCy Schubert 1962b15cb3dSCy Schubert #define MAX_PDU_LEN 1600 1972b15cb3dSCy Schubert #define TICKOVER_LOW 10 1982b15cb3dSCy Schubert #define TICKOVER_HIGH 120 1992b15cb3dSCy Schubert #define LOGTHROTTLE 3600 2002b15cb3dSCy Schubert 201276da39aSCy Schubert /* Primary channel PPS avilability dance: 202276da39aSCy Schubert * Every good PPS sample gets us a credit of PPS_INCCOUNT points, every 203276da39aSCy Schubert * bad/missing PPS sample costs us a debit of PPS_DECCOUNT points. When 204276da39aSCy Schubert * the account reaches the upper limit we change to a mode where only 205276da39aSCy Schubert * PPS-augmented samples are fed to the core; when the account drops to 206276da39aSCy Schubert * zero we switch to a mode where TPV-only timestamps are fed to the 207276da39aSCy Schubert * core. 208276da39aSCy Schubert * This reduces the chance of rapid alternation between raw and 209276da39aSCy Schubert * PPS-augmented time stamps. 210276da39aSCy Schubert */ 211276da39aSCy Schubert #define PPS_MAXCOUNT 60 /* upper limit of account */ 212276da39aSCy Schubert #define PPS_INCCOUNT 3 /* credit for good samples */ 213276da39aSCy Schubert #define PPS_DECCOUNT 1 /* debit for bad samples */ 214276da39aSCy Schubert 215276da39aSCy Schubert /* The secondary (PPS) channel uses a different strategy to avoid old 216276da39aSCy Schubert * PPS samples in the median filter. 217276da39aSCy Schubert */ 218276da39aSCy Schubert #define PPS2_MAXCOUNT 10 2192b15cb3dSCy Schubert 2202b15cb3dSCy Schubert #ifndef BOOL 2212b15cb3dSCy Schubert # define BOOL int 2222b15cb3dSCy Schubert #endif 2232b15cb3dSCy Schubert #ifndef TRUE 2242b15cb3dSCy Schubert # define TRUE 1 2252b15cb3dSCy Schubert #endif 2262b15cb3dSCy Schubert #ifndef FALSE 2272b15cb3dSCy Schubert # define FALSE 0 2282b15cb3dSCy Schubert #endif 2292b15cb3dSCy Schubert 230276da39aSCy Schubert #define PROTO_VERSION(hi,lo) \ 231276da39aSCy Schubert ((((uint32_t)(hi) << 16) & 0xFFFF0000u) | \ 232276da39aSCy Schubert ((uint32_t)(lo) & 0x0FFFFu)) 233276da39aSCy Schubert 2342b15cb3dSCy Schubert /* some local typedefs: The NTPD formatting style cries for short type 2352b15cb3dSCy Schubert * names, and we provide them locally. Note:the suffix '_t' is reserved 2362b15cb3dSCy Schubert * for the standard; I use a capital T instead. 2372b15cb3dSCy Schubert */ 2382b15cb3dSCy Schubert typedef struct peer peerT; 2392b15cb3dSCy Schubert typedef struct refclockproc clockprocT; 2402b15cb3dSCy Schubert typedef struct addrinfo addrinfoT; 2412b15cb3dSCy Schubert 2422b15cb3dSCy Schubert /* ===================================================================== 2432b15cb3dSCy Schubert * We use the same device name scheme as does the NMEA driver; since 2442b15cb3dSCy Schubert * GPSD supports the same links, we can select devices by a fixed name. 2452b15cb3dSCy Schubert */ 2462b15cb3dSCy Schubert static const char * s_dev_stem = "/dev/gps"; 2472b15cb3dSCy Schubert 2482b15cb3dSCy Schubert /* ===================================================================== 2492b15cb3dSCy Schubert * forward declarations for transfer vector and the vector itself 2502b15cb3dSCy Schubert */ 2512b15cb3dSCy Schubert 2522b15cb3dSCy Schubert static void gpsd_init (void); 2532b15cb3dSCy Schubert static int gpsd_start (int, peerT *); 2542b15cb3dSCy Schubert static void gpsd_shutdown (int, peerT *); 2552b15cb3dSCy Schubert static void gpsd_receive (struct recvbuf *); 2562b15cb3dSCy Schubert static void gpsd_poll (int, peerT *); 2572b15cb3dSCy Schubert static void gpsd_control (int, const struct refclockstat *, 2582b15cb3dSCy Schubert struct refclockstat *, peerT *); 2592b15cb3dSCy Schubert static void gpsd_timer (int, peerT *); 2602b15cb3dSCy Schubert 261276da39aSCy Schubert static int myasprintf(char**, char const*, ...) NTP_PRINTF(2, 3); 262276da39aSCy Schubert 263276da39aSCy Schubert static void enter_opmode(peerT *peer, int mode); 264276da39aSCy Schubert static void leave_opmode(peerT *peer, int mode); 2652b15cb3dSCy Schubert 2662b15cb3dSCy Schubert struct refclock refclock_gpsdjson = { 2672b15cb3dSCy Schubert gpsd_start, /* start up driver */ 2682b15cb3dSCy Schubert gpsd_shutdown, /* shut down driver */ 2692b15cb3dSCy Schubert gpsd_poll, /* transmit poll message */ 2702b15cb3dSCy Schubert gpsd_control, /* fudge control */ 2712b15cb3dSCy Schubert gpsd_init, /* initialize driver */ 2722b15cb3dSCy Schubert noentry, /* buginfo */ 2732b15cb3dSCy Schubert gpsd_timer /* called once per second */ 2742b15cb3dSCy Schubert }; 2752b15cb3dSCy Schubert 2762b15cb3dSCy Schubert /* ===================================================================== 2772b15cb3dSCy Schubert * our local clock unit and data 2782b15cb3dSCy Schubert */ 279276da39aSCy Schubert struct gpsd_unit; 280276da39aSCy Schubert typedef struct gpsd_unit gpsd_unitT; 2812b15cb3dSCy Schubert 282276da39aSCy Schubert struct gpsd_unit { 283276da39aSCy Schubert /* links for sharing between master/slave units */ 284276da39aSCy Schubert gpsd_unitT *next_unit; 285276da39aSCy Schubert size_t refcount; 286276da39aSCy Schubert 287276da39aSCy Schubert /* data for the secondary PPS channel */ 288276da39aSCy Schubert peerT *pps_peer; 289276da39aSCy Schubert 290276da39aSCy Schubert /* unit and operation modes */ 291276da39aSCy Schubert int unit; 292276da39aSCy Schubert int mode; 293276da39aSCy Schubert char *logname; /* cached name for log/print */ 294276da39aSCy Schubert char * device; /* device name of unit */ 295276da39aSCy Schubert 296276da39aSCy Schubert /* current line protocol version */ 297276da39aSCy Schubert uint32_t proto_version; 298276da39aSCy Schubert 299276da39aSCy Schubert /* PPS time stamps primary + secondary channel */ 3002b15cb3dSCy Schubert l_fp pps_local; /* when we received the PPS message */ 3012b15cb3dSCy Schubert l_fp pps_stamp; /* related reference time */ 3022b15cb3dSCy Schubert l_fp pps_recvt; /* when GPSD detected the pulse */ 303276da39aSCy Schubert l_fp pps_stamp2;/* related reference time (secondary) */ 304276da39aSCy Schubert l_fp pps_recvt2;/* when GPSD detected the pulse (secondary)*/ 305276da39aSCy Schubert int ppscount; /* PPS counter (primary unit) */ 306276da39aSCy Schubert int ppscount2; /* PPS counter (secondary unit) */ 3072b15cb3dSCy Schubert 308276da39aSCy Schubert /* TPV or TOFF serial time information */ 309276da39aSCy Schubert l_fp sti_local; /* when we received the TPV/TOFF message */ 310276da39aSCy Schubert l_fp sti_stamp; /* effective GPS time stamp */ 311276da39aSCy Schubert l_fp sti_recvt; /* when GPSD got the fix */ 312276da39aSCy Schubert 313276da39aSCy Schubert /* precision estimates */ 314276da39aSCy Schubert int16_t sti_prec; /* serial precision based on EPT */ 315276da39aSCy Schubert int16_t pps_prec; /* PPS precision from GPSD or above */ 3162b15cb3dSCy Schubert 3172b15cb3dSCy Schubert /* fudge values for correction, mirrored as 'l_fp' */ 318276da39aSCy Schubert l_fp pps_fudge; /* PPS fudge primary channel */ 319276da39aSCy Schubert l_fp pps_fudge2; /* PPS fudge secondary channel */ 320276da39aSCy Schubert l_fp sti_fudge; /* TPV/TOFF serial data fudge */ 3212b15cb3dSCy Schubert 3222b15cb3dSCy Schubert /* Flags to indicate available data */ 323276da39aSCy Schubert int fl_nosync: 1; /* GPSD signals bad quality */ 324276da39aSCy Schubert int fl_sti : 1; /* valid TPV/TOFF seen (have time) */ 3252b15cb3dSCy Schubert int fl_pps : 1; /* valid pulse seen */ 326276da39aSCy Schubert int fl_pps2 : 1; /* valid pulse seen for PPS channel */ 327276da39aSCy Schubert int fl_rawsti: 1; /* permit raw TPV/TOFF time stamps */ 3282b15cb3dSCy Schubert int fl_vers : 1; /* have protocol version */ 3292b15cb3dSCy Schubert int fl_watch : 1; /* watch reply seen */ 330276da39aSCy Schubert /* protocol flags */ 331276da39aSCy Schubert int pf_nsec : 1; /* have nanosec PPS info */ 332276da39aSCy Schubert int pf_toff : 1; /* have TOFF record for timing */ 3332b15cb3dSCy Schubert 3342b15cb3dSCy Schubert /* admin stuff for sockets and device selection */ 3352b15cb3dSCy Schubert int fdt; /* current connecting socket */ 3362b15cb3dSCy Schubert addrinfoT * addr; /* next address to try */ 3372b15cb3dSCy Schubert u_int tickover; /* timeout countdown */ 3382b15cb3dSCy Schubert u_int tickpres; /* timeout preset */ 3392b15cb3dSCy Schubert 3402b15cb3dSCy Schubert /* tallies for the various events */ 3412b15cb3dSCy Schubert u_int tc_recv; /* received known records */ 342276da39aSCy Schubert u_int tc_breply; /* bad replies / parsing errors */ 343276da39aSCy Schubert u_int tc_nosync; /* TPV / sample cycles w/o fix */ 344276da39aSCy Schubert u_int tc_sti_recv;/* received serial time info records */ 345276da39aSCy Schubert u_int tc_sti_used;/* used --^-- */ 346276da39aSCy Schubert u_int tc_pps_recv;/* received PPS timing info records */ 347276da39aSCy Schubert u_int tc_pps_used;/* used --^-- */ 3482b15cb3dSCy Schubert 3492b15cb3dSCy Schubert /* log bloat throttle */ 3502b15cb3dSCy Schubert u_int logthrottle;/* seconds to next log slot */ 3512b15cb3dSCy Schubert 352276da39aSCy Schubert /* The parse context for the current record */ 353276da39aSCy Schubert json_ctx json_parse; 354276da39aSCy Schubert 3552b15cb3dSCy Schubert /* record assemby buffer and saved length */ 3562b15cb3dSCy Schubert int buflen; 3572b15cb3dSCy Schubert char buffer[MAX_PDU_LEN]; 358276da39aSCy Schubert }; 3592b15cb3dSCy Schubert 3602b15cb3dSCy Schubert /* ===================================================================== 3612b15cb3dSCy Schubert * static local helpers forward decls 3622b15cb3dSCy Schubert */ 3632b15cb3dSCy Schubert static void gpsd_init_socket(peerT * const peer); 3642b15cb3dSCy Schubert static void gpsd_test_socket(peerT * const peer); 3652b15cb3dSCy Schubert static void gpsd_stop_socket(peerT * const peer); 3662b15cb3dSCy Schubert 3672b15cb3dSCy Schubert static void gpsd_parse(peerT * const peer, 3682b15cb3dSCy Schubert const l_fp * const rtime); 3692b15cb3dSCy Schubert static BOOL convert_ascii_time(l_fp * fp, const char * gps_time); 3702b15cb3dSCy Schubert static void save_ltc(clockprocT * const pp, const char * const tc); 3712b15cb3dSCy Schubert static int syslogok(clockprocT * const pp, gpsd_unitT * const up); 372276da39aSCy Schubert static void log_data(peerT *peer, const char *what, 373276da39aSCy Schubert const char *buf, size_t len); 374276da39aSCy Schubert static int16_t clamped_precision(int rawprec); 3752b15cb3dSCy Schubert 3762b15cb3dSCy Schubert /* ===================================================================== 3772b15cb3dSCy Schubert * local / static stuff 3782b15cb3dSCy Schubert */ 3792b15cb3dSCy Schubert 3802b15cb3dSCy Schubert /* The logon string is actually the ?WATCH command of GPSD, using JSON 3812b15cb3dSCy Schubert * data and selecting the GPS device name we created from our unit 382276da39aSCy Schubert * number. We have an old a newer version that request PPS (and TOFF) 383276da39aSCy Schubert * transmission. 384276da39aSCy Schubert * Note: These are actually format strings! 3852b15cb3dSCy Schubert */ 386276da39aSCy Schubert static const char * const s_req_watch[2] = { 387276da39aSCy Schubert "?WATCH={\"device\":\"%s\",\"enable\":true,\"json\":true};\r\n", 388276da39aSCy Schubert "?WATCH={\"device\":\"%s\",\"enable\":true,\"json\":true,\"pps\":true};\r\n" 389276da39aSCy Schubert }; 3902b15cb3dSCy Schubert 391276da39aSCy Schubert static const char * const s_req_version = 392276da39aSCy Schubert "?VERSION;\r\n"; 393276da39aSCy Schubert 394276da39aSCy Schubert /* We keep a static list of network addresses for 'localhost:gpsd' or a 395276da39aSCy Schubert * fallback alias of it, and we try to connect to them in round-robin 396276da39aSCy Schubert * fashion. The service lookup is done during the driver init 397276da39aSCy Schubert * function to minmise the impact of 'getaddrinfo()'. 398276da39aSCy Schubert * 399276da39aSCy Schubert * Alas, the init function is called even if there are no clocks 400276da39aSCy Schubert * configured for this driver. So it makes sense to defer the logging of 401276da39aSCy Schubert * any errors or other notifications until the first clock unit is 402276da39aSCy Schubert * started -- otherwise there might be syslog entries from a driver that 403276da39aSCy Schubert * is not used at all. 4042b15cb3dSCy Schubert */ 4052b15cb3dSCy Schubert static addrinfoT *s_gpsd_addr; 406276da39aSCy Schubert static gpsd_unitT *s_clock_units; 407276da39aSCy Schubert 408276da39aSCy Schubert /* list of service/socket names we want to resolve against */ 409276da39aSCy Schubert static const char * const s_svctab[][2] = { 410276da39aSCy Schubert { "localhost", "gpsd" }, 411276da39aSCy Schubert { "localhost", "2947" }, 412276da39aSCy Schubert { "127.0.0.1", "2947" }, 413276da39aSCy Schubert { NULL, NULL } 414276da39aSCy Schubert }; 415276da39aSCy Schubert 416276da39aSCy Schubert /* list of address resolution errors and index of service entry that 417276da39aSCy Schubert * finally worked. 418276da39aSCy Schubert */ 419276da39aSCy Schubert static int s_svcerr[sizeof(s_svctab)/sizeof(s_svctab[0])]; 420276da39aSCy Schubert static int s_svcidx; 4212b15cb3dSCy Schubert 4222b15cb3dSCy Schubert /* ===================================================================== 4232b15cb3dSCy Schubert * log throttling 4242b15cb3dSCy Schubert */ 4252b15cb3dSCy Schubert static int/*BOOL*/ 4262b15cb3dSCy Schubert syslogok( 4272b15cb3dSCy Schubert clockprocT * const pp, 4282b15cb3dSCy Schubert gpsd_unitT * const up) 4292b15cb3dSCy Schubert { 4302b15cb3dSCy Schubert int res = (0 != (pp->sloppyclockflag & CLK_FLAG3)) 4312b15cb3dSCy Schubert || (0 == up->logthrottle ) 4322b15cb3dSCy Schubert || (LOGTHROTTLE == up->logthrottle ); 4332b15cb3dSCy Schubert if (res) 4342b15cb3dSCy Schubert up->logthrottle = LOGTHROTTLE; 4352b15cb3dSCy Schubert return res; 4362b15cb3dSCy Schubert } 4372b15cb3dSCy Schubert 4382b15cb3dSCy Schubert /* ===================================================================== 4392b15cb3dSCy Schubert * the clock functions 4402b15cb3dSCy Schubert */ 4412b15cb3dSCy Schubert 4422b15cb3dSCy Schubert /* --------------------------------------------------------------------- 4432b15cb3dSCy Schubert * Init: This currently just gets the socket address for the GPS daemon 4442b15cb3dSCy Schubert */ 4452b15cb3dSCy Schubert static void 4462b15cb3dSCy Schubert gpsd_init(void) 4472b15cb3dSCy Schubert { 4482b15cb3dSCy Schubert addrinfoT hints; 449276da39aSCy Schubert int rc, idx; 4502b15cb3dSCy Schubert 451276da39aSCy Schubert memset(s_svcerr, 0, sizeof(s_svcerr)); 4522b15cb3dSCy Schubert memset(&hints, 0, sizeof(hints)); 4532b15cb3dSCy Schubert hints.ai_family = AF_UNSPEC; 4542b15cb3dSCy Schubert hints.ai_protocol = IPPROTO_TCP; 4552b15cb3dSCy Schubert hints.ai_socktype = SOCK_STREAM; 4562b15cb3dSCy Schubert 457276da39aSCy Schubert for (idx = 0; s_svctab[idx][0] && !s_gpsd_addr; idx++) { 458276da39aSCy Schubert rc = getaddrinfo(s_svctab[idx][0], s_svctab[idx][1], 459276da39aSCy Schubert &hints, &s_gpsd_addr); 460276da39aSCy Schubert s_svcerr[idx] = rc; 461276da39aSCy Schubert if (0 == rc) 462276da39aSCy Schubert break; 4632b15cb3dSCy Schubert s_gpsd_addr = NULL; 4642b15cb3dSCy Schubert } 465276da39aSCy Schubert s_svcidx = idx; 466276da39aSCy Schubert } 467276da39aSCy Schubert 468276da39aSCy Schubert /* --------------------------------------------------------------------- 469276da39aSCy Schubert * Init Check: flush pending log messages and check if we can proceed 470276da39aSCy Schubert */ 471276da39aSCy Schubert static int/*BOOL*/ 472276da39aSCy Schubert gpsd_init_check(void) 473276da39aSCy Schubert { 474276da39aSCy Schubert int idx; 475276da39aSCy Schubert 476276da39aSCy Schubert /* Check if there is something to log */ 477276da39aSCy Schubert if (s_svcidx == 0) 478276da39aSCy Schubert return (s_gpsd_addr != NULL); 479276da39aSCy Schubert 480276da39aSCy Schubert /* spool out the resolver errors */ 481276da39aSCy Schubert for (idx = 0; idx < s_svcidx; ++idx) { 482276da39aSCy Schubert msyslog(LOG_WARNING, 483276da39aSCy Schubert "GPSD_JSON: failed to resolve '%s:%s', rc=%d (%s)", 484276da39aSCy Schubert s_svctab[idx][0], s_svctab[idx][1], 485276da39aSCy Schubert s_svcerr[idx], gai_strerror(s_svcerr[idx])); 486276da39aSCy Schubert } 487276da39aSCy Schubert 488276da39aSCy Schubert /* check if it was fatal, or if we can proceed */ 489276da39aSCy Schubert if (s_gpsd_addr == NULL) 490276da39aSCy Schubert msyslog(LOG_ERR, "%s", 491276da39aSCy Schubert "GPSD_JSON: failed to get socket address, giving up."); 492276da39aSCy Schubert else if (idx != 0) 493276da39aSCy Schubert msyslog(LOG_WARNING, 494276da39aSCy Schubert "GPSD_JSON: using '%s:%s' instead of '%s:%s'", 495276da39aSCy Schubert s_svctab[idx][0], s_svctab[idx][1], 496276da39aSCy Schubert s_svctab[0][0], s_svctab[0][1]); 497276da39aSCy Schubert 498276da39aSCy Schubert /* make sure this gets logged only once and tell if we can 499276da39aSCy Schubert * proceed or not 500276da39aSCy Schubert */ 501276da39aSCy Schubert s_svcidx = 0; 502276da39aSCy Schubert return (s_gpsd_addr != NULL); 503276da39aSCy Schubert } 5042b15cb3dSCy Schubert 5052b15cb3dSCy Schubert /* --------------------------------------------------------------------- 5062b15cb3dSCy Schubert * Start: allocate a unit pointer and set up the runtime data 5072b15cb3dSCy Schubert */ 5082b15cb3dSCy Schubert static int 5092b15cb3dSCy Schubert gpsd_start( 5102b15cb3dSCy Schubert int unit, 5112b15cb3dSCy Schubert peerT * peer) 5122b15cb3dSCy Schubert { 5132b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 514276da39aSCy Schubert gpsd_unitT * up; 515276da39aSCy Schubert gpsd_unitT ** uscan = &s_clock_units; 5162b15cb3dSCy Schubert 5172b15cb3dSCy Schubert struct stat sb; 5182b15cb3dSCy Schubert 519276da39aSCy Schubert /* check if we can proceed at all or if init failed */ 520276da39aSCy Schubert if ( ! gpsd_init_check()) 521276da39aSCy Schubert return FALSE; 522276da39aSCy Schubert 523276da39aSCy Schubert /* search for matching unit */ 524276da39aSCy Schubert while ((up = *uscan) != NULL && up->unit != (unit & 0x7F)) 525276da39aSCy Schubert uscan = &up->next_unit; 526276da39aSCy Schubert if (up == NULL) { 527276da39aSCy Schubert /* alloc unit, add to list and increment use count ASAP. */ 528276da39aSCy Schubert up = emalloc_zero(sizeof(*up)); 529276da39aSCy Schubert *uscan = up; 530276da39aSCy Schubert ++up->refcount; 531276da39aSCy Schubert 5322b15cb3dSCy Schubert /* initialize the unit structure */ 533276da39aSCy Schubert up->logname = estrdup(refnumtoa(&peer->srcadr)); 534276da39aSCy Schubert up->unit = unit & 0x7F; 5352b15cb3dSCy Schubert up->fdt = -1; 5362b15cb3dSCy Schubert up->addr = s_gpsd_addr; 5372b15cb3dSCy Schubert up->tickpres = TICKOVER_LOW; 5382b15cb3dSCy Schubert 539276da39aSCy Schubert /* Create the device name and check for a Character 540276da39aSCy Schubert * Device. It's assumed that GPSD was started with the 541276da39aSCy Schubert * same link, so the names match. (If this is not 542276da39aSCy Schubert * practicable, we will have to read the symlink, if 543276da39aSCy Schubert * any, so we can get the true device file.) 544276da39aSCy Schubert */ 545276da39aSCy Schubert if (-1 == myasprintf(&up->device, "%s%u", 546276da39aSCy Schubert s_dev_stem, up->unit)) { 547276da39aSCy Schubert msyslog(LOG_ERR, "%s: clock device name too long", 548276da39aSCy Schubert up->logname); 549276da39aSCy Schubert goto dev_fail; 550276da39aSCy Schubert } 551276da39aSCy Schubert if (-1 == stat(up->device, &sb) || !S_ISCHR(sb.st_mode)) { 552276da39aSCy Schubert msyslog(LOG_ERR, "%s: '%s' is not a character device", 553276da39aSCy Schubert up->logname, up->device); 554276da39aSCy Schubert goto dev_fail; 555276da39aSCy Schubert } 556276da39aSCy Schubert } else { 557276da39aSCy Schubert /* All set up, just increment use count. */ 558276da39aSCy Schubert ++up->refcount; 559276da39aSCy Schubert } 560276da39aSCy Schubert 5612b15cb3dSCy Schubert /* setup refclock processing */ 5622b15cb3dSCy Schubert pp->unitptr = (caddr_t)up; 5632b15cb3dSCy Schubert pp->io.fd = -1; 5642b15cb3dSCy Schubert pp->io.clock_recv = gpsd_receive; 5652b15cb3dSCy Schubert pp->io.srcclock = peer; 5662b15cb3dSCy Schubert pp->io.datalen = 0; 5672b15cb3dSCy Schubert pp->a_lastcode[0] = '\0'; 5682b15cb3dSCy Schubert pp->lencode = 0; 5692b15cb3dSCy Schubert pp->clockdesc = DESCRIPTION; 5702b15cb3dSCy Schubert memcpy(&pp->refid, REFID, 4); 5712b15cb3dSCy Schubert 5722b15cb3dSCy Schubert /* Initialize miscellaneous variables */ 573276da39aSCy Schubert if (unit >= 128) 574276da39aSCy Schubert peer->precision = PPS_PRECISION; 575276da39aSCy Schubert else 5762b15cb3dSCy Schubert peer->precision = PRECISION; 5772b15cb3dSCy Schubert 578276da39aSCy Schubert /* If the daemon name lookup failed, just give up now. */ 579276da39aSCy Schubert if (NULL == up->addr) { 580276da39aSCy Schubert msyslog(LOG_ERR, "%s: no GPSD socket address, giving up", 581276da39aSCy Schubert up->logname); 5822b15cb3dSCy Schubert goto dev_fail; 5832b15cb3dSCy Schubert } 584276da39aSCy Schubert 5852b15cb3dSCy Schubert LOGIF(CLOCKINFO, 5862b15cb3dSCy Schubert (LOG_NOTICE, "%s: startup, device is '%s'", 5872b15cb3dSCy Schubert refnumtoa(&peer->srcadr), up->device)); 588276da39aSCy Schubert up->mode = MODE_OP_MODE(peer->ttl); 589276da39aSCy Schubert if (up->mode > MODE_OP_MAXVAL) 590276da39aSCy Schubert up->mode = 0; 591276da39aSCy Schubert if (unit >= 128) 592276da39aSCy Schubert up->pps_peer = peer; 593276da39aSCy Schubert else 594276da39aSCy Schubert enter_opmode(peer, up->mode); 5952b15cb3dSCy Schubert return TRUE; 5962b15cb3dSCy Schubert 5972b15cb3dSCy Schubert dev_fail: 5982b15cb3dSCy Schubert /* On failure, remove all UNIT ressources and declare defeat. */ 5992b15cb3dSCy Schubert 6002b15cb3dSCy Schubert INSIST (up); 601276da39aSCy Schubert if (!--up->refcount) { 602276da39aSCy Schubert *uscan = up->next_unit; 6032b15cb3dSCy Schubert free(up->device); 6042b15cb3dSCy Schubert free(up); 605276da39aSCy Schubert } 6062b15cb3dSCy Schubert 6072b15cb3dSCy Schubert pp->unitptr = (caddr_t)NULL; 6082b15cb3dSCy Schubert return FALSE; 6092b15cb3dSCy Schubert } 6102b15cb3dSCy Schubert 6112b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 6122b15cb3dSCy Schubert 6132b15cb3dSCy Schubert static void 6142b15cb3dSCy Schubert gpsd_shutdown( 6152b15cb3dSCy Schubert int unit, 6162b15cb3dSCy Schubert peerT * peer) 6172b15cb3dSCy Schubert { 6182b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 6192b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 620276da39aSCy Schubert gpsd_unitT ** uscan = &s_clock_units; 6212b15cb3dSCy Schubert 6222b15cb3dSCy Schubert UNUSED_ARG(unit); 6232b15cb3dSCy Schubert 624276da39aSCy Schubert /* The unit pointer might have been removed already. */ 625276da39aSCy Schubert if (up == NULL) 626276da39aSCy Schubert return; 627276da39aSCy Schubert 628276da39aSCy Schubert /* now check if we must close IO resources */ 629276da39aSCy Schubert if (peer != up->pps_peer) { 630276da39aSCy Schubert if (-1 != pp->io.fd) { 631276da39aSCy Schubert DPRINTF(1, ("%s: closing clock, fd=%d\n", 632276da39aSCy Schubert up->logname, pp->io.fd)); 633276da39aSCy Schubert io_closeclock(&pp->io); 634276da39aSCy Schubert pp->io.fd = -1; 635276da39aSCy Schubert } 636276da39aSCy Schubert if (up->fdt != -1) 637276da39aSCy Schubert close(up->fdt); 638276da39aSCy Schubert } 639276da39aSCy Schubert /* decrement use count and eventually remove this unit. */ 640276da39aSCy Schubert if (!--up->refcount) { 641276da39aSCy Schubert /* unlink this unit */ 642276da39aSCy Schubert while (*uscan != NULL) 643276da39aSCy Schubert if (*uscan == up) 644276da39aSCy Schubert *uscan = up->next_unit; 645276da39aSCy Schubert else 646276da39aSCy Schubert uscan = &(*uscan)->next_unit; 647276da39aSCy Schubert free(up->logname); 6482b15cb3dSCy Schubert free(up->device); 6492b15cb3dSCy Schubert free(up); 6502b15cb3dSCy Schubert } 6512b15cb3dSCy Schubert pp->unitptr = (caddr_t)NULL; 6522b15cb3dSCy Schubert LOGIF(CLOCKINFO, 6532b15cb3dSCy Schubert (LOG_NOTICE, "%s: shutdown", refnumtoa(&peer->srcadr))); 6542b15cb3dSCy Schubert } 6552b15cb3dSCy Schubert 6562b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 6572b15cb3dSCy Schubert 6582b15cb3dSCy Schubert static void 6592b15cb3dSCy Schubert gpsd_receive( 6602b15cb3dSCy Schubert struct recvbuf * rbufp) 6612b15cb3dSCy Schubert { 6622b15cb3dSCy Schubert /* declare & init control structure ptrs */ 6632b15cb3dSCy Schubert peerT * const peer = rbufp->recv_peer; 6642b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 6652b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 6662b15cb3dSCy Schubert 6672b15cb3dSCy Schubert const char *psrc, *esrc; 6682b15cb3dSCy Schubert char *pdst, *edst, ch; 6692b15cb3dSCy Schubert 670276da39aSCy Schubert /* log the data stream, if this is enabled */ 671276da39aSCy Schubert log_data(peer, "recv", (const char*)rbufp->recv_buffer, 672276da39aSCy Schubert (size_t)rbufp->recv_length); 673276da39aSCy Schubert 674276da39aSCy Schubert 6752b15cb3dSCy Schubert /* Since we're getting a raw stream data, we must assemble lines 6762b15cb3dSCy Schubert * in our receive buffer. We can't use neither 'refclock_gtraw' 6772b15cb3dSCy Schubert * not 'refclock_gtlin' here... We process chars until we reach 6782b15cb3dSCy Schubert * an EoL (that is, line feed) but we truncate the message if it 6792b15cb3dSCy Schubert * does not fit the buffer. GPSD might truncate messages, too, 6802b15cb3dSCy Schubert * so dealing with truncated buffers is necessary anyway. 6812b15cb3dSCy Schubert */ 6822b15cb3dSCy Schubert psrc = (const char*)rbufp->recv_buffer; 6832b15cb3dSCy Schubert esrc = psrc + rbufp->recv_length; 6842b15cb3dSCy Schubert 6852b15cb3dSCy Schubert pdst = up->buffer + up->buflen; 6862b15cb3dSCy Schubert edst = pdst + sizeof(up->buffer) - 1; /* for trailing NUL */ 6872b15cb3dSCy Schubert 6882b15cb3dSCy Schubert while (psrc != esrc) { 6892b15cb3dSCy Schubert ch = *psrc++; 6902b15cb3dSCy Schubert if (ch == '\n') { 6912b15cb3dSCy Schubert /* trim trailing whitespace & terminate buffer */ 6922b15cb3dSCy Schubert while (pdst != up->buffer && pdst[-1] <= ' ') 6932b15cb3dSCy Schubert --pdst; 6942b15cb3dSCy Schubert *pdst = '\0'; 6952b15cb3dSCy Schubert /* process data and reset buffer */ 696276da39aSCy Schubert up->buflen = pdst - up->buffer; 6972b15cb3dSCy Schubert gpsd_parse(peer, &rbufp->recv_time); 6982b15cb3dSCy Schubert pdst = up->buffer; 6992b15cb3dSCy Schubert } else if (pdst != edst) { 7002b15cb3dSCy Schubert /* add next char, ignoring leading whitespace */ 7012b15cb3dSCy Schubert if (ch > ' ' || pdst != up->buffer) 7022b15cb3dSCy Schubert *pdst++ = ch; 7032b15cb3dSCy Schubert } 7042b15cb3dSCy Schubert } 7052b15cb3dSCy Schubert up->buflen = pdst - up->buffer; 7062b15cb3dSCy Schubert up->tickover = TICKOVER_LOW; 7072b15cb3dSCy Schubert } 7082b15cb3dSCy Schubert 7092b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 7102b15cb3dSCy Schubert 7112b15cb3dSCy Schubert static void 712276da39aSCy Schubert poll_primary( 713276da39aSCy Schubert peerT * const peer , 714276da39aSCy Schubert clockprocT * const pp , 715276da39aSCy Schubert gpsd_unitT * const up ) 716276da39aSCy Schubert { 717276da39aSCy Schubert if (pp->coderecv != pp->codeproc) { 718276da39aSCy Schubert /* all is well */ 719276da39aSCy Schubert pp->lastref = pp->lastrec; 720276da39aSCy Schubert refclock_report(peer, CEVNT_NOMINAL); 721276da39aSCy Schubert refclock_receive(peer); 722276da39aSCy Schubert } else { 723276da39aSCy Schubert /* Not working properly, admit to it. If we have no 724276da39aSCy Schubert * connection to GPSD, declare the clock as faulty. If 725276da39aSCy Schubert * there were bad replies, this is handled as the major 726276da39aSCy Schubert * cause, and everything else is just a timeout. 727276da39aSCy Schubert */ 728276da39aSCy Schubert peer->precision = PRECISION; 729276da39aSCy Schubert if (-1 == pp->io.fd) 730276da39aSCy Schubert refclock_report(peer, CEVNT_FAULT); 731276da39aSCy Schubert else if (0 != up->tc_breply) 732276da39aSCy Schubert refclock_report(peer, CEVNT_BADREPLY); 733276da39aSCy Schubert else 734276da39aSCy Schubert refclock_report(peer, CEVNT_TIMEOUT); 735276da39aSCy Schubert } 736276da39aSCy Schubert 737276da39aSCy Schubert if (pp->sloppyclockflag & CLK_FLAG4) 738276da39aSCy Schubert mprintf_clock_stats( 739276da39aSCy Schubert &peer->srcadr,"%u %u %u %u %u %u %u", 740276da39aSCy Schubert up->tc_recv, 741276da39aSCy Schubert up->tc_breply, up->tc_nosync, 742276da39aSCy Schubert up->tc_sti_recv, up->tc_sti_used, 743276da39aSCy Schubert up->tc_pps_recv, up->tc_pps_used); 744276da39aSCy Schubert 745276da39aSCy Schubert /* clear tallies for next round */ 746276da39aSCy Schubert up->tc_breply = 0; 747276da39aSCy Schubert up->tc_recv = 0; 748276da39aSCy Schubert up->tc_nosync = 0; 749276da39aSCy Schubert up->tc_sti_recv = 0; 750276da39aSCy Schubert up->tc_sti_used = 0; 751276da39aSCy Schubert up->tc_pps_recv = 0; 752276da39aSCy Schubert up->tc_pps_used = 0; 753276da39aSCy Schubert } 754276da39aSCy Schubert 755276da39aSCy Schubert static void 756276da39aSCy Schubert poll_secondary( 757276da39aSCy Schubert peerT * const peer , 758276da39aSCy Schubert clockprocT * const pp , 759276da39aSCy Schubert gpsd_unitT * const up ) 760276da39aSCy Schubert { 761276da39aSCy Schubert if (pp->coderecv != pp->codeproc) { 762276da39aSCy Schubert /* all is well */ 763276da39aSCy Schubert pp->lastref = pp->lastrec; 764276da39aSCy Schubert refclock_report(peer, CEVNT_NOMINAL); 765276da39aSCy Schubert refclock_receive(peer); 766276da39aSCy Schubert } else { 767276da39aSCy Schubert peer->precision = PPS_PRECISION; 768276da39aSCy Schubert peer->flags &= ~FLAG_PPS; 769276da39aSCy Schubert refclock_report(peer, CEVNT_TIMEOUT); 770276da39aSCy Schubert } 771276da39aSCy Schubert } 772276da39aSCy Schubert 773276da39aSCy Schubert static void 7742b15cb3dSCy Schubert gpsd_poll( 7752b15cb3dSCy Schubert int unit, 7762b15cb3dSCy Schubert peerT * peer) 7772b15cb3dSCy Schubert { 7782b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 7792b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 7802b15cb3dSCy Schubert 7812b15cb3dSCy Schubert ++pp->polls; 782276da39aSCy Schubert if (peer == up->pps_peer) 783276da39aSCy Schubert poll_secondary(peer, pp, up); 784276da39aSCy Schubert else 785276da39aSCy Schubert poll_primary(peer, pp, up); 7862b15cb3dSCy Schubert } 7872b15cb3dSCy Schubert 7882b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 7892b15cb3dSCy Schubert 7902b15cb3dSCy Schubert static void 7912b15cb3dSCy Schubert gpsd_control( 7922b15cb3dSCy Schubert int unit, 7932b15cb3dSCy Schubert const struct refclockstat * in_st, 7942b15cb3dSCy Schubert struct refclockstat * out_st, 7952b15cb3dSCy Schubert peerT * peer ) 7962b15cb3dSCy Schubert { 7972b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 7982b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 7992b15cb3dSCy Schubert 800276da39aSCy Schubert if (peer == up->pps_peer) { 801276da39aSCy Schubert DTOLFP(pp->fudgetime1, &up->pps_fudge2); 802276da39aSCy Schubert if ( ! (pp->sloppyclockflag & CLK_FLAG1)) 803276da39aSCy Schubert peer->flags &= ~FLAG_PPS; 804276da39aSCy Schubert } else { 8052b15cb3dSCy Schubert /* save preprocessed fudge times */ 8062b15cb3dSCy Schubert DTOLFP(pp->fudgetime1, &up->pps_fudge); 807276da39aSCy Schubert DTOLFP(pp->fudgetime2, &up->sti_fudge); 808276da39aSCy Schubert 809276da39aSCy Schubert if (MODE_OP_MODE(up->mode ^ peer->ttl)) { 810276da39aSCy Schubert leave_opmode(peer, up->mode); 811276da39aSCy Schubert up->mode = MODE_OP_MODE(peer->ttl); 812276da39aSCy Schubert enter_opmode(peer, up->mode); 813276da39aSCy Schubert } 814276da39aSCy Schubert } 8152b15cb3dSCy Schubert } 8162b15cb3dSCy Schubert 8172b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 8182b15cb3dSCy Schubert 8192b15cb3dSCy Schubert static void 820276da39aSCy Schubert timer_primary( 821276da39aSCy Schubert peerT * const peer , 822276da39aSCy Schubert clockprocT * const pp , 823276da39aSCy Schubert gpsd_unitT * const up ) 8242b15cb3dSCy Schubert { 8252b15cb3dSCy Schubert int rc; 8262b15cb3dSCy Schubert 8272b15cb3dSCy Schubert /* This is used for timeout handling. Nothing that needs 8282b15cb3dSCy Schubert * sub-second precison happens here, so receive/connect/retry 8292b15cb3dSCy Schubert * timeouts are simply handled by a count down, and then we 8302b15cb3dSCy Schubert * decide what to do by the socket values. 8312b15cb3dSCy Schubert * 8322b15cb3dSCy Schubert * Note that the timer stays at zero here, unless some of the 8332b15cb3dSCy Schubert * functions set it to another value. 8342b15cb3dSCy Schubert */ 8352b15cb3dSCy Schubert if (up->logthrottle) 8362b15cb3dSCy Schubert --up->logthrottle; 8372b15cb3dSCy Schubert if (up->tickover) 8382b15cb3dSCy Schubert --up->tickover; 8392b15cb3dSCy Schubert switch (up->tickover) { 8402b15cb3dSCy Schubert case 4: 841276da39aSCy Schubert /* If we are connected to GPSD, try to get a live signal 842276da39aSCy Schubert * by querying the version. Otherwise just check the 843276da39aSCy Schubert * socket to become ready. 8442b15cb3dSCy Schubert */ 8452b15cb3dSCy Schubert if (-1 != pp->io.fd) { 846276da39aSCy Schubert size_t rlen = strlen(s_req_version); 847276da39aSCy Schubert DPRINTF(2, ("%s: timer livecheck: '%s'\n", 848276da39aSCy Schubert up->logname, s_req_version)); 849276da39aSCy Schubert log_data(peer, "send", s_req_version, rlen); 850276da39aSCy Schubert rc = write(pp->io.fd, s_req_version, rlen); 8512b15cb3dSCy Schubert (void)rc; 8522b15cb3dSCy Schubert } else if (-1 != up->fdt) { 8532b15cb3dSCy Schubert gpsd_test_socket(peer); 8542b15cb3dSCy Schubert } 8552b15cb3dSCy Schubert break; 8562b15cb3dSCy Schubert 8572b15cb3dSCy Schubert case 0: 8582b15cb3dSCy Schubert if (-1 != pp->io.fd) 8592b15cb3dSCy Schubert gpsd_stop_socket(peer); 8602b15cb3dSCy Schubert else if (-1 != up->fdt) 8612b15cb3dSCy Schubert gpsd_test_socket(peer); 8622b15cb3dSCy Schubert else if (NULL != s_gpsd_addr) 8632b15cb3dSCy Schubert gpsd_init_socket(peer); 8642b15cb3dSCy Schubert break; 8652b15cb3dSCy Schubert 8662b15cb3dSCy Schubert default: 8672b15cb3dSCy Schubert if (-1 == pp->io.fd && -1 != up->fdt) 8682b15cb3dSCy Schubert gpsd_test_socket(peer); 8692b15cb3dSCy Schubert } 870276da39aSCy Schubert } 8712b15cb3dSCy Schubert 872276da39aSCy Schubert static void 873276da39aSCy Schubert timer_secondary( 874276da39aSCy Schubert peerT * const peer , 875276da39aSCy Schubert clockprocT * const pp , 876276da39aSCy Schubert gpsd_unitT * const up ) 877276da39aSCy Schubert { 878276da39aSCy Schubert /* Reduce the count by one. Flush sample buffer and clear PPS 879276da39aSCy Schubert * flag when this happens. 880276da39aSCy Schubert */ 881276da39aSCy Schubert up->ppscount2 = max(0, (up->ppscount2 - 1)); 882276da39aSCy Schubert if (0 == up->ppscount2) { 883276da39aSCy Schubert if (pp->coderecv != pp->codeproc) { 884276da39aSCy Schubert refclock_report(peer, CEVNT_TIMEOUT); 885276da39aSCy Schubert pp->coderecv = pp->codeproc; 886276da39aSCy Schubert } 8872b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; 8882b15cb3dSCy Schubert } 889276da39aSCy Schubert } 890276da39aSCy Schubert 891276da39aSCy Schubert static void 892276da39aSCy Schubert gpsd_timer( 893276da39aSCy Schubert int unit, 894276da39aSCy Schubert peerT * peer) 895276da39aSCy Schubert { 896276da39aSCy Schubert clockprocT * const pp = peer->procptr; 897276da39aSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 898276da39aSCy Schubert 899276da39aSCy Schubert if (peer == up->pps_peer) 900276da39aSCy Schubert timer_secondary(peer, pp, up); 901276da39aSCy Schubert else 902276da39aSCy Schubert timer_primary(peer, pp, up); 903276da39aSCy Schubert } 904276da39aSCy Schubert 905276da39aSCy Schubert /* ===================================================================== 906276da39aSCy Schubert * handle opmode switches 907276da39aSCy Schubert */ 908276da39aSCy Schubert 909276da39aSCy Schubert static void 910276da39aSCy Schubert enter_opmode( 911276da39aSCy Schubert peerT *peer, 912276da39aSCy Schubert int mode) 913276da39aSCy Schubert { 914276da39aSCy Schubert clockprocT * const pp = peer->procptr; 915276da39aSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 916276da39aSCy Schubert 917276da39aSCy Schubert DPRINTF(1, ("%s: enter operation mode %d\n", 918276da39aSCy Schubert up->logname, MODE_OP_MODE(mode))); 919276da39aSCy Schubert 920276da39aSCy Schubert if (MODE_OP_MODE(mode) == MODE_OP_AUTO) { 921276da39aSCy Schubert up->fl_rawsti = 0; 922276da39aSCy Schubert up->ppscount = PPS_MAXCOUNT / 2; 923276da39aSCy Schubert } 924276da39aSCy Schubert up->fl_pps = 0; 925276da39aSCy Schubert up->fl_sti = 0; 926276da39aSCy Schubert } 927276da39aSCy Schubert 928276da39aSCy Schubert /* ------------------------------------------------------------------ */ 929276da39aSCy Schubert 930276da39aSCy Schubert static void 931276da39aSCy Schubert leave_opmode( 932276da39aSCy Schubert peerT *peer, 933276da39aSCy Schubert int mode) 934276da39aSCy Schubert { 935276da39aSCy Schubert clockprocT * const pp = peer->procptr; 936276da39aSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 937276da39aSCy Schubert 938276da39aSCy Schubert DPRINTF(1, ("%s: leaving operation mode %d\n", 939276da39aSCy Schubert up->logname, MODE_OP_MODE(mode))); 940276da39aSCy Schubert 941276da39aSCy Schubert if (MODE_OP_MODE(mode) == MODE_OP_AUTO) { 942276da39aSCy Schubert up->fl_rawsti = 0; 943276da39aSCy Schubert up->ppscount = 0; 944276da39aSCy Schubert } 945276da39aSCy Schubert up->fl_pps = 0; 946276da39aSCy Schubert up->fl_sti = 0; 947276da39aSCy Schubert } 948276da39aSCy Schubert 949276da39aSCy Schubert /* ===================================================================== 950276da39aSCy Schubert * operation mode specific evaluation 951276da39aSCy Schubert */ 952276da39aSCy Schubert 953276da39aSCy Schubert static void 954276da39aSCy Schubert add_clock_sample( 955276da39aSCy Schubert peerT * const peer , 956276da39aSCy Schubert clockprocT * const pp , 957276da39aSCy Schubert l_fp stamp, 958276da39aSCy Schubert l_fp recvt) 959276da39aSCy Schubert { 960276da39aSCy Schubert pp->lastref = stamp; 961276da39aSCy Schubert if (pp->coderecv == pp->codeproc) 962276da39aSCy Schubert refclock_report(peer, CEVNT_NOMINAL); 963276da39aSCy Schubert refclock_process_offset(pp, stamp, recvt, 0.0); 964276da39aSCy Schubert } 965276da39aSCy Schubert 966276da39aSCy Schubert /* ------------------------------------------------------------------ */ 967276da39aSCy Schubert 968276da39aSCy Schubert static void 969276da39aSCy Schubert eval_strict( 970276da39aSCy Schubert peerT * const peer , 971276da39aSCy Schubert clockprocT * const pp , 972276da39aSCy Schubert gpsd_unitT * const up ) 973276da39aSCy Schubert { 974276da39aSCy Schubert if (up->fl_sti && up->fl_pps) { 975276da39aSCy Schubert /* use TPV reference time + PPS receive time */ 976276da39aSCy Schubert add_clock_sample(peer, pp, up->sti_stamp, up->pps_recvt); 977276da39aSCy Schubert peer->precision = up->pps_prec; 978276da39aSCy Schubert /* both packets consumed now... */ 979276da39aSCy Schubert up->fl_pps = 0; 980276da39aSCy Schubert up->fl_sti = 0; 981276da39aSCy Schubert ++up->tc_sti_used; 982276da39aSCy Schubert } 983276da39aSCy Schubert } 984276da39aSCy Schubert 985276da39aSCy Schubert /* ------------------------------------------------------------------ */ 986276da39aSCy Schubert /* PPS processing for the secondary channel. GPSD provides us with full 987276da39aSCy Schubert * timing information, so there's no danger of PLL-locking to the wrong 988276da39aSCy Schubert * second. The belts and suspenders needed for the raw ATOM clock are 989276da39aSCy Schubert * unnecessary here. 990276da39aSCy Schubert */ 991276da39aSCy Schubert static void 992276da39aSCy Schubert eval_pps_secondary( 993276da39aSCy Schubert peerT * const peer , 994276da39aSCy Schubert clockprocT * const pp , 995276da39aSCy Schubert gpsd_unitT * const up ) 996276da39aSCy Schubert { 997276da39aSCy Schubert if (up->fl_pps2) { 998276da39aSCy Schubert /* feed data */ 999276da39aSCy Schubert add_clock_sample(peer, pp, up->pps_stamp2, up->pps_recvt2); 1000276da39aSCy Schubert peer->precision = up->pps_prec; 1001276da39aSCy Schubert /* PPS peer flag logic */ 1002276da39aSCy Schubert up->ppscount2 = min(PPS2_MAXCOUNT, (up->ppscount2 + 2)); 1003276da39aSCy Schubert if ((PPS2_MAXCOUNT == up->ppscount2) && 1004276da39aSCy Schubert (pp->sloppyclockflag & CLK_FLAG1) ) 1005276da39aSCy Schubert peer->flags |= FLAG_PPS; 1006276da39aSCy Schubert /* mark time stamp as burned... */ 1007276da39aSCy Schubert up->fl_pps2 = 0; 1008276da39aSCy Schubert ++up->tc_pps_used; 1009276da39aSCy Schubert } 1010276da39aSCy Schubert } 1011276da39aSCy Schubert 1012276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1013276da39aSCy Schubert 1014276da39aSCy Schubert static void 1015276da39aSCy Schubert eval_serial( 1016276da39aSCy Schubert peerT * const peer , 1017276da39aSCy Schubert clockprocT * const pp , 1018276da39aSCy Schubert gpsd_unitT * const up ) 1019276da39aSCy Schubert { 1020276da39aSCy Schubert if (up->fl_sti) { 1021276da39aSCy Schubert add_clock_sample(peer, pp, up->sti_stamp, up->sti_recvt); 1022276da39aSCy Schubert peer->precision = up->sti_prec; 1023276da39aSCy Schubert /* mark time stamp as burned... */ 1024276da39aSCy Schubert up->fl_sti = 0; 1025276da39aSCy Schubert ++up->tc_sti_used; 1026276da39aSCy Schubert } 1027276da39aSCy Schubert } 1028276da39aSCy Schubert 1029276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1030276da39aSCy Schubert static void 1031276da39aSCy Schubert eval_auto( 1032276da39aSCy Schubert peerT * const peer , 1033276da39aSCy Schubert clockprocT * const pp , 1034276da39aSCy Schubert gpsd_unitT * const up ) 1035276da39aSCy Schubert { 1036276da39aSCy Schubert /* If there's no TPV available, stop working here... */ 1037276da39aSCy Schubert if (!up->fl_sti) 1038276da39aSCy Schubert return; 1039276da39aSCy Schubert 1040276da39aSCy Schubert /* check how to handle STI+PPS: Can PPS be used to augment STI 1041276da39aSCy Schubert * (or vice versae), do we drop the sample because there is a 1042276da39aSCy Schubert * temporary missing PPS signal, or do we feed on STI time 1043276da39aSCy Schubert * stamps alone? 1044276da39aSCy Schubert * 1045276da39aSCy Schubert * Do a counter/threshold dance to decide how to proceed. 1046276da39aSCy Schubert */ 1047276da39aSCy Schubert if (up->fl_pps) { 1048276da39aSCy Schubert up->ppscount = min(PPS_MAXCOUNT, 1049276da39aSCy Schubert (up->ppscount + PPS_INCCOUNT)); 1050276da39aSCy Schubert if ((PPS_MAXCOUNT == up->ppscount) && up->fl_rawsti) { 1051276da39aSCy Schubert up->fl_rawsti = 0; 1052276da39aSCy Schubert msyslog(LOG_INFO, 1053276da39aSCy Schubert "%s: expect valid PPS from now", 1054276da39aSCy Schubert up->logname); 1055276da39aSCy Schubert } 1056276da39aSCy Schubert } else { 1057276da39aSCy Schubert up->ppscount = max(0, (up->ppscount - PPS_DECCOUNT)); 1058276da39aSCy Schubert if ((0 == up->ppscount) && !up->fl_rawsti) { 1059276da39aSCy Schubert up->fl_rawsti = -1; 1060276da39aSCy Schubert msyslog(LOG_WARNING, 1061276da39aSCy Schubert "%s: use TPV alone from now", 1062276da39aSCy Schubert up->logname); 1063276da39aSCy Schubert } 1064276da39aSCy Schubert } 1065276da39aSCy Schubert 1066276da39aSCy Schubert /* now eventually feed the sample */ 1067276da39aSCy Schubert if (up->fl_rawsti) 1068276da39aSCy Schubert eval_serial(peer, pp, up); 1069276da39aSCy Schubert else 1070276da39aSCy Schubert eval_strict(peer, pp, up); 1071276da39aSCy Schubert } 10722b15cb3dSCy Schubert 10732b15cb3dSCy Schubert /* ===================================================================== 10742b15cb3dSCy Schubert * JSON parsing stuff 10752b15cb3dSCy Schubert */ 10762b15cb3dSCy Schubert 1077276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1078276da39aSCy Schubert /* Parse a decimal integer with a possible sign. Works like 'strtoll()' 1079276da39aSCy Schubert * or 'strtol()', but with a fixed base of 10 and without eating away 1080276da39aSCy Schubert * leading whitespace. For the error codes, the handling of the end 1081276da39aSCy Schubert * pointer and the return values see 'strtol()'. 1082276da39aSCy Schubert */ 1083276da39aSCy Schubert static json_int 1084276da39aSCy Schubert strtojint( 1085276da39aSCy Schubert const char *cp, char **ep) 1086276da39aSCy Schubert { 1087276da39aSCy Schubert json_uint accu, limit_lo, limit_hi; 1088276da39aSCy Schubert int flags; /* bit 0: overflow; bit 1: sign */ 1089276da39aSCy Schubert const char * hold; 10902b15cb3dSCy Schubert 1091276da39aSCy Schubert /* pointer union to circumvent a tricky/sticky const issue */ 1092276da39aSCy Schubert union { const char * c; char * v; } vep; 10932b15cb3dSCy Schubert 1094276da39aSCy Schubert /* store initial value of 'cp' -- see 'strtol()' */ 1095276da39aSCy Schubert vep.c = cp; 10962b15cb3dSCy Schubert 1097276da39aSCy Schubert /* Eat away an optional sign and set the limits accordingly: The 1098276da39aSCy Schubert * high limit is the maximum absolute value that can be returned, 1099276da39aSCy Schubert * and the low limit is the biggest value that does not cause an 1100276da39aSCy Schubert * overflow when multiplied with 10. Avoid negation overflows. 1101276da39aSCy Schubert */ 1102276da39aSCy Schubert if (*cp == '-') { 1103276da39aSCy Schubert cp += 1; 1104276da39aSCy Schubert flags = 2; 1105276da39aSCy Schubert limit_hi = (json_uint)-(JSON_INT_MIN + 1) + 1; 1106276da39aSCy Schubert } else { 1107276da39aSCy Schubert cp += (*cp == '+'); 1108276da39aSCy Schubert flags = 0; 1109276da39aSCy Schubert limit_hi = (json_uint)JSON_INT_MAX; 1110276da39aSCy Schubert } 1111276da39aSCy Schubert limit_lo = limit_hi / 10; 1112276da39aSCy Schubert 1113276da39aSCy Schubert /* Now try to convert a sequence of digits. */ 1114276da39aSCy Schubert hold = cp; 1115276da39aSCy Schubert accu = 0; 1116*9034852cSGleb Smirnoff while (isdigit(*(const u_char*)cp)) { 1117276da39aSCy Schubert flags |= (accu > limit_lo); 1118*9034852cSGleb Smirnoff accu = accu * 10 + (*(const u_char*)cp++ - '0'); 1119276da39aSCy Schubert flags |= (accu > limit_hi); 1120276da39aSCy Schubert } 1121276da39aSCy Schubert /* Check for empty conversion (no digits seen). */ 1122276da39aSCy Schubert if (hold != cp) 1123276da39aSCy Schubert vep.c = cp; 1124276da39aSCy Schubert else 1125276da39aSCy Schubert errno = EINVAL; /* accu is still zero */ 1126276da39aSCy Schubert /* Check for range overflow */ 1127276da39aSCy Schubert if (flags & 1) { 1128276da39aSCy Schubert errno = ERANGE; 1129276da39aSCy Schubert accu = limit_hi; 1130276da39aSCy Schubert } 1131276da39aSCy Schubert /* If possible, store back the end-of-conversion pointer */ 1132276da39aSCy Schubert if (ep) 1133276da39aSCy Schubert *ep = vep.v; 1134276da39aSCy Schubert /* If negative, return the negated result if the accu is not 1135276da39aSCy Schubert * zero. Avoid negation overflows. 1136276da39aSCy Schubert */ 1137276da39aSCy Schubert if ((flags & 2) && accu) 1138276da39aSCy Schubert return -(json_int)(accu - 1) - 1; 1139276da39aSCy Schubert else 1140276da39aSCy Schubert return (json_int)accu; 1141276da39aSCy Schubert } 11422b15cb3dSCy Schubert 11432b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 11442b15cb3dSCy Schubert 11452b15cb3dSCy Schubert static tok_ref 11462b15cb3dSCy Schubert json_token_skip( 11472b15cb3dSCy Schubert const json_ctx * ctx, 11482b15cb3dSCy Schubert tok_ref tid) 11492b15cb3dSCy Schubert { 1150276da39aSCy Schubert if (tid >= 0 && tid < ctx->ntok) { 1151276da39aSCy Schubert int len = ctx->tok[tid].size; 1152276da39aSCy Schubert /* For arrays and objects, the size is the number of 1153276da39aSCy Schubert * ITEMS in the compound. Thats the number of objects in 1154276da39aSCy Schubert * the array, and the number of key/value pairs for 1155276da39aSCy Schubert * objects. In theory, the key must be a string, and we 1156276da39aSCy Schubert * could simply skip one token before skipping the 1157276da39aSCy Schubert * value, which can be anything. We're a bit paranoid 1158276da39aSCy Schubert * and lazy at the same time: We simply double the 1159276da39aSCy Schubert * number of tokens to skip and fall through into the 1160276da39aSCy Schubert * array processing when encountering an object. 1161276da39aSCy Schubert */ 1162276da39aSCy Schubert switch (ctx->tok[tid].type) { 1163276da39aSCy Schubert case JSMN_OBJECT: 1164276da39aSCy Schubert len *= 2; 1165276da39aSCy Schubert /* FALLTHROUGH */ 1166276da39aSCy Schubert case JSMN_ARRAY: 11672b15cb3dSCy Schubert for (++tid; len; --len) 11682b15cb3dSCy Schubert tid = json_token_skip(ctx, tid); 11692b15cb3dSCy Schubert break; 1170276da39aSCy Schubert 1171276da39aSCy Schubert default: 1172276da39aSCy Schubert ++tid; 1173276da39aSCy Schubert break; 1174276da39aSCy Schubert } 1175276da39aSCy Schubert if (tid > ctx->ntok) /* Impossible? Paranoia rulez. */ 11762b15cb3dSCy Schubert tid = ctx->ntok; 1177276da39aSCy Schubert } 11782b15cb3dSCy Schubert return tid; 11792b15cb3dSCy Schubert } 11802b15cb3dSCy Schubert 11812b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 11822b15cb3dSCy Schubert 11832b15cb3dSCy Schubert static int 11842b15cb3dSCy Schubert json_object_lookup( 11852b15cb3dSCy Schubert const json_ctx * ctx , 11862b15cb3dSCy Schubert tok_ref tid , 1187276da39aSCy Schubert const char * key , 1188276da39aSCy Schubert int what) 11892b15cb3dSCy Schubert { 11902b15cb3dSCy Schubert int len; 11912b15cb3dSCy Schubert 1192276da39aSCy Schubert if (tid < 0 || tid >= ctx->ntok || 1193276da39aSCy Schubert ctx->tok[tid].type != JSMN_OBJECT) 11942b15cb3dSCy Schubert return INVALID_TOKEN; 1195276da39aSCy Schubert 11962b15cb3dSCy Schubert len = ctx->tok[tid].size; 1197276da39aSCy Schubert for (++tid; len && tid+1 < ctx->ntok; --len) { 1198276da39aSCy Schubert if (ctx->tok[tid].type != JSMN_STRING) { /* Blooper! */ 1199276da39aSCy Schubert tid = json_token_skip(ctx, tid); /* skip key */ 1200276da39aSCy Schubert tid = json_token_skip(ctx, tid); /* skip val */ 1201276da39aSCy Schubert } else if (strcmp(key, ctx->buf + ctx->tok[tid].start)) { 1202276da39aSCy Schubert tid = json_token_skip(ctx, tid+1); /* skip key+val */ 1203276da39aSCy Schubert } else if (what < 0 || what == ctx->tok[tid+1].type) { 12042b15cb3dSCy Schubert return tid + 1; 1205276da39aSCy Schubert } else { 1206276da39aSCy Schubert break; 1207276da39aSCy Schubert } 1208276da39aSCy Schubert /* if skipping ahead returned an error, bail out here. */ 1209276da39aSCy Schubert if (tid < 0) 1210276da39aSCy Schubert break; 12112b15cb3dSCy Schubert } 12122b15cb3dSCy Schubert return INVALID_TOKEN; 12132b15cb3dSCy Schubert } 12142b15cb3dSCy Schubert 12152b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 12162b15cb3dSCy Schubert 1217276da39aSCy Schubert static const char* 1218276da39aSCy Schubert json_object_lookup_primitive( 1219276da39aSCy Schubert const json_ctx * ctx, 1220276da39aSCy Schubert tok_ref tid, 1221276da39aSCy Schubert const char * key) 1222276da39aSCy Schubert { 1223276da39aSCy Schubert tid = json_object_lookup(ctx, tid, key, JSMN_PRIMITIVE); 1224276da39aSCy Schubert if (INVALID_TOKEN != tid) 1225276da39aSCy Schubert return ctx->buf + ctx->tok[tid].start; 1226276da39aSCy Schubert else 1227276da39aSCy Schubert return NULL; 1228276da39aSCy Schubert } 1229276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1230276da39aSCy Schubert /* look up a boolean value. This essentially returns a tribool: 1231276da39aSCy Schubert * 0->false, 1->true, (-1)->error/undefined 1232276da39aSCy Schubert */ 1233276da39aSCy Schubert static int 1234276da39aSCy Schubert json_object_lookup_bool( 1235276da39aSCy Schubert const json_ctx * ctx, 1236276da39aSCy Schubert tok_ref tid, 1237276da39aSCy Schubert const char * key) 1238276da39aSCy Schubert { 1239276da39aSCy Schubert const char *cp; 1240276da39aSCy Schubert cp = json_object_lookup_primitive(ctx, tid, key); 1241276da39aSCy Schubert switch ( cp ? *cp : '\0') { 1242276da39aSCy Schubert case 't': return 1; 1243276da39aSCy Schubert case 'f': return 0; 1244276da39aSCy Schubert default : return -1; 1245276da39aSCy Schubert } 1246276da39aSCy Schubert } 1247276da39aSCy Schubert 1248276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1249276da39aSCy Schubert 12502b15cb3dSCy Schubert static const char* 12512b15cb3dSCy Schubert json_object_lookup_string( 12522b15cb3dSCy Schubert const json_ctx * ctx, 12532b15cb3dSCy Schubert tok_ref tid, 12542b15cb3dSCy Schubert const char * key) 12552b15cb3dSCy Schubert { 1256276da39aSCy Schubert tid = json_object_lookup(ctx, tid, key, JSMN_STRING); 1257276da39aSCy Schubert if (INVALID_TOKEN != tid) 1258276da39aSCy Schubert return ctx->buf + ctx->tok[tid].start; 12592b15cb3dSCy Schubert return NULL; 12602b15cb3dSCy Schubert } 12612b15cb3dSCy Schubert 12622b15cb3dSCy Schubert static const char* 12632b15cb3dSCy Schubert json_object_lookup_string_default( 12642b15cb3dSCy Schubert const json_ctx * ctx, 12652b15cb3dSCy Schubert tok_ref tid, 12662b15cb3dSCy Schubert const char * key, 12672b15cb3dSCy Schubert const char * def) 12682b15cb3dSCy Schubert { 1269276da39aSCy Schubert tid = json_object_lookup(ctx, tid, key, JSMN_STRING); 1270276da39aSCy Schubert if (INVALID_TOKEN != tid) 1271276da39aSCy Schubert return ctx->buf + ctx->tok[tid].start; 12722b15cb3dSCy Schubert return def; 12732b15cb3dSCy Schubert } 12742b15cb3dSCy Schubert 12752b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 12762b15cb3dSCy Schubert 12772b15cb3dSCy Schubert static json_int 12782b15cb3dSCy Schubert json_object_lookup_int( 12792b15cb3dSCy Schubert const json_ctx * ctx, 12802b15cb3dSCy Schubert tok_ref tid, 12812b15cb3dSCy Schubert const char * key) 12822b15cb3dSCy Schubert { 12832b15cb3dSCy Schubert json_int ret; 1284276da39aSCy Schubert const char * cp; 12852b15cb3dSCy Schubert char * ep; 12862b15cb3dSCy Schubert 1287276da39aSCy Schubert cp = json_object_lookup_primitive(ctx, tid, key); 1288276da39aSCy Schubert if (NULL != cp) { 1289276da39aSCy Schubert ret = strtojint(cp, &ep); 1290276da39aSCy Schubert if (cp != ep && '\0' == *ep) 12912b15cb3dSCy Schubert return ret; 1292276da39aSCy Schubert } else { 12932b15cb3dSCy Schubert errno = EINVAL; 1294276da39aSCy Schubert } 12952b15cb3dSCy Schubert return 0; 12962b15cb3dSCy Schubert } 12972b15cb3dSCy Schubert 12982b15cb3dSCy Schubert static json_int 12992b15cb3dSCy Schubert json_object_lookup_int_default( 13002b15cb3dSCy Schubert const json_ctx * ctx, 13012b15cb3dSCy Schubert tok_ref tid, 13022b15cb3dSCy Schubert const char * key, 13032b15cb3dSCy Schubert json_int def) 13042b15cb3dSCy Schubert { 1305276da39aSCy Schubert json_int ret; 1306276da39aSCy Schubert const char * cp; 1307276da39aSCy Schubert char * ep; 13082b15cb3dSCy Schubert 1309276da39aSCy Schubert cp = json_object_lookup_primitive(ctx, tid, key); 1310276da39aSCy Schubert if (NULL != cp) { 1311276da39aSCy Schubert ret = strtojint(cp, &ep); 1312276da39aSCy Schubert if (cp != ep && '\0' == *ep) 1313276da39aSCy Schubert return ret; 1314276da39aSCy Schubert } 1315276da39aSCy Schubert return def; 13162b15cb3dSCy Schubert } 13172b15cb3dSCy Schubert 13182b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 1319276da39aSCy Schubert #if 0 /* currently unused */ 13202b15cb3dSCy Schubert static double 13212b15cb3dSCy Schubert json_object_lookup_float( 13222b15cb3dSCy Schubert const json_ctx * ctx, 13232b15cb3dSCy Schubert tok_ref tid, 13242b15cb3dSCy Schubert const char * key) 13252b15cb3dSCy Schubert { 13262b15cb3dSCy Schubert double ret; 1327276da39aSCy Schubert const char * cp; 13282b15cb3dSCy Schubert char * ep; 13292b15cb3dSCy Schubert 1330276da39aSCy Schubert cp = json_object_lookup_primitive(ctx, tid, key); 1331276da39aSCy Schubert if (NULL != cp) { 1332276da39aSCy Schubert ret = strtod(cp, &ep); 1333276da39aSCy Schubert if (cp != ep && '\0' == *ep) 13342b15cb3dSCy Schubert return ret; 1335276da39aSCy Schubert } else { 13362b15cb3dSCy Schubert errno = EINVAL; 1337276da39aSCy Schubert } 13382b15cb3dSCy Schubert return 0.0; 13392b15cb3dSCy Schubert } 1340276da39aSCy Schubert #endif 13412b15cb3dSCy Schubert 13422b15cb3dSCy Schubert static double 13432b15cb3dSCy Schubert json_object_lookup_float_default( 13442b15cb3dSCy Schubert const json_ctx * ctx, 13452b15cb3dSCy Schubert tok_ref tid, 13462b15cb3dSCy Schubert const char * key, 13472b15cb3dSCy Schubert double def) 13482b15cb3dSCy Schubert { 1349276da39aSCy Schubert double ret; 1350276da39aSCy Schubert const char * cp; 1351276da39aSCy Schubert char * ep; 13522b15cb3dSCy Schubert 1353276da39aSCy Schubert cp = json_object_lookup_primitive(ctx, tid, key); 1354276da39aSCy Schubert if (NULL != cp) { 1355276da39aSCy Schubert ret = strtod(cp, &ep); 1356276da39aSCy Schubert if (cp != ep && '\0' == *ep) 1357276da39aSCy Schubert return ret; 1358276da39aSCy Schubert } 1359276da39aSCy Schubert return def; 13602b15cb3dSCy Schubert } 13612b15cb3dSCy Schubert 13622b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 13632b15cb3dSCy Schubert 13642b15cb3dSCy Schubert static BOOL 13652b15cb3dSCy Schubert json_parse_record( 13662b15cb3dSCy Schubert json_ctx * ctx, 1367276da39aSCy Schubert char * buf, 1368276da39aSCy Schubert size_t len) 13692b15cb3dSCy Schubert { 13702b15cb3dSCy Schubert jsmn_parser jsm; 13712b15cb3dSCy Schubert int idx, rc; 13722b15cb3dSCy Schubert 13732b15cb3dSCy Schubert jsmn_init(&jsm); 1374276da39aSCy Schubert rc = jsmn_parse(&jsm, buf, len, ctx->tok, JSMN_MAXTOK); 1375276da39aSCy Schubert if (rc <= 0) 1376276da39aSCy Schubert return FALSE; 13772b15cb3dSCy Schubert ctx->buf = buf; 1378276da39aSCy Schubert ctx->ntok = rc; 1379276da39aSCy Schubert 1380276da39aSCy Schubert if (JSMN_OBJECT != ctx->tok[0].type) 1381276da39aSCy Schubert return FALSE; /* not object!?! */ 13822b15cb3dSCy Schubert 13832b15cb3dSCy Schubert /* Make all tokens NUL terminated by overwriting the 1384276da39aSCy Schubert * terminator symbol. Makes string compares and number parsing a 1385276da39aSCy Schubert * lot easier! 13862b15cb3dSCy Schubert */ 1387276da39aSCy Schubert for (idx = 0; idx < ctx->ntok; ++idx) 13882b15cb3dSCy Schubert if (ctx->tok[idx].end > ctx->tok[idx].start) 13892b15cb3dSCy Schubert ctx->buf[ctx->tok[idx].end] = '\0'; 13902b15cb3dSCy Schubert return TRUE; 13912b15cb3dSCy Schubert } 13922b15cb3dSCy Schubert 13932b15cb3dSCy Schubert 13942b15cb3dSCy Schubert /* ===================================================================== 13952b15cb3dSCy Schubert * static local helpers 13962b15cb3dSCy Schubert */ 1397276da39aSCy Schubert static BOOL 1398276da39aSCy Schubert get_binary_time( 1399276da39aSCy Schubert l_fp * const dest , 1400276da39aSCy Schubert json_ctx * const jctx , 1401276da39aSCy Schubert const char * const time_name, 1402276da39aSCy Schubert const char * const frac_name, 1403276da39aSCy Schubert long fscale ) 1404276da39aSCy Schubert { 1405276da39aSCy Schubert BOOL retv = FALSE; 1406276da39aSCy Schubert struct timespec ts; 1407276da39aSCy Schubert 1408276da39aSCy Schubert errno = 0; 1409276da39aSCy Schubert ts.tv_sec = (time_t)json_object_lookup_int(jctx, 0, time_name); 1410276da39aSCy Schubert ts.tv_nsec = (long )json_object_lookup_int(jctx, 0, frac_name); 1411276da39aSCy Schubert if (0 == errno) { 1412276da39aSCy Schubert ts.tv_nsec *= fscale; 1413276da39aSCy Schubert *dest = tspec_stamp_to_lfp(ts); 1414276da39aSCy Schubert retv = TRUE; 1415276da39aSCy Schubert } 1416276da39aSCy Schubert return retv; 1417276da39aSCy Schubert } 14182b15cb3dSCy Schubert 14192b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 14202b15cb3dSCy Schubert /* Process a WATCH record 14212b15cb3dSCy Schubert * 14222b15cb3dSCy Schubert * Currently this is only used to recognise that the device is present 14232b15cb3dSCy Schubert * and that we're listed subscribers. 14242b15cb3dSCy Schubert */ 14252b15cb3dSCy Schubert static void 14262b15cb3dSCy Schubert process_watch( 14272b15cb3dSCy Schubert peerT * const peer , 14282b15cb3dSCy Schubert json_ctx * const jctx , 14292b15cb3dSCy Schubert const l_fp * const rtime) 14302b15cb3dSCy Schubert { 14312b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 14322b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 14332b15cb3dSCy Schubert 1434276da39aSCy Schubert const char * path; 1435276da39aSCy Schubert 1436276da39aSCy Schubert path = json_object_lookup_string(jctx, 0, "device"); 1437276da39aSCy Schubert if (NULL == path || strcmp(path, up->device)) 1438276da39aSCy Schubert return; 1439276da39aSCy Schubert 1440276da39aSCy Schubert if (json_object_lookup_bool(jctx, 0, "enable") > 0 && 1441276da39aSCy Schubert json_object_lookup_bool(jctx, 0, "json" ) > 0 ) 14422b15cb3dSCy Schubert up->fl_watch = -1; 1443276da39aSCy Schubert else 1444276da39aSCy Schubert up->fl_watch = 0; 1445276da39aSCy Schubert DPRINTF(2, ("%s: process_watch, enabled=%d\n", 1446276da39aSCy Schubert up->logname, (up->fl_watch & 1))); 14472b15cb3dSCy Schubert } 14482b15cb3dSCy Schubert 14492b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 14502b15cb3dSCy Schubert 14512b15cb3dSCy Schubert static void 14522b15cb3dSCy Schubert process_version( 14532b15cb3dSCy Schubert peerT * const peer , 14542b15cb3dSCy Schubert json_ctx * const jctx , 14552b15cb3dSCy Schubert const l_fp * const rtime) 14562b15cb3dSCy Schubert { 14572b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 14582b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 14592b15cb3dSCy Schubert 14602b15cb3dSCy Schubert int len; 14612b15cb3dSCy Schubert char * buf; 14622b15cb3dSCy Schubert const char *revision; 14632b15cb3dSCy Schubert const char *release; 1464276da39aSCy Schubert uint16_t pvhi, pvlo; 14652b15cb3dSCy Schubert 14662b15cb3dSCy Schubert /* get protocol version number */ 14672b15cb3dSCy Schubert revision = json_object_lookup_string_default( 14682b15cb3dSCy Schubert jctx, 0, "rev", "(unknown)"); 14692b15cb3dSCy Schubert release = json_object_lookup_string_default( 14702b15cb3dSCy Schubert jctx, 0, "release", "(unknown)"); 14712b15cb3dSCy Schubert errno = 0; 1472276da39aSCy Schubert pvhi = (uint16_t)json_object_lookup_int(jctx, 0, "proto_major"); 1473276da39aSCy Schubert pvlo = (uint16_t)json_object_lookup_int(jctx, 0, "proto_minor"); 1474276da39aSCy Schubert 14752b15cb3dSCy Schubert if (0 == errno) { 1476276da39aSCy Schubert if ( ! up->fl_vers) 14772b15cb3dSCy Schubert msyslog(LOG_INFO, 14782b15cb3dSCy Schubert "%s: GPSD revision=%s release=%s protocol=%u.%u", 1479276da39aSCy Schubert up->logname, revision, release, 1480276da39aSCy Schubert pvhi, pvlo); 1481276da39aSCy Schubert up->proto_version = PROTO_VERSION(pvhi, pvlo); 1482276da39aSCy Schubert up->fl_vers = -1; 1483276da39aSCy Schubert } else { 1484276da39aSCy Schubert if (syslogok(pp, up)) 1485276da39aSCy Schubert msyslog(LOG_INFO, 1486276da39aSCy Schubert "%s: could not evaluate version data", 1487276da39aSCy Schubert up->logname); 1488276da39aSCy Schubert return; 14892b15cb3dSCy Schubert } 1490276da39aSCy Schubert /* With the 3.9 GPSD protocol, '*_musec' vanished from the PPS 1491276da39aSCy Schubert * record and was replace by '*_nsec'. 14922b15cb3dSCy Schubert */ 1493276da39aSCy Schubert up->pf_nsec = -(up->proto_version >= PROTO_VERSION(3,9)); 14942b15cb3dSCy Schubert 1495276da39aSCy Schubert /* With the 3.10 protocol we can get TOFF records for better 1496276da39aSCy Schubert * timing information. 1497276da39aSCy Schubert */ 1498276da39aSCy Schubert up->pf_toff = -(up->proto_version >= PROTO_VERSION(3,10)); 14992b15cb3dSCy Schubert 1500276da39aSCy Schubert /* request watch for our GPS device if not yet watched. 1501276da39aSCy Schubert * 1502276da39aSCy Schubert * The version string is also sent as a life signal, if we have 1503276da39aSCy Schubert * seen useable data. So if we're already watching the device, 1504276da39aSCy Schubert * skip the request. 1505276da39aSCy Schubert * 15062b15cb3dSCy Schubert * Reuse the input buffer, which is no longer needed in the 15072b15cb3dSCy Schubert * current cycle. Also assume that we can write the watch 15082b15cb3dSCy Schubert * request in one sweep into the socket; since we do not do 15092b15cb3dSCy Schubert * output otherwise, this should always work. (Unless the 15102b15cb3dSCy Schubert * TCP/IP window size gets lower than the length of the 15112b15cb3dSCy Schubert * request. We handle that when it happens.) 15122b15cb3dSCy Schubert */ 1513276da39aSCy Schubert if (up->fl_watch) 1514276da39aSCy Schubert return; 1515276da39aSCy Schubert 15162b15cb3dSCy Schubert snprintf(up->buffer, sizeof(up->buffer), 1517276da39aSCy Schubert s_req_watch[up->pf_toff != 0], up->device); 15182b15cb3dSCy Schubert buf = up->buffer; 15192b15cb3dSCy Schubert len = strlen(buf); 1520276da39aSCy Schubert log_data(peer, "send", buf, len); 1521276da39aSCy Schubert if (len != write(pp->io.fd, buf, len) && (syslogok(pp, up))) { 15222b15cb3dSCy Schubert /* Note: if the server fails to read our request, the 15232b15cb3dSCy Schubert * resulting data timeout will take care of the 15242b15cb3dSCy Schubert * connection! 15252b15cb3dSCy Schubert */ 1526276da39aSCy Schubert msyslog(LOG_ERR, "%s: failed to write watch request (%m)", 1527276da39aSCy Schubert up->logname); 15282b15cb3dSCy Schubert } 15292b15cb3dSCy Schubert } 15302b15cb3dSCy Schubert 15312b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 15322b15cb3dSCy Schubert 15332b15cb3dSCy Schubert static void 15342b15cb3dSCy Schubert process_tpv( 15352b15cb3dSCy Schubert peerT * const peer , 15362b15cb3dSCy Schubert json_ctx * const jctx , 15372b15cb3dSCy Schubert const l_fp * const rtime) 15382b15cb3dSCy Schubert { 15392b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 15402b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 15412b15cb3dSCy Schubert 15422b15cb3dSCy Schubert const char * gps_time; 15432b15cb3dSCy Schubert int gps_mode; 1544276da39aSCy Schubert double ept; 15452b15cb3dSCy Schubert int xlog2; 15462b15cb3dSCy Schubert 15472b15cb3dSCy Schubert gps_mode = (int)json_object_lookup_int_default( 15482b15cb3dSCy Schubert jctx, 0, "mode", 0); 15492b15cb3dSCy Schubert 1550276da39aSCy Schubert gps_time = json_object_lookup_string( 1551276da39aSCy Schubert jctx, 0, "time"); 15522b15cb3dSCy Schubert 1553276da39aSCy Schubert /* accept time stamps only in 2d or 3d fix */ 1554276da39aSCy Schubert if (gps_mode < 2 || NULL == gps_time) { 15552b15cb3dSCy Schubert /* receiver has no fix; tell about and avoid stale data */ 1556276da39aSCy Schubert if ( ! up->pf_toff) 1557276da39aSCy Schubert ++up->tc_sti_recv; 1558276da39aSCy Schubert ++up->tc_nosync; 1559276da39aSCy Schubert up->fl_sti = 0; 15602b15cb3dSCy Schubert up->fl_pps = 0; 1561276da39aSCy Schubert up->fl_nosync = -1; 15622b15cb3dSCy Schubert return; 15632b15cb3dSCy Schubert } 1564276da39aSCy Schubert up->fl_nosync = 0; 15652b15cb3dSCy Schubert 1566276da39aSCy Schubert /* convert clock and set resulting ref time, but only if the 1567276da39aSCy Schubert * TOFF sentence is *not* available 1568276da39aSCy Schubert */ 1569276da39aSCy Schubert if ( ! up->pf_toff) { 1570276da39aSCy Schubert ++up->tc_sti_recv; 15712b15cb3dSCy Schubert /* save last time code to clock data */ 15722b15cb3dSCy Schubert save_ltc(pp, gps_time); 1573276da39aSCy Schubert /* now parse the time string */ 1574276da39aSCy Schubert if (convert_ascii_time(&up->sti_stamp, gps_time)) { 1575276da39aSCy Schubert DPRINTF(2, ("%s: process_tpv, stamp='%s'," 1576276da39aSCy Schubert " recvt='%s' mode=%u\n", 1577276da39aSCy Schubert up->logname, 1578276da39aSCy Schubert gmprettydate(&up->sti_stamp), 1579276da39aSCy Schubert gmprettydate(&up->sti_recvt), 15802b15cb3dSCy Schubert gps_mode)); 15812b15cb3dSCy Schubert 1582276da39aSCy Schubert /* have to use local receive time as substitute 1583276da39aSCy Schubert * for the real receive time: TPV does not tell 1584276da39aSCy Schubert * us. 1585276da39aSCy Schubert */ 1586276da39aSCy Schubert up->sti_local = *rtime; 1587276da39aSCy Schubert up->sti_recvt = *rtime; 1588276da39aSCy Schubert L_SUB(&up->sti_recvt, &up->sti_fudge); 1589276da39aSCy Schubert up->fl_sti = -1; 15902b15cb3dSCy Schubert } else { 1591276da39aSCy Schubert ++up->tc_breply; 1592276da39aSCy Schubert up->fl_sti = 0; 1593276da39aSCy Schubert } 15942b15cb3dSCy Schubert } 15952b15cb3dSCy Schubert 15962b15cb3dSCy Schubert /* Set the precision from the GPSD data 1597276da39aSCy Schubert * Use the ETP field for an estimation of the precision of the 1598276da39aSCy Schubert * serial data. If ETP is not available, use the default serial 1599276da39aSCy Schubert * data presion instead. (Note: The PPS branch has a different 1600276da39aSCy Schubert * precision estimation, since it gets the proper value directly 1601276da39aSCy Schubert * from GPSD!) 16022b15cb3dSCy Schubert */ 1603276da39aSCy Schubert ept = json_object_lookup_float_default(jctx, 0, "ept", 2.0e-3); 1604276da39aSCy Schubert ept = frexp(fabs(ept)*0.70710678, &xlog2); /* ~ sqrt(0.5) */ 1605276da39aSCy Schubert if (ept < 0.25) 1606276da39aSCy Schubert xlog2 = INT_MIN; 1607276da39aSCy Schubert if (ept > 2.0) 1608276da39aSCy Schubert xlog2 = INT_MAX; 1609276da39aSCy Schubert up->sti_prec = clamped_precision(xlog2); 16102b15cb3dSCy Schubert } 16112b15cb3dSCy Schubert 16122b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 16132b15cb3dSCy Schubert 16142b15cb3dSCy Schubert static void 16152b15cb3dSCy Schubert process_pps( 16162b15cb3dSCy Schubert peerT * const peer , 16172b15cb3dSCy Schubert json_ctx * const jctx , 16182b15cb3dSCy Schubert const l_fp * const rtime) 16192b15cb3dSCy Schubert { 16202b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 16212b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 16222b15cb3dSCy Schubert 1623276da39aSCy Schubert int xlog2; 16242b15cb3dSCy Schubert 1625276da39aSCy Schubert ++up->tc_pps_recv; 16262b15cb3dSCy Schubert 1627276da39aSCy Schubert /* Bail out if there's indication that time sync is bad or 1628276da39aSCy Schubert * if we're explicitely requested to ignore PPS data. 1629276da39aSCy Schubert */ 1630276da39aSCy Schubert if (up->fl_nosync) 1631276da39aSCy Schubert return; 16322b15cb3dSCy Schubert 16332b15cb3dSCy Schubert up->pps_local = *rtime; 1634276da39aSCy Schubert /* Now grab the time values. 'clock_*' is the event time of the 1635276da39aSCy Schubert * pulse measured on the local system clock; 'real_*' is the GPS 1636276da39aSCy Schubert * reference time GPSD associated with the pulse. 1637276da39aSCy Schubert */ 1638276da39aSCy Schubert if (up->pf_nsec) { 1639276da39aSCy Schubert if ( ! get_binary_time(&up->pps_recvt2, jctx, 1640276da39aSCy Schubert "clock_sec", "clock_nsec", 1)) 1641276da39aSCy Schubert goto fail; 1642276da39aSCy Schubert if ( ! get_binary_time(&up->pps_stamp2, jctx, 1643276da39aSCy Schubert "real_sec", "real_nsec", 1)) 1644276da39aSCy Schubert goto fail; 1645276da39aSCy Schubert } else { 1646276da39aSCy Schubert if ( ! get_binary_time(&up->pps_recvt2, jctx, 1647276da39aSCy Schubert "clock_sec", "clock_musec", 1000)) 1648276da39aSCy Schubert goto fail; 1649276da39aSCy Schubert if ( ! get_binary_time(&up->pps_stamp2, jctx, 1650276da39aSCy Schubert "real_sec", "real_musec", 1000)) 1651276da39aSCy Schubert goto fail; 1652276da39aSCy Schubert } 16532b15cb3dSCy Schubert 1654276da39aSCy Schubert /* Try to read the precision field from the PPS record. If it's 1655276da39aSCy Schubert * not there, take the precision from the serial data. 1656276da39aSCy Schubert */ 1657276da39aSCy Schubert xlog2 = json_object_lookup_int_default( 1658276da39aSCy Schubert jctx, 0, "precision", up->sti_prec); 1659276da39aSCy Schubert up->pps_prec = clamped_precision(xlog2); 1660276da39aSCy Schubert 1661276da39aSCy Schubert /* Get fudged receive times for primary & secondary unit */ 1662276da39aSCy Schubert up->pps_recvt = up->pps_recvt2; 1663276da39aSCy Schubert L_SUB(&up->pps_recvt , &up->pps_fudge ); 1664276da39aSCy Schubert L_SUB(&up->pps_recvt2, &up->pps_fudge2); 1665276da39aSCy Schubert pp->lastrec = up->pps_recvt; 1666276da39aSCy Schubert 1667276da39aSCy Schubert /* Map to nearest full second as reference time stamp for the 1668276da39aSCy Schubert * primary channel. Sanity checks are done in evaluation step. 1669276da39aSCy Schubert */ 16702b15cb3dSCy Schubert up->pps_stamp = up->pps_recvt; 16712b15cb3dSCy Schubert L_ADDUF(&up->pps_stamp, 0x80000000u); 16722b15cb3dSCy Schubert up->pps_stamp.l_uf = 0; 16732b15cb3dSCy Schubert 1674276da39aSCy Schubert if (NULL != up->pps_peer) 1675276da39aSCy Schubert save_ltc(up->pps_peer->procptr, 1676276da39aSCy Schubert gmprettydate(&up->pps_stamp2)); 1677276da39aSCy Schubert DPRINTF(2, ("%s: PPS record processed," 1678276da39aSCy Schubert " stamp='%s', recvt='%s'\n", 1679276da39aSCy Schubert up->logname, 1680276da39aSCy Schubert gmprettydate(&up->pps_stamp2), 1681276da39aSCy Schubert gmprettydate(&up->pps_recvt2))); 16822b15cb3dSCy Schubert 1683276da39aSCy Schubert up->fl_pps = (0 != (pp->sloppyclockflag & CLK_FLAG2)) - 1; 1684276da39aSCy Schubert up->fl_pps2 = -1; 16852b15cb3dSCy Schubert return; 16862b15cb3dSCy Schubert 16872b15cb3dSCy Schubert fail: 1688276da39aSCy Schubert DPRINTF(1, ("%s: PPS record processing FAILED\n", 1689276da39aSCy Schubert up->logname)); 1690276da39aSCy Schubert ++up->tc_breply; 1691276da39aSCy Schubert } 1692276da39aSCy Schubert 1693276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1694276da39aSCy Schubert 1695276da39aSCy Schubert static void 1696276da39aSCy Schubert process_toff( 1697276da39aSCy Schubert peerT * const peer , 1698276da39aSCy Schubert json_ctx * const jctx , 1699276da39aSCy Schubert const l_fp * const rtime) 1700276da39aSCy Schubert { 1701276da39aSCy Schubert clockprocT * const pp = peer->procptr; 1702276da39aSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 1703276da39aSCy Schubert 1704276da39aSCy Schubert ++up->tc_sti_recv; 1705276da39aSCy Schubert 1706276da39aSCy Schubert /* remember this! */ 1707276da39aSCy Schubert up->pf_toff = -1; 1708276da39aSCy Schubert 1709276da39aSCy Schubert /* bail out if there's indication that time sync is bad */ 1710276da39aSCy Schubert if (up->fl_nosync) 1711276da39aSCy Schubert return; 1712276da39aSCy Schubert 1713276da39aSCy Schubert if ( ! get_binary_time(&up->sti_recvt, jctx, 1714276da39aSCy Schubert "clock_sec", "clock_nsec", 1)) 1715276da39aSCy Schubert goto fail; 1716276da39aSCy Schubert if ( ! get_binary_time(&up->sti_stamp, jctx, 1717276da39aSCy Schubert "real_sec", "real_nsec", 1)) 1718276da39aSCy Schubert goto fail; 1719276da39aSCy Schubert L_SUB(&up->sti_recvt, &up->sti_fudge); 1720276da39aSCy Schubert up->sti_local = *rtime; 1721276da39aSCy Schubert up->fl_sti = -1; 1722276da39aSCy Schubert 1723276da39aSCy Schubert save_ltc(pp, gmprettydate(&up->sti_stamp)); 1724276da39aSCy Schubert DPRINTF(2, ("%s: TOFF record processed," 1725276da39aSCy Schubert " stamp='%s', recvt='%s'\n", 1726276da39aSCy Schubert up->logname, 1727276da39aSCy Schubert gmprettydate(&up->sti_stamp), 1728276da39aSCy Schubert gmprettydate(&up->sti_recvt))); 1729276da39aSCy Schubert return; 1730276da39aSCy Schubert 1731276da39aSCy Schubert fail: 1732276da39aSCy Schubert DPRINTF(1, ("%s: TOFF record processing FAILED\n", 1733276da39aSCy Schubert up->logname)); 1734276da39aSCy Schubert ++up->tc_breply; 17352b15cb3dSCy Schubert } 17362b15cb3dSCy Schubert 17372b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 17382b15cb3dSCy Schubert 17392b15cb3dSCy Schubert static void 17402b15cb3dSCy Schubert gpsd_parse( 17412b15cb3dSCy Schubert peerT * const peer , 17422b15cb3dSCy Schubert const l_fp * const rtime) 17432b15cb3dSCy Schubert { 17442b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 17452b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 17462b15cb3dSCy Schubert 17472b15cb3dSCy Schubert const char * clsid; 17482b15cb3dSCy Schubert 1749276da39aSCy Schubert DPRINTF(2, ("%s: gpsd_parse: time %s '%.*s'\n", 1750276da39aSCy Schubert up->logname, ulfptoa(rtime, 6), 1751276da39aSCy Schubert up->buflen, up->buffer)); 17522b15cb3dSCy Schubert 1753276da39aSCy Schubert /* See if we can grab anything potentially useful. JSMN does not 1754276da39aSCy Schubert * need a trailing NUL, but it needs the number of bytes to 1755276da39aSCy Schubert * process. */ 1756276da39aSCy Schubert if (!json_parse_record(&up->json_parse, up->buffer, up->buflen)) { 1757276da39aSCy Schubert ++up->tc_breply; 17582b15cb3dSCy Schubert return; 1759276da39aSCy Schubert } 17602b15cb3dSCy Schubert 17612b15cb3dSCy Schubert /* Now dispatch over the objects we know */ 1762276da39aSCy Schubert clsid = json_object_lookup_string(&up->json_parse, 0, "class"); 1763276da39aSCy Schubert if (NULL == clsid) { 1764276da39aSCy Schubert ++up->tc_breply; 1765276da39aSCy Schubert return; 1766276da39aSCy Schubert } 17672b15cb3dSCy Schubert 1768276da39aSCy Schubert if (!strcmp("TPV", clsid)) 1769276da39aSCy Schubert process_tpv(peer, &up->json_parse, rtime); 17702b15cb3dSCy Schubert else if (!strcmp("PPS", clsid)) 1771276da39aSCy Schubert process_pps(peer, &up->json_parse, rtime); 1772276da39aSCy Schubert else if (!strcmp("TOFF", clsid)) 1773276da39aSCy Schubert process_toff(peer, &up->json_parse, rtime); 1774276da39aSCy Schubert else if (!strcmp("VERSION", clsid)) 1775276da39aSCy Schubert process_version(peer, &up->json_parse, rtime); 17762b15cb3dSCy Schubert else if (!strcmp("WATCH", clsid)) 1777276da39aSCy Schubert process_watch(peer, &up->json_parse, rtime); 17782b15cb3dSCy Schubert else 17792b15cb3dSCy Schubert return; /* nothing we know about... */ 1780276da39aSCy Schubert ++up->tc_recv; 17812b15cb3dSCy Schubert 1782276da39aSCy Schubert /* if possible, feed the PPS side channel */ 1783276da39aSCy Schubert if (up->pps_peer) 1784276da39aSCy Schubert eval_pps_secondary( 1785276da39aSCy Schubert up->pps_peer, up->pps_peer->procptr, up); 17862b15cb3dSCy Schubert 1787276da39aSCy Schubert /* check PPS vs. STI receive times: 1788276da39aSCy Schubert * If STI is before PPS, then clearly the STI is too old. If PPS 1789276da39aSCy Schubert * is before STI by more than one second, then PPS is too old. 1790276da39aSCy Schubert * Weed out stale time stamps & flags. 1791276da39aSCy Schubert */ 1792276da39aSCy Schubert if (up->fl_pps && up->fl_sti) { 1793276da39aSCy Schubert l_fp diff; 1794276da39aSCy Schubert diff = up->sti_local; 1795276da39aSCy Schubert L_SUB(&diff, &up->pps_local); 1796276da39aSCy Schubert if (diff.l_i > 0) 1797276da39aSCy Schubert up->fl_pps = 0; /* pps too old */ 1798276da39aSCy Schubert else if (diff.l_i < 0) 1799276da39aSCy Schubert up->fl_sti = 0; /* serial data too old */ 18002b15cb3dSCy Schubert } 1801276da39aSCy Schubert 1802276da39aSCy Schubert /* dispatch to the mode-dependent processing functions */ 1803276da39aSCy Schubert switch (up->mode) { 1804276da39aSCy Schubert default: 1805276da39aSCy Schubert case MODE_OP_STI: 1806276da39aSCy Schubert eval_serial(peer, pp, up); 1807276da39aSCy Schubert break; 1808276da39aSCy Schubert 1809276da39aSCy Schubert case MODE_OP_STRICT: 1810276da39aSCy Schubert eval_strict(peer, pp, up); 1811276da39aSCy Schubert break; 1812276da39aSCy Schubert 1813276da39aSCy Schubert case MODE_OP_AUTO: 1814276da39aSCy Schubert eval_auto(peer, pp, up); 1815276da39aSCy Schubert break; 18162b15cb3dSCy Schubert } 18172b15cb3dSCy Schubert } 18182b15cb3dSCy Schubert 18192b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 18202b15cb3dSCy Schubert 18212b15cb3dSCy Schubert static void 18222b15cb3dSCy Schubert gpsd_stop_socket( 18232b15cb3dSCy Schubert peerT * const peer) 18242b15cb3dSCy Schubert { 18252b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 18262b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 18272b15cb3dSCy Schubert 1828276da39aSCy Schubert if (-1 != pp->io.fd) { 18292b15cb3dSCy Schubert if (syslogok(pp, up)) 18302b15cb3dSCy Schubert msyslog(LOG_INFO, 1831276da39aSCy Schubert "%s: closing socket to GPSD, fd=%d", 1832276da39aSCy Schubert up->logname, pp->io.fd); 1833276da39aSCy Schubert else 1834276da39aSCy Schubert DPRINTF(1, ("%s: closing socket to GPSD, fd=%d\n", 1835276da39aSCy Schubert up->logname, pp->io.fd)); 1836276da39aSCy Schubert io_closeclock(&pp->io); 1837276da39aSCy Schubert pp->io.fd = -1; 1838276da39aSCy Schubert } 18392b15cb3dSCy Schubert up->tickover = up->tickpres; 18402b15cb3dSCy Schubert up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH); 18412b15cb3dSCy Schubert up->fl_vers = 0; 1842276da39aSCy Schubert up->fl_sti = 0; 18432b15cb3dSCy Schubert up->fl_pps = 0; 18442b15cb3dSCy Schubert up->fl_watch = 0; 18452b15cb3dSCy Schubert } 18462b15cb3dSCy Schubert 18472b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 18482b15cb3dSCy Schubert 18492b15cb3dSCy Schubert static void 18502b15cb3dSCy Schubert gpsd_init_socket( 18512b15cb3dSCy Schubert peerT * const peer) 18522b15cb3dSCy Schubert { 18532b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 18542b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 18552b15cb3dSCy Schubert addrinfoT * ai; 18562b15cb3dSCy Schubert int rc; 18572b15cb3dSCy Schubert int ov; 18582b15cb3dSCy Schubert 18592b15cb3dSCy Schubert /* draw next address to try */ 18602b15cb3dSCy Schubert if (NULL == up->addr) 18612b15cb3dSCy Schubert up->addr = s_gpsd_addr; 18622b15cb3dSCy Schubert ai = up->addr; 18632b15cb3dSCy Schubert up->addr = ai->ai_next; 18642b15cb3dSCy Schubert 18652b15cb3dSCy Schubert /* try to create a matching socket */ 18662b15cb3dSCy Schubert up->fdt = socket( 18672b15cb3dSCy Schubert ai->ai_family, ai->ai_socktype, ai->ai_protocol); 18682b15cb3dSCy Schubert if (-1 == up->fdt) { 18692b15cb3dSCy Schubert if (syslogok(pp, up)) 18702b15cb3dSCy Schubert msyslog(LOG_ERR, 18712b15cb3dSCy Schubert "%s: cannot create GPSD socket: %m", 1872276da39aSCy Schubert up->logname); 18732b15cb3dSCy Schubert goto no_socket; 18742b15cb3dSCy Schubert } 18752b15cb3dSCy Schubert 1876276da39aSCy Schubert /* Make sure the socket is non-blocking. Connect/reconnect and 1877276da39aSCy Schubert * IO happen in an event-driven environment, and synchronous 1878276da39aSCy Schubert * operations wreak havoc on that. 1879276da39aSCy Schubert */ 18802b15cb3dSCy Schubert rc = fcntl(up->fdt, F_SETFL, O_NONBLOCK, 1); 18812b15cb3dSCy Schubert if (-1 == rc) { 18822b15cb3dSCy Schubert if (syslogok(pp, up)) 18832b15cb3dSCy Schubert msyslog(LOG_ERR, 18842b15cb3dSCy Schubert "%s: cannot set GPSD socket to non-blocking: %m", 1885276da39aSCy Schubert up->logname); 18862b15cb3dSCy Schubert goto no_socket; 18872b15cb3dSCy Schubert } 1888276da39aSCy Schubert /* Disable nagling. The way both GPSD and NTPD handle the 1889276da39aSCy Schubert * protocol makes it record-oriented, and in most cases 1890276da39aSCy Schubert * complete records (JSON serialised objects) will be sent in 1891276da39aSCy Schubert * one sweep. Nagling gives not much advantage but adds another 1892276da39aSCy Schubert * delay, which can worsen the situation for some packets. 1893276da39aSCy Schubert */ 18942b15cb3dSCy Schubert ov = 1; 18952b15cb3dSCy Schubert rc = setsockopt(up->fdt, IPPROTO_TCP, TCP_NODELAY, 18962b15cb3dSCy Schubert (char*)&ov, sizeof(ov)); 18972b15cb3dSCy Schubert if (-1 == rc) { 18982b15cb3dSCy Schubert if (syslogok(pp, up)) 18992b15cb3dSCy Schubert msyslog(LOG_INFO, 19002b15cb3dSCy Schubert "%s: cannot disable TCP nagle: %m", 1901276da39aSCy Schubert up->logname); 19022b15cb3dSCy Schubert } 19032b15cb3dSCy Schubert 1904276da39aSCy Schubert /* Start a non-blocking connect. There might be a synchronous 1905276da39aSCy Schubert * connection result we have to handle. 1906276da39aSCy Schubert */ 19072b15cb3dSCy Schubert rc = connect(up->fdt, ai->ai_addr, ai->ai_addrlen); 1908276da39aSCy Schubert if (-1 == rc) { 1909276da39aSCy Schubert if (errno == EINPROGRESS) { 1910276da39aSCy Schubert DPRINTF(1, ("%s: async connect pending, fd=%d\n", 1911276da39aSCy Schubert up->logname, up->fdt)); 1912276da39aSCy Schubert return; 1913276da39aSCy Schubert } 1914276da39aSCy Schubert 19152b15cb3dSCy Schubert if (syslogok(pp, up)) 19162b15cb3dSCy Schubert msyslog(LOG_ERR, 19172b15cb3dSCy Schubert "%s: cannot connect GPSD socket: %m", 1918276da39aSCy Schubert up->logname); 1919276da39aSCy Schubert goto no_socket; 1920276da39aSCy Schubert } 1921276da39aSCy Schubert 1922276da39aSCy Schubert /* We had a successful synchronous connect, so we add the 1923276da39aSCy Schubert * refclock processing ASAP. We still have to wait for the 1924276da39aSCy Schubert * version string and apply the watch command later on, but we 1925276da39aSCy Schubert * might as well get the show on the road now. 1926276da39aSCy Schubert */ 1927276da39aSCy Schubert DPRINTF(1, ("%s: new socket connection, fd=%d\n", 1928276da39aSCy Schubert up->logname, up->fdt)); 1929276da39aSCy Schubert 1930276da39aSCy Schubert pp->io.fd = up->fdt; 1931276da39aSCy Schubert up->fdt = -1; 1932276da39aSCy Schubert if (0 == io_addclock(&pp->io)) { 1933276da39aSCy Schubert if (syslogok(pp, up)) 1934276da39aSCy Schubert msyslog(LOG_ERR, 1935276da39aSCy Schubert "%s: failed to register with I/O engine", 1936276da39aSCy Schubert up->logname); 19372b15cb3dSCy Schubert goto no_socket; 19382b15cb3dSCy Schubert } 19392b15cb3dSCy Schubert 19402b15cb3dSCy Schubert return; 19412b15cb3dSCy Schubert 19422b15cb3dSCy Schubert no_socket: 1943276da39aSCy Schubert if (-1 != pp->io.fd) 1944276da39aSCy Schubert close(pp->io.fd); 19452b15cb3dSCy Schubert if (-1 != up->fdt) 19462b15cb3dSCy Schubert close(up->fdt); 1947276da39aSCy Schubert pp->io.fd = -1; 19482b15cb3dSCy Schubert up->fdt = -1; 19492b15cb3dSCy Schubert up->tickover = up->tickpres; 19502b15cb3dSCy Schubert up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH); 19512b15cb3dSCy Schubert } 19522b15cb3dSCy Schubert 19532b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 19542b15cb3dSCy Schubert 19552b15cb3dSCy Schubert static void 19562b15cb3dSCy Schubert gpsd_test_socket( 19572b15cb3dSCy Schubert peerT * const peer) 19582b15cb3dSCy Schubert { 19592b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 19602b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 19612b15cb3dSCy Schubert 19622b15cb3dSCy Schubert int ec, rc; 19632b15cb3dSCy Schubert socklen_t lc; 19642b15cb3dSCy Schubert 19652b15cb3dSCy Schubert /* Check if the non-blocking connect was finished by testing the 19662b15cb3dSCy Schubert * socket for writeability. Use the 'poll()' API if available 19672b15cb3dSCy Schubert * and 'select()' otherwise. 19682b15cb3dSCy Schubert */ 1969276da39aSCy Schubert DPRINTF(2, ("%s: check connect, fd=%d\n", 1970276da39aSCy Schubert up->logname, up->fdt)); 19712b15cb3dSCy Schubert 19722b15cb3dSCy Schubert #if defined(HAVE_SYS_POLL_H) 19732b15cb3dSCy Schubert { 19742b15cb3dSCy Schubert struct pollfd pfd; 19752b15cb3dSCy Schubert 19762b15cb3dSCy Schubert pfd.events = POLLOUT; 19772b15cb3dSCy Schubert pfd.fd = up->fdt; 19782b15cb3dSCy Schubert rc = poll(&pfd, 1, 0); 19792b15cb3dSCy Schubert if (1 != rc || !(pfd.revents & POLLOUT)) 19802b15cb3dSCy Schubert return; 19812b15cb3dSCy Schubert } 19822b15cb3dSCy Schubert #elif defined(HAVE_SYS_SELECT_H) 19832b15cb3dSCy Schubert { 19842b15cb3dSCy Schubert struct timeval tout; 19852b15cb3dSCy Schubert fd_set wset; 19862b15cb3dSCy Schubert 19872b15cb3dSCy Schubert memset(&tout, 0, sizeof(tout)); 19882b15cb3dSCy Schubert FD_ZERO(&wset); 19892b15cb3dSCy Schubert FD_SET(up->fdt, &wset); 19902b15cb3dSCy Schubert rc = select(up->fdt+1, NULL, &wset, NULL, &tout); 19912b15cb3dSCy Schubert if (0 == rc || !(FD_ISSET(up->fdt, &wset))) 19922b15cb3dSCy Schubert return; 19932b15cb3dSCy Schubert } 19942b15cb3dSCy Schubert #else 19952b15cb3dSCy Schubert # error Blooper! That should have been found earlier! 19962b15cb3dSCy Schubert #endif 19972b15cb3dSCy Schubert 19982b15cb3dSCy Schubert /* next timeout is a full one... */ 19992b15cb3dSCy Schubert up->tickover = TICKOVER_LOW; 20002b15cb3dSCy Schubert 20012b15cb3dSCy Schubert /* check for socket error */ 20022b15cb3dSCy Schubert ec = 0; 20032b15cb3dSCy Schubert lc = sizeof(ec); 20042b15cb3dSCy Schubert rc = getsockopt(up->fdt, SOL_SOCKET, SO_ERROR, &ec, &lc); 20052b15cb3dSCy Schubert if (-1 == rc || 0 != ec) { 2006276da39aSCy Schubert const char *errtxt; 2007276da39aSCy Schubert if (0 == ec) 2008276da39aSCy Schubert ec = errno; 2009276da39aSCy Schubert errtxt = strerror(ec); 20102b15cb3dSCy Schubert if (syslogok(pp, up)) 20112b15cb3dSCy Schubert msyslog(LOG_ERR, 2012276da39aSCy Schubert "%s: async connect to GPSD failed," 2013276da39aSCy Schubert " fd=%d, ec=%d(%s)", 2014276da39aSCy Schubert up->logname, up->fdt, ec, errtxt); 2015276da39aSCy Schubert else 2016276da39aSCy Schubert DPRINTF(1, ("%s: async connect to GPSD failed," 2017276da39aSCy Schubert " fd=%d, ec=%d(%s)\n", 2018276da39aSCy Schubert up->logname, up->fdt, ec, errtxt)); 20192b15cb3dSCy Schubert goto no_socket; 2020276da39aSCy Schubert } else { 2021276da39aSCy Schubert DPRINTF(1, ("%s: async connect to GPSD succeeded, fd=%d\n", 2022276da39aSCy Schubert up->logname, up->fdt)); 20232b15cb3dSCy Schubert } 2024276da39aSCy Schubert 20252b15cb3dSCy Schubert /* swap socket FDs, and make sure the clock was added */ 20262b15cb3dSCy Schubert pp->io.fd = up->fdt; 20272b15cb3dSCy Schubert up->fdt = -1; 20282b15cb3dSCy Schubert if (0 == io_addclock(&pp->io)) { 20292b15cb3dSCy Schubert if (syslogok(pp, up)) 20302b15cb3dSCy Schubert msyslog(LOG_ERR, 20312b15cb3dSCy Schubert "%s: failed to register with I/O engine", 2032276da39aSCy Schubert up->logname); 20332b15cb3dSCy Schubert goto no_socket; 20342b15cb3dSCy Schubert } 20352b15cb3dSCy Schubert return; 20362b15cb3dSCy Schubert 20372b15cb3dSCy Schubert no_socket: 2038276da39aSCy Schubert if (-1 != up->fdt) { 2039276da39aSCy Schubert DPRINTF(1, ("%s: closing socket, fd=%d\n", 2040276da39aSCy Schubert up->logname, up->fdt)); 20412b15cb3dSCy Schubert close(up->fdt); 2042276da39aSCy Schubert } 20432b15cb3dSCy Schubert up->fdt = -1; 20442b15cb3dSCy Schubert up->tickover = up->tickpres; 20452b15cb3dSCy Schubert up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH); 20462b15cb3dSCy Schubert } 20472b15cb3dSCy Schubert 20482b15cb3dSCy Schubert /* ===================================================================== 20492b15cb3dSCy Schubert * helper stuff 20502b15cb3dSCy Schubert */ 20512b15cb3dSCy Schubert 2052276da39aSCy Schubert /* ------------------------------------------------------------------- 2053276da39aSCy Schubert * store a properly clamped precision value 20542b15cb3dSCy Schubert */ 2055276da39aSCy Schubert static int16_t 2056276da39aSCy Schubert clamped_precision( 2057276da39aSCy Schubert int rawprec) 20582b15cb3dSCy Schubert { 2059276da39aSCy Schubert if (rawprec > 0) 2060276da39aSCy Schubert rawprec = 0; 2061276da39aSCy Schubert if (rawprec < -32) 2062276da39aSCy Schubert rawprec = -32; 2063276da39aSCy Schubert return (int16_t)rawprec; 20642b15cb3dSCy Schubert } 20652b15cb3dSCy Schubert 20662b15cb3dSCy Schubert /* ------------------------------------------------------------------- 2067276da39aSCy Schubert * Convert a GPSD timestamp (ISO8601 Format) to an l_fp 20682b15cb3dSCy Schubert */ 20692b15cb3dSCy Schubert static BOOL 20702b15cb3dSCy Schubert convert_ascii_time( 20712b15cb3dSCy Schubert l_fp * fp , 20722b15cb3dSCy Schubert const char * gps_time) 20732b15cb3dSCy Schubert { 20742b15cb3dSCy Schubert char *ep; 20752b15cb3dSCy Schubert struct tm gd; 20762b15cb3dSCy Schubert struct timespec ts; 2077276da39aSCy Schubert uint32_t dw; 20782b15cb3dSCy Schubert 20792b15cb3dSCy Schubert /* Use 'strptime' to take the brunt of the work, then parse 20802b15cb3dSCy Schubert * the fractional part manually, starting with a digit weight of 20812b15cb3dSCy Schubert * 10^8 nanoseconds. 20822b15cb3dSCy Schubert */ 20832b15cb3dSCy Schubert ts.tv_nsec = 0; 20842b15cb3dSCy Schubert ep = strptime(gps_time, "%Y-%m-%dT%H:%M:%S", &gd); 2085276da39aSCy Schubert if (NULL == ep) 2086276da39aSCy Schubert return FALSE; /* could not parse the mandatory stuff! */ 20872b15cb3dSCy Schubert if (*ep == '.') { 2088276da39aSCy Schubert dw = 100000000u; 2089*9034852cSGleb Smirnoff while (isdigit(*(u_char*)++ep)) { 2090*9034852cSGleb Smirnoff ts.tv_nsec += (*(u_char*)ep - '0') * dw; 2091276da39aSCy Schubert dw /= 10u; 20922b15cb3dSCy Schubert } 20932b15cb3dSCy Schubert } 20942b15cb3dSCy Schubert if (ep[0] != 'Z' || ep[1] != '\0') 2095276da39aSCy Schubert return FALSE; /* trailing garbage */ 20962b15cb3dSCy Schubert 2097276da39aSCy Schubert /* Now convert the whole thing into a 'l_fp'. We do not use 2098276da39aSCy Schubert * 'mkgmtime()' since its not standard and going through the 2099276da39aSCy Schubert * calendar routines is not much effort, either. 2100276da39aSCy Schubert */ 21012b15cb3dSCy Schubert ts.tv_sec = (ntpcal_tm_to_rd(&gd) - DAY_NTP_STARTS) * SECSPERDAY 21022b15cb3dSCy Schubert + ntpcal_tm_to_daysec(&gd); 21032b15cb3dSCy Schubert *fp = tspec_intv_to_lfp(ts); 21042b15cb3dSCy Schubert 21052b15cb3dSCy Schubert return TRUE; 21062b15cb3dSCy Schubert } 21072b15cb3dSCy Schubert 21082b15cb3dSCy Schubert /* ------------------------------------------------------------------- 21092b15cb3dSCy Schubert * Save the last timecode string, making sure it's properly truncated 21102b15cb3dSCy Schubert * if necessary and NUL terminated in any case. 21112b15cb3dSCy Schubert */ 21122b15cb3dSCy Schubert static void 21132b15cb3dSCy Schubert save_ltc( 21142b15cb3dSCy Schubert clockprocT * const pp, 21152b15cb3dSCy Schubert const char * const tc) 21162b15cb3dSCy Schubert { 21172b15cb3dSCy Schubert size_t len; 21182b15cb3dSCy Schubert 21192b15cb3dSCy Schubert len = (tc) ? strlen(tc) : 0; 21202b15cb3dSCy Schubert if (len >= sizeof(pp->a_lastcode)) 21212b15cb3dSCy Schubert len = sizeof(pp->a_lastcode) - 1; 21222b15cb3dSCy Schubert pp->lencode = (u_short)len; 21232b15cb3dSCy Schubert memcpy(pp->a_lastcode, tc, len); 21242b15cb3dSCy Schubert pp->a_lastcode[len] = '\0'; 21252b15cb3dSCy Schubert } 21262b15cb3dSCy Schubert 2127276da39aSCy Schubert /* ------------------------------------------------------------------- 21282b15cb3dSCy Schubert * asprintf replacement... it's not available everywhere... 21292b15cb3dSCy Schubert */ 21302b15cb3dSCy Schubert static int 21312b15cb3dSCy Schubert myasprintf( 21322b15cb3dSCy Schubert char ** spp, 21332b15cb3dSCy Schubert char const * fmt, 21342b15cb3dSCy Schubert ... ) 21352b15cb3dSCy Schubert { 21362b15cb3dSCy Schubert size_t alen, plen; 21372b15cb3dSCy Schubert 21382b15cb3dSCy Schubert alen = 32; 21392b15cb3dSCy Schubert *spp = NULL; 21402b15cb3dSCy Schubert do { 21412b15cb3dSCy Schubert va_list va; 21422b15cb3dSCy Schubert 21432b15cb3dSCy Schubert alen += alen; 21442b15cb3dSCy Schubert free(*spp); 21452b15cb3dSCy Schubert *spp = (char*)malloc(alen); 21462b15cb3dSCy Schubert if (NULL == *spp) 21472b15cb3dSCy Schubert return -1; 21482b15cb3dSCy Schubert 21492b15cb3dSCy Schubert va_start(va, fmt); 21502b15cb3dSCy Schubert plen = (size_t)vsnprintf(*spp, alen, fmt, va); 21512b15cb3dSCy Schubert va_end(va); 21522b15cb3dSCy Schubert } while (plen >= alen); 21532b15cb3dSCy Schubert 21542b15cb3dSCy Schubert return (int)plen; 21552b15cb3dSCy Schubert } 21562b15cb3dSCy Schubert 2157276da39aSCy Schubert /* ------------------------------------------------------------------- 2158276da39aSCy Schubert * dump a raw data buffer 2159276da39aSCy Schubert */ 2160276da39aSCy Schubert 2161276da39aSCy Schubert static char * 2162276da39aSCy Schubert add_string( 2163276da39aSCy Schubert char *dp, 2164276da39aSCy Schubert char *ep, 2165276da39aSCy Schubert const char *sp) 2166276da39aSCy Schubert { 2167276da39aSCy Schubert while (dp != ep && *sp) 2168276da39aSCy Schubert *dp++ = *sp++; 2169276da39aSCy Schubert return dp; 2170276da39aSCy Schubert } 2171276da39aSCy Schubert 2172276da39aSCy Schubert static void 2173276da39aSCy Schubert log_data( 2174276da39aSCy Schubert peerT *peer, 2175276da39aSCy Schubert const char *what, 2176276da39aSCy Schubert const char *buf , 2177276da39aSCy Schubert size_t len ) 2178276da39aSCy Schubert { 2179276da39aSCy Schubert /* we're running single threaded with regards to the clocks. */ 2180276da39aSCy Schubert static char s_lbuf[2048]; 2181276da39aSCy Schubert 2182276da39aSCy Schubert clockprocT * const pp = peer->procptr; 2183276da39aSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 2184276da39aSCy Schubert 2185276da39aSCy Schubert if (debug > 1) { 2186276da39aSCy Schubert const char *sptr = buf; 2187276da39aSCy Schubert const char *stop = buf + len; 2188276da39aSCy Schubert char *dptr = s_lbuf; 2189276da39aSCy Schubert char *dtop = s_lbuf + sizeof(s_lbuf) - 1; /* for NUL */ 2190276da39aSCy Schubert 2191276da39aSCy Schubert while (sptr != stop && dptr != dtop) { 2192*9034852cSGleb Smirnoff u_char uch = (u_char)*sptr++; 2193*9034852cSGleb Smirnoff if (uch == '\\') { 2194276da39aSCy Schubert dptr = add_string(dptr, dtop, "\\\\"); 2195*9034852cSGleb Smirnoff } else if (isprint(uch)) { 2196*9034852cSGleb Smirnoff *dptr++ = (char)uch; 2197276da39aSCy Schubert } else { 2198276da39aSCy Schubert char fbuf[6]; 2199*9034852cSGleb Smirnoff snprintf(fbuf, sizeof(fbuf), "\\%03o", uch); 2200276da39aSCy Schubert dptr = add_string(dptr, dtop, fbuf); 2201276da39aSCy Schubert } 2202276da39aSCy Schubert } 2203276da39aSCy Schubert *dptr = '\0'; 2204276da39aSCy Schubert mprintf("%s[%s]: '%s'\n", up->logname, what, s_lbuf); 2205276da39aSCy Schubert } 2206276da39aSCy Schubert } 2207276da39aSCy Schubert 22082b15cb3dSCy Schubert #else 22092b15cb3dSCy Schubert NONEMPTY_TRANSLATION_UNIT 22102b15cb3dSCy Schubert #endif /* REFCLOCK && CLOCK_GPSDJSON */ 2211