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 380276da39aSCy Schubert static const char * const s_req_version = 381276da39aSCy Schubert "?VERSION;\r\n"; 382276da39aSCy Schubert 383276da39aSCy Schubert /* We keep a static list of network addresses for 'localhost:gpsd' or a 384276da39aSCy Schubert * fallback alias of it, and we try to connect to them in round-robin 385276da39aSCy Schubert * fashion. The service lookup is done during the driver init 386276da39aSCy Schubert * function to minmise the impact of 'getaddrinfo()'. 387276da39aSCy Schubert * 388276da39aSCy Schubert * Alas, the init function is called even if there are no clocks 389276da39aSCy Schubert * configured for this driver. So it makes sense to defer the logging of 390276da39aSCy Schubert * any errors or other notifications until the first clock unit is 391276da39aSCy Schubert * started -- otherwise there might be syslog entries from a driver that 392276da39aSCy Schubert * is not used at all. 3932b15cb3dSCy Schubert */ 3942b15cb3dSCy Schubert static addrinfoT *s_gpsd_addr; 395276da39aSCy Schubert static gpsd_unitT *s_clock_units; 396276da39aSCy Schubert 397276da39aSCy Schubert /* list of service/socket names we want to resolve against */ 398276da39aSCy Schubert static const char * const s_svctab[][2] = { 399276da39aSCy Schubert { "localhost", "gpsd" }, 400276da39aSCy Schubert { "localhost", "2947" }, 401276da39aSCy Schubert { "127.0.0.1", "2947" }, 402276da39aSCy Schubert { NULL, NULL } 403276da39aSCy Schubert }; 404276da39aSCy Schubert 405276da39aSCy Schubert /* list of address resolution errors and index of service entry that 406276da39aSCy Schubert * finally worked. 407276da39aSCy Schubert */ 408276da39aSCy Schubert static int s_svcerr[sizeof(s_svctab)/sizeof(s_svctab[0])]; 409276da39aSCy Schubert static int s_svcidx; 4102b15cb3dSCy Schubert 4112b15cb3dSCy Schubert /* ===================================================================== 4122b15cb3dSCy Schubert * log throttling 4132b15cb3dSCy Schubert */ 4142b15cb3dSCy Schubert static int/*BOOL*/ 4152b15cb3dSCy Schubert syslogok( 4162b15cb3dSCy Schubert clockprocT * const pp, 4172b15cb3dSCy Schubert gpsd_unitT * const up) 4182b15cb3dSCy Schubert { 4192b15cb3dSCy Schubert int res = (0 != (pp->sloppyclockflag & CLK_FLAG3)) 4202b15cb3dSCy Schubert || (0 == up->logthrottle ) 4212b15cb3dSCy Schubert || (LOGTHROTTLE == up->logthrottle ); 4222b15cb3dSCy Schubert if (res) 4232b15cb3dSCy Schubert up->logthrottle = LOGTHROTTLE; 4242b15cb3dSCy Schubert return res; 4252b15cb3dSCy Schubert } 4262b15cb3dSCy Schubert 4272b15cb3dSCy Schubert /* ===================================================================== 4282b15cb3dSCy Schubert * the clock functions 4292b15cb3dSCy Schubert */ 4302b15cb3dSCy Schubert 4312b15cb3dSCy Schubert /* --------------------------------------------------------------------- 4322b15cb3dSCy Schubert * Init: This currently just gets the socket address for the GPS daemon 4332b15cb3dSCy Schubert */ 4342b15cb3dSCy Schubert static void 4352b15cb3dSCy Schubert gpsd_init(void) 4362b15cb3dSCy Schubert { 4372b15cb3dSCy Schubert addrinfoT hints; 438276da39aSCy Schubert int rc, idx; 4392b15cb3dSCy Schubert 440276da39aSCy Schubert memset(s_svcerr, 0, sizeof(s_svcerr)); 4412b15cb3dSCy Schubert memset(&hints, 0, sizeof(hints)); 4422b15cb3dSCy Schubert hints.ai_family = AF_UNSPEC; 4432b15cb3dSCy Schubert hints.ai_protocol = IPPROTO_TCP; 4442b15cb3dSCy Schubert hints.ai_socktype = SOCK_STREAM; 4452b15cb3dSCy Schubert 446276da39aSCy Schubert for (idx = 0; s_svctab[idx][0] && !s_gpsd_addr; idx++) { 447276da39aSCy Schubert rc = getaddrinfo(s_svctab[idx][0], s_svctab[idx][1], 448276da39aSCy Schubert &hints, &s_gpsd_addr); 449276da39aSCy Schubert s_svcerr[idx] = rc; 450276da39aSCy Schubert if (0 == rc) 451276da39aSCy Schubert break; 4522b15cb3dSCy Schubert s_gpsd_addr = NULL; 4532b15cb3dSCy Schubert } 454276da39aSCy Schubert s_svcidx = idx; 455276da39aSCy Schubert } 456276da39aSCy Schubert 457276da39aSCy Schubert /* --------------------------------------------------------------------- 458276da39aSCy Schubert * Init Check: flush pending log messages and check if we can proceed 459276da39aSCy Schubert */ 460276da39aSCy Schubert static int/*BOOL*/ 461276da39aSCy Schubert gpsd_init_check(void) 462276da39aSCy Schubert { 463276da39aSCy Schubert int idx; 464276da39aSCy Schubert 465276da39aSCy Schubert /* Check if there is something to log */ 466276da39aSCy Schubert if (s_svcidx == 0) 467276da39aSCy Schubert return (s_gpsd_addr != NULL); 468276da39aSCy Schubert 469276da39aSCy Schubert /* spool out the resolver errors */ 470276da39aSCy Schubert for (idx = 0; idx < s_svcidx; ++idx) { 471276da39aSCy Schubert msyslog(LOG_WARNING, 472276da39aSCy Schubert "GPSD_JSON: failed to resolve '%s:%s', rc=%d (%s)", 473276da39aSCy Schubert s_svctab[idx][0], s_svctab[idx][1], 474276da39aSCy Schubert s_svcerr[idx], gai_strerror(s_svcerr[idx])); 475276da39aSCy Schubert } 476276da39aSCy Schubert 477276da39aSCy Schubert /* check if it was fatal, or if we can proceed */ 478276da39aSCy Schubert if (s_gpsd_addr == NULL) 479276da39aSCy Schubert msyslog(LOG_ERR, "%s", 480276da39aSCy Schubert "GPSD_JSON: failed to get socket address, giving up."); 481276da39aSCy Schubert else if (idx != 0) 482276da39aSCy Schubert msyslog(LOG_WARNING, 483276da39aSCy Schubert "GPSD_JSON: using '%s:%s' instead of '%s:%s'", 484276da39aSCy Schubert s_svctab[idx][0], s_svctab[idx][1], 485276da39aSCy Schubert s_svctab[0][0], s_svctab[0][1]); 486276da39aSCy Schubert 487276da39aSCy Schubert /* make sure this gets logged only once and tell if we can 488276da39aSCy Schubert * proceed or not 489276da39aSCy Schubert */ 490276da39aSCy Schubert s_svcidx = 0; 491276da39aSCy Schubert return (s_gpsd_addr != NULL); 492276da39aSCy Schubert } 4932b15cb3dSCy Schubert 4942b15cb3dSCy Schubert /* --------------------------------------------------------------------- 4952b15cb3dSCy Schubert * Start: allocate a unit pointer and set up the runtime data 4962b15cb3dSCy Schubert */ 4972b15cb3dSCy Schubert static int 4982b15cb3dSCy Schubert gpsd_start( 4992b15cb3dSCy Schubert int unit, 5002b15cb3dSCy Schubert peerT * peer) 5012b15cb3dSCy Schubert { 5022b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 503276da39aSCy Schubert gpsd_unitT * up; 504276da39aSCy Schubert gpsd_unitT ** uscan = &s_clock_units; 5052b15cb3dSCy Schubert 5062b15cb3dSCy Schubert struct stat sb; 5072b15cb3dSCy Schubert 508276da39aSCy Schubert /* check if we can proceed at all or if init failed */ 509276da39aSCy Schubert if ( ! gpsd_init_check()) 510276da39aSCy Schubert return FALSE; 511276da39aSCy Schubert 512276da39aSCy Schubert /* search for matching unit */ 513276da39aSCy Schubert while ((up = *uscan) != NULL && up->unit != (unit & 0x7F)) 514276da39aSCy Schubert uscan = &up->next_unit; 515276da39aSCy Schubert if (up == NULL) { 516276da39aSCy Schubert /* alloc unit, add to list and increment use count ASAP. */ 517276da39aSCy Schubert up = emalloc_zero(sizeof(*up)); 518276da39aSCy Schubert *uscan = up; 519276da39aSCy Schubert ++up->refcount; 520276da39aSCy Schubert 5212b15cb3dSCy Schubert /* initialize the unit structure */ 522276da39aSCy Schubert up->logname = estrdup(refnumtoa(&peer->srcadr)); 523276da39aSCy Schubert up->unit = unit & 0x7F; 5242b15cb3dSCy Schubert up->fdt = -1; 5252b15cb3dSCy Schubert up->addr = s_gpsd_addr; 5262b15cb3dSCy Schubert up->tickpres = TICKOVER_LOW; 5272b15cb3dSCy Schubert 528276da39aSCy Schubert /* Create the device name and check for a Character 529276da39aSCy Schubert * Device. It's assumed that GPSD was started with the 530276da39aSCy Schubert * same link, so the names match. (If this is not 531276da39aSCy Schubert * practicable, we will have to read the symlink, if 532276da39aSCy Schubert * any, so we can get the true device file.) 533276da39aSCy Schubert */ 534276da39aSCy Schubert if (-1 == myasprintf(&up->device, "%s%u", 535276da39aSCy Schubert s_dev_stem, up->unit)) { 536276da39aSCy Schubert msyslog(LOG_ERR, "%s: clock device name too long", 537276da39aSCy Schubert up->logname); 538276da39aSCy Schubert goto dev_fail; 539276da39aSCy Schubert } 540276da39aSCy Schubert if (-1 == stat(up->device, &sb) || !S_ISCHR(sb.st_mode)) { 541276da39aSCy Schubert msyslog(LOG_ERR, "%s: '%s' is not a character device", 542276da39aSCy Schubert up->logname, up->device); 543276da39aSCy Schubert goto dev_fail; 544276da39aSCy Schubert } 545276da39aSCy Schubert } else { 546276da39aSCy Schubert /* All set up, just increment use count. */ 547276da39aSCy Schubert ++up->refcount; 548276da39aSCy Schubert } 549276da39aSCy Schubert 5502b15cb3dSCy Schubert /* setup refclock processing */ 5512b15cb3dSCy Schubert pp->unitptr = (caddr_t)up; 5522b15cb3dSCy Schubert pp->io.fd = -1; 5532b15cb3dSCy Schubert pp->io.clock_recv = gpsd_receive; 5542b15cb3dSCy Schubert pp->io.srcclock = peer; 5552b15cb3dSCy Schubert pp->io.datalen = 0; 5562b15cb3dSCy Schubert pp->a_lastcode[0] = '\0'; 5572b15cb3dSCy Schubert pp->lencode = 0; 5582b15cb3dSCy Schubert pp->clockdesc = DESCRIPTION; 5592b15cb3dSCy Schubert memcpy(&pp->refid, REFID, 4); 5602b15cb3dSCy Schubert 5612b15cb3dSCy Schubert /* Initialize miscellaneous variables */ 562276da39aSCy Schubert if (unit >= 128) 563276da39aSCy Schubert peer->precision = PPS_PRECISION; 564276da39aSCy Schubert else 5652b15cb3dSCy Schubert peer->precision = PRECISION; 5662b15cb3dSCy Schubert 567276da39aSCy Schubert /* If the daemon name lookup failed, just give up now. */ 568276da39aSCy Schubert if (NULL == up->addr) { 569276da39aSCy Schubert msyslog(LOG_ERR, "%s: no GPSD socket address, giving up", 570276da39aSCy Schubert up->logname); 5712b15cb3dSCy Schubert goto dev_fail; 5722b15cb3dSCy Schubert } 573276da39aSCy Schubert 5742b15cb3dSCy Schubert LOGIF(CLOCKINFO, 5752b15cb3dSCy Schubert (LOG_NOTICE, "%s: startup, device is '%s'", 5762b15cb3dSCy Schubert refnumtoa(&peer->srcadr), up->device)); 577276da39aSCy Schubert up->mode = MODE_OP_MODE(peer->ttl); 578276da39aSCy Schubert if (up->mode > MODE_OP_MAXVAL) 579276da39aSCy Schubert up->mode = 0; 580276da39aSCy Schubert if (unit >= 128) 581276da39aSCy Schubert up->pps_peer = peer; 582276da39aSCy Schubert else 583276da39aSCy Schubert enter_opmode(peer, up->mode); 5842b15cb3dSCy Schubert return TRUE; 5852b15cb3dSCy Schubert 5862b15cb3dSCy Schubert dev_fail: 5872b15cb3dSCy Schubert /* On failure, remove all UNIT ressources and declare defeat. */ 5882b15cb3dSCy Schubert 5892b15cb3dSCy Schubert INSIST (up); 590276da39aSCy Schubert if (!--up->refcount) { 591276da39aSCy Schubert *uscan = up->next_unit; 5922b15cb3dSCy Schubert free(up->device); 5932b15cb3dSCy Schubert free(up); 594276da39aSCy Schubert } 5952b15cb3dSCy Schubert 5962b15cb3dSCy Schubert pp->unitptr = (caddr_t)NULL; 5972b15cb3dSCy Schubert return FALSE; 5982b15cb3dSCy Schubert } 5992b15cb3dSCy Schubert 6002b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 6012b15cb3dSCy Schubert 6022b15cb3dSCy Schubert static void 6032b15cb3dSCy Schubert gpsd_shutdown( 6042b15cb3dSCy Schubert int unit, 6052b15cb3dSCy Schubert peerT * peer) 6062b15cb3dSCy Schubert { 6072b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 6082b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 609276da39aSCy Schubert gpsd_unitT ** uscan = &s_clock_units; 6102b15cb3dSCy Schubert 6112b15cb3dSCy Schubert UNUSED_ARG(unit); 6122b15cb3dSCy Schubert 613276da39aSCy Schubert /* The unit pointer might have been removed already. */ 614276da39aSCy Schubert if (up == NULL) 615276da39aSCy Schubert return; 616276da39aSCy Schubert 617276da39aSCy Schubert /* now check if we must close IO resources */ 618276da39aSCy Schubert if (peer != up->pps_peer) { 619276da39aSCy Schubert if (-1 != pp->io.fd) { 620276da39aSCy Schubert DPRINTF(1, ("%s: closing clock, fd=%d\n", 621276da39aSCy Schubert up->logname, pp->io.fd)); 622276da39aSCy Schubert io_closeclock(&pp->io); 623276da39aSCy Schubert pp->io.fd = -1; 624276da39aSCy Schubert } 625276da39aSCy Schubert if (up->fdt != -1) 626276da39aSCy Schubert close(up->fdt); 627276da39aSCy Schubert } 628276da39aSCy Schubert /* decrement use count and eventually remove this unit. */ 629276da39aSCy Schubert if (!--up->refcount) { 630276da39aSCy Schubert /* unlink this unit */ 631276da39aSCy Schubert while (*uscan != NULL) 632276da39aSCy Schubert if (*uscan == up) 633276da39aSCy Schubert *uscan = up->next_unit; 634276da39aSCy Schubert else 635276da39aSCy Schubert uscan = &(*uscan)->next_unit; 636276da39aSCy Schubert free(up->logname); 6372b15cb3dSCy Schubert free(up->device); 6382b15cb3dSCy Schubert free(up); 6392b15cb3dSCy Schubert } 6402b15cb3dSCy Schubert pp->unitptr = (caddr_t)NULL; 6412b15cb3dSCy Schubert LOGIF(CLOCKINFO, 6422b15cb3dSCy Schubert (LOG_NOTICE, "%s: shutdown", refnumtoa(&peer->srcadr))); 6432b15cb3dSCy Schubert } 6442b15cb3dSCy Schubert 6452b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 6462b15cb3dSCy Schubert 6472b15cb3dSCy Schubert static void 6482b15cb3dSCy Schubert gpsd_receive( 6492b15cb3dSCy Schubert struct recvbuf * rbufp) 6502b15cb3dSCy Schubert { 6512b15cb3dSCy Schubert /* declare & init control structure ptrs */ 6522b15cb3dSCy Schubert peerT * const peer = rbufp->recv_peer; 6532b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 6542b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 6552b15cb3dSCy Schubert 6562b15cb3dSCy Schubert const char *psrc, *esrc; 6572b15cb3dSCy Schubert char *pdst, *edst, ch; 6582b15cb3dSCy Schubert 659276da39aSCy Schubert /* log the data stream, if this is enabled */ 660276da39aSCy Schubert log_data(peer, "recv", (const char*)rbufp->recv_buffer, 661276da39aSCy Schubert (size_t)rbufp->recv_length); 662276da39aSCy Schubert 663276da39aSCy Schubert 6642b15cb3dSCy Schubert /* Since we're getting a raw stream data, we must assemble lines 6652b15cb3dSCy Schubert * in our receive buffer. We can't use neither 'refclock_gtraw' 6662b15cb3dSCy Schubert * not 'refclock_gtlin' here... We process chars until we reach 6672b15cb3dSCy Schubert * an EoL (that is, line feed) but we truncate the message if it 6682b15cb3dSCy Schubert * does not fit the buffer. GPSD might truncate messages, too, 6692b15cb3dSCy Schubert * so dealing with truncated buffers is necessary anyway. 6702b15cb3dSCy Schubert */ 6712b15cb3dSCy Schubert psrc = (const char*)rbufp->recv_buffer; 6722b15cb3dSCy Schubert esrc = psrc + rbufp->recv_length; 6732b15cb3dSCy Schubert 6742b15cb3dSCy Schubert pdst = up->buffer + up->buflen; 6752b15cb3dSCy Schubert edst = pdst + sizeof(up->buffer) - 1; /* for trailing NUL */ 6762b15cb3dSCy Schubert 6772b15cb3dSCy Schubert while (psrc != esrc) { 6782b15cb3dSCy Schubert ch = *psrc++; 6792b15cb3dSCy Schubert if (ch == '\n') { 6802b15cb3dSCy Schubert /* trim trailing whitespace & terminate buffer */ 6812b15cb3dSCy Schubert while (pdst != up->buffer && pdst[-1] <= ' ') 6822b15cb3dSCy Schubert --pdst; 6832b15cb3dSCy Schubert *pdst = '\0'; 6842b15cb3dSCy Schubert /* process data and reset buffer */ 685276da39aSCy Schubert up->buflen = pdst - up->buffer; 6862b15cb3dSCy Schubert gpsd_parse(peer, &rbufp->recv_time); 6872b15cb3dSCy Schubert pdst = up->buffer; 6882b15cb3dSCy Schubert } else if (pdst != edst) { 6892b15cb3dSCy Schubert /* add next char, ignoring leading whitespace */ 6902b15cb3dSCy Schubert if (ch > ' ' || pdst != up->buffer) 6912b15cb3dSCy Schubert *pdst++ = ch; 6922b15cb3dSCy Schubert } 6932b15cb3dSCy Schubert } 6942b15cb3dSCy Schubert up->buflen = pdst - up->buffer; 6952b15cb3dSCy Schubert up->tickover = TICKOVER_LOW; 6962b15cb3dSCy Schubert } 6972b15cb3dSCy Schubert 6982b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 6992b15cb3dSCy Schubert 7002b15cb3dSCy Schubert static void 701276da39aSCy Schubert poll_primary( 702276da39aSCy Schubert peerT * const peer , 703276da39aSCy Schubert clockprocT * const pp , 704276da39aSCy Schubert gpsd_unitT * const up ) 705276da39aSCy Schubert { 706276da39aSCy Schubert if (pp->coderecv != pp->codeproc) { 707276da39aSCy Schubert /* all is well */ 708276da39aSCy Schubert pp->lastref = pp->lastrec; 709276da39aSCy Schubert refclock_report(peer, CEVNT_NOMINAL); 710276da39aSCy Schubert refclock_receive(peer); 711276da39aSCy Schubert } else { 712276da39aSCy Schubert /* Not working properly, admit to it. If we have no 713276da39aSCy Schubert * connection to GPSD, declare the clock as faulty. If 714276da39aSCy Schubert * there were bad replies, this is handled as the major 715276da39aSCy Schubert * cause, and everything else is just a timeout. 716276da39aSCy Schubert */ 717276da39aSCy Schubert peer->precision = PRECISION; 718276da39aSCy Schubert if (-1 == pp->io.fd) 719276da39aSCy Schubert refclock_report(peer, CEVNT_FAULT); 720276da39aSCy Schubert else if (0 != up->tc_breply) 721276da39aSCy Schubert refclock_report(peer, CEVNT_BADREPLY); 722276da39aSCy Schubert else 723276da39aSCy Schubert refclock_report(peer, CEVNT_TIMEOUT); 724276da39aSCy Schubert } 725276da39aSCy Schubert 726276da39aSCy Schubert if (pp->sloppyclockflag & CLK_FLAG4) 727276da39aSCy Schubert mprintf_clock_stats( 728276da39aSCy Schubert &peer->srcadr,"%u %u %u %u %u %u %u", 729276da39aSCy Schubert up->tc_recv, 730276da39aSCy Schubert up->tc_breply, up->tc_nosync, 731276da39aSCy Schubert up->tc_sti_recv, up->tc_sti_used, 732276da39aSCy Schubert up->tc_pps_recv, up->tc_pps_used); 733276da39aSCy Schubert 734276da39aSCy Schubert /* clear tallies for next round */ 735276da39aSCy Schubert up->tc_breply = 0; 736276da39aSCy Schubert up->tc_recv = 0; 737276da39aSCy Schubert up->tc_nosync = 0; 738276da39aSCy Schubert up->tc_sti_recv = 0; 739276da39aSCy Schubert up->tc_sti_used = 0; 740276da39aSCy Schubert up->tc_pps_recv = 0; 741276da39aSCy Schubert up->tc_pps_used = 0; 742276da39aSCy Schubert } 743276da39aSCy Schubert 744276da39aSCy Schubert static void 745276da39aSCy Schubert poll_secondary( 746276da39aSCy Schubert peerT * const peer , 747276da39aSCy Schubert clockprocT * const pp , 748276da39aSCy Schubert gpsd_unitT * const up ) 749276da39aSCy Schubert { 750276da39aSCy Schubert if (pp->coderecv != pp->codeproc) { 751276da39aSCy Schubert /* all is well */ 752276da39aSCy Schubert pp->lastref = pp->lastrec; 753276da39aSCy Schubert refclock_report(peer, CEVNT_NOMINAL); 754276da39aSCy Schubert refclock_receive(peer); 755276da39aSCy Schubert } else { 756276da39aSCy Schubert peer->precision = PPS_PRECISION; 757276da39aSCy Schubert peer->flags &= ~FLAG_PPS; 758276da39aSCy Schubert refclock_report(peer, CEVNT_TIMEOUT); 759276da39aSCy Schubert } 760276da39aSCy Schubert } 761276da39aSCy Schubert 762276da39aSCy Schubert static void 7632b15cb3dSCy Schubert gpsd_poll( 7642b15cb3dSCy Schubert int unit, 7652b15cb3dSCy Schubert peerT * peer) 7662b15cb3dSCy Schubert { 7672b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 7682b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 7692b15cb3dSCy Schubert 7702b15cb3dSCy Schubert ++pp->polls; 771276da39aSCy Schubert if (peer == up->pps_peer) 772276da39aSCy Schubert poll_secondary(peer, pp, up); 773276da39aSCy Schubert else 774276da39aSCy Schubert poll_primary(peer, pp, up); 7752b15cb3dSCy Schubert } 7762b15cb3dSCy Schubert 7772b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 7782b15cb3dSCy Schubert 7792b15cb3dSCy Schubert static void 7802b15cb3dSCy Schubert gpsd_control( 7812b15cb3dSCy Schubert int unit, 7822b15cb3dSCy Schubert const struct refclockstat * in_st, 7832b15cb3dSCy Schubert struct refclockstat * out_st, 7842b15cb3dSCy Schubert peerT * peer ) 7852b15cb3dSCy Schubert { 7862b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 7872b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 7882b15cb3dSCy Schubert 789276da39aSCy Schubert if (peer == up->pps_peer) { 790276da39aSCy Schubert DTOLFP(pp->fudgetime1, &up->pps_fudge2); 791276da39aSCy Schubert if ( ! (pp->sloppyclockflag & CLK_FLAG1)) 792276da39aSCy Schubert peer->flags &= ~FLAG_PPS; 793276da39aSCy Schubert } else { 7942b15cb3dSCy Schubert /* save preprocessed fudge times */ 7952b15cb3dSCy Schubert DTOLFP(pp->fudgetime1, &up->pps_fudge); 796276da39aSCy Schubert DTOLFP(pp->fudgetime2, &up->sti_fudge); 797276da39aSCy Schubert 798276da39aSCy Schubert if (MODE_OP_MODE(up->mode ^ peer->ttl)) { 799276da39aSCy Schubert leave_opmode(peer, up->mode); 800276da39aSCy Schubert up->mode = MODE_OP_MODE(peer->ttl); 801276da39aSCy Schubert enter_opmode(peer, up->mode); 802276da39aSCy Schubert } 803276da39aSCy Schubert } 8042b15cb3dSCy Schubert } 8052b15cb3dSCy Schubert 8062b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 8072b15cb3dSCy Schubert 8082b15cb3dSCy Schubert static void 809276da39aSCy Schubert timer_primary( 810276da39aSCy Schubert peerT * const peer , 811276da39aSCy Schubert clockprocT * const pp , 812276da39aSCy Schubert gpsd_unitT * const up ) 8132b15cb3dSCy Schubert { 8142b15cb3dSCy Schubert int rc; 8152b15cb3dSCy Schubert 8162b15cb3dSCy Schubert /* This is used for timeout handling. Nothing that needs 8172b15cb3dSCy Schubert * sub-second precison happens here, so receive/connect/retry 8182b15cb3dSCy Schubert * timeouts are simply handled by a count down, and then we 8192b15cb3dSCy Schubert * decide what to do by the socket values. 8202b15cb3dSCy Schubert * 8212b15cb3dSCy Schubert * Note that the timer stays at zero here, unless some of the 8222b15cb3dSCy Schubert * functions set it to another value. 8232b15cb3dSCy Schubert */ 8242b15cb3dSCy Schubert if (up->logthrottle) 8252b15cb3dSCy Schubert --up->logthrottle; 8262b15cb3dSCy Schubert if (up->tickover) 8272b15cb3dSCy Schubert --up->tickover; 8282b15cb3dSCy Schubert switch (up->tickover) { 8292b15cb3dSCy Schubert case 4: 830276da39aSCy Schubert /* If we are connected to GPSD, try to get a live signal 831276da39aSCy Schubert * by querying the version. Otherwise just check the 832276da39aSCy Schubert * socket to become ready. 8332b15cb3dSCy Schubert */ 8342b15cb3dSCy Schubert if (-1 != pp->io.fd) { 835276da39aSCy Schubert size_t rlen = strlen(s_req_version); 836276da39aSCy Schubert DPRINTF(2, ("%s: timer livecheck: '%s'\n", 837276da39aSCy Schubert up->logname, s_req_version)); 838276da39aSCy Schubert log_data(peer, "send", s_req_version, rlen); 839276da39aSCy Schubert rc = write(pp->io.fd, s_req_version, rlen); 8402b15cb3dSCy Schubert (void)rc; 8412b15cb3dSCy Schubert } else if (-1 != up->fdt) { 8422b15cb3dSCy Schubert gpsd_test_socket(peer); 8432b15cb3dSCy Schubert } 8442b15cb3dSCy Schubert break; 8452b15cb3dSCy Schubert 8462b15cb3dSCy Schubert case 0: 8472b15cb3dSCy Schubert if (-1 != pp->io.fd) 8482b15cb3dSCy Schubert gpsd_stop_socket(peer); 8492b15cb3dSCy Schubert else if (-1 != up->fdt) 8502b15cb3dSCy Schubert gpsd_test_socket(peer); 8512b15cb3dSCy Schubert else if (NULL != s_gpsd_addr) 8522b15cb3dSCy Schubert gpsd_init_socket(peer); 8532b15cb3dSCy Schubert break; 8542b15cb3dSCy Schubert 8552b15cb3dSCy Schubert default: 8562b15cb3dSCy Schubert if (-1 == pp->io.fd && -1 != up->fdt) 8572b15cb3dSCy Schubert gpsd_test_socket(peer); 8582b15cb3dSCy Schubert } 859276da39aSCy Schubert } 8602b15cb3dSCy Schubert 861276da39aSCy Schubert static void 862276da39aSCy Schubert timer_secondary( 863276da39aSCy Schubert peerT * const peer , 864276da39aSCy Schubert clockprocT * const pp , 865276da39aSCy Schubert gpsd_unitT * const up ) 866276da39aSCy Schubert { 867276da39aSCy Schubert /* Reduce the count by one. Flush sample buffer and clear PPS 868276da39aSCy Schubert * flag when this happens. 869276da39aSCy Schubert */ 870276da39aSCy Schubert up->ppscount2 = max(0, (up->ppscount2 - 1)); 871276da39aSCy Schubert if (0 == up->ppscount2) { 872276da39aSCy Schubert if (pp->coderecv != pp->codeproc) { 873276da39aSCy Schubert refclock_report(peer, CEVNT_TIMEOUT); 874276da39aSCy Schubert pp->coderecv = pp->codeproc; 875276da39aSCy Schubert } 8762b15cb3dSCy Schubert peer->flags &= ~FLAG_PPS; 8772b15cb3dSCy Schubert } 878276da39aSCy Schubert } 879276da39aSCy Schubert 880276da39aSCy Schubert static void 881276da39aSCy Schubert gpsd_timer( 882276da39aSCy Schubert int unit, 883276da39aSCy Schubert peerT * peer) 884276da39aSCy Schubert { 885276da39aSCy Schubert clockprocT * const pp = peer->procptr; 886276da39aSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 887276da39aSCy Schubert 888276da39aSCy Schubert if (peer == up->pps_peer) 889276da39aSCy Schubert timer_secondary(peer, pp, up); 890276da39aSCy Schubert else 891276da39aSCy Schubert timer_primary(peer, pp, up); 892276da39aSCy Schubert } 893276da39aSCy Schubert 894276da39aSCy Schubert /* ===================================================================== 895276da39aSCy Schubert * handle opmode switches 896276da39aSCy Schubert */ 897276da39aSCy Schubert 898276da39aSCy Schubert static void 899276da39aSCy Schubert enter_opmode( 900276da39aSCy Schubert peerT *peer, 901276da39aSCy Schubert int mode) 902276da39aSCy Schubert { 903276da39aSCy Schubert clockprocT * const pp = peer->procptr; 904276da39aSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 905276da39aSCy Schubert 906276da39aSCy Schubert DPRINTF(1, ("%s: enter operation mode %d\n", 907276da39aSCy Schubert up->logname, MODE_OP_MODE(mode))); 908276da39aSCy Schubert 909276da39aSCy Schubert if (MODE_OP_MODE(mode) == MODE_OP_AUTO) { 910276da39aSCy Schubert up->fl_rawsti = 0; 911276da39aSCy Schubert up->ppscount = PPS_MAXCOUNT / 2; 912276da39aSCy Schubert } 913276da39aSCy Schubert up->fl_pps = 0; 914276da39aSCy Schubert up->fl_sti = 0; 915276da39aSCy Schubert } 916276da39aSCy Schubert 917276da39aSCy Schubert /* ------------------------------------------------------------------ */ 918276da39aSCy Schubert 919276da39aSCy Schubert static void 920276da39aSCy Schubert leave_opmode( 921276da39aSCy Schubert peerT *peer, 922276da39aSCy Schubert int mode) 923276da39aSCy Schubert { 924276da39aSCy Schubert clockprocT * const pp = peer->procptr; 925276da39aSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 926276da39aSCy Schubert 927276da39aSCy Schubert DPRINTF(1, ("%s: leaving operation mode %d\n", 928276da39aSCy Schubert up->logname, MODE_OP_MODE(mode))); 929276da39aSCy Schubert 930276da39aSCy Schubert if (MODE_OP_MODE(mode) == MODE_OP_AUTO) { 931276da39aSCy Schubert up->fl_rawsti = 0; 932276da39aSCy Schubert up->ppscount = 0; 933276da39aSCy Schubert } 934276da39aSCy Schubert up->fl_pps = 0; 935276da39aSCy Schubert up->fl_sti = 0; 936276da39aSCy Schubert } 937276da39aSCy Schubert 938276da39aSCy Schubert /* ===================================================================== 939276da39aSCy Schubert * operation mode specific evaluation 940276da39aSCy Schubert */ 941276da39aSCy Schubert 942276da39aSCy Schubert static void 943276da39aSCy Schubert add_clock_sample( 944276da39aSCy Schubert peerT * const peer , 945276da39aSCy Schubert clockprocT * const pp , 946276da39aSCy Schubert l_fp stamp, 947276da39aSCy Schubert l_fp recvt) 948276da39aSCy Schubert { 949276da39aSCy Schubert pp->lastref = stamp; 950276da39aSCy Schubert if (pp->coderecv == pp->codeproc) 951276da39aSCy Schubert refclock_report(peer, CEVNT_NOMINAL); 952f391d6bcSXin LI refclock_process_offset(pp, stamp, recvt, pp->fudgetime1); 953276da39aSCy Schubert } 954276da39aSCy Schubert 955276da39aSCy Schubert /* ------------------------------------------------------------------ */ 956276da39aSCy Schubert 957276da39aSCy Schubert static void 958276da39aSCy Schubert eval_strict( 959276da39aSCy Schubert peerT * const peer , 960276da39aSCy Schubert clockprocT * const pp , 961276da39aSCy Schubert gpsd_unitT * const up ) 962276da39aSCy Schubert { 963276da39aSCy Schubert if (up->fl_sti && up->fl_pps) { 964276da39aSCy Schubert /* use TPV reference time + PPS receive time */ 965276da39aSCy Schubert add_clock_sample(peer, pp, up->sti_stamp, up->pps_recvt); 966276da39aSCy Schubert peer->precision = up->pps_prec; 967276da39aSCy Schubert /* both packets consumed now... */ 968276da39aSCy Schubert up->fl_pps = 0; 969276da39aSCy Schubert up->fl_sti = 0; 970276da39aSCy Schubert ++up->tc_sti_used; 971276da39aSCy Schubert } 972276da39aSCy Schubert } 973276da39aSCy Schubert 974276da39aSCy Schubert /* ------------------------------------------------------------------ */ 975276da39aSCy Schubert /* PPS processing for the secondary channel. GPSD provides us with full 976276da39aSCy Schubert * timing information, so there's no danger of PLL-locking to the wrong 977276da39aSCy Schubert * second. The belts and suspenders needed for the raw ATOM clock are 978276da39aSCy Schubert * unnecessary here. 979276da39aSCy Schubert */ 980276da39aSCy Schubert static void 981276da39aSCy Schubert eval_pps_secondary( 982276da39aSCy Schubert peerT * const peer , 983276da39aSCy Schubert clockprocT * const pp , 984276da39aSCy Schubert gpsd_unitT * const up ) 985276da39aSCy Schubert { 986276da39aSCy Schubert if (up->fl_pps2) { 987276da39aSCy Schubert /* feed data */ 988276da39aSCy Schubert add_clock_sample(peer, pp, up->pps_stamp2, up->pps_recvt2); 989276da39aSCy Schubert peer->precision = up->pps_prec; 990276da39aSCy Schubert /* PPS peer flag logic */ 991276da39aSCy Schubert up->ppscount2 = min(PPS2_MAXCOUNT, (up->ppscount2 + 2)); 992276da39aSCy Schubert if ((PPS2_MAXCOUNT == up->ppscount2) && 993276da39aSCy Schubert (pp->sloppyclockflag & CLK_FLAG1) ) 994276da39aSCy Schubert peer->flags |= FLAG_PPS; 995276da39aSCy Schubert /* mark time stamp as burned... */ 996276da39aSCy Schubert up->fl_pps2 = 0; 997276da39aSCy Schubert ++up->tc_pps_used; 998276da39aSCy Schubert } 999276da39aSCy Schubert } 1000276da39aSCy Schubert 1001276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1002276da39aSCy Schubert 1003276da39aSCy Schubert static void 1004276da39aSCy Schubert eval_serial( 1005276da39aSCy Schubert peerT * const peer , 1006276da39aSCy Schubert clockprocT * const pp , 1007276da39aSCy Schubert gpsd_unitT * const up ) 1008276da39aSCy Schubert { 1009276da39aSCy Schubert if (up->fl_sti) { 1010276da39aSCy Schubert add_clock_sample(peer, pp, up->sti_stamp, up->sti_recvt); 1011276da39aSCy Schubert peer->precision = up->sti_prec; 1012276da39aSCy Schubert /* mark time stamp as burned... */ 1013276da39aSCy Schubert up->fl_sti = 0; 1014276da39aSCy Schubert ++up->tc_sti_used; 1015276da39aSCy Schubert } 1016276da39aSCy Schubert } 1017276da39aSCy Schubert 1018276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1019276da39aSCy Schubert static void 1020276da39aSCy Schubert eval_auto( 1021276da39aSCy Schubert peerT * const peer , 1022276da39aSCy Schubert clockprocT * const pp , 1023276da39aSCy Schubert gpsd_unitT * const up ) 1024276da39aSCy Schubert { 1025276da39aSCy Schubert /* If there's no TPV available, stop working here... */ 1026276da39aSCy Schubert if (!up->fl_sti) 1027276da39aSCy Schubert return; 1028276da39aSCy Schubert 1029276da39aSCy Schubert /* check how to handle STI+PPS: Can PPS be used to augment STI 1030276da39aSCy Schubert * (or vice versae), do we drop the sample because there is a 1031276da39aSCy Schubert * temporary missing PPS signal, or do we feed on STI time 1032276da39aSCy Schubert * stamps alone? 1033276da39aSCy Schubert * 1034276da39aSCy Schubert * Do a counter/threshold dance to decide how to proceed. 1035276da39aSCy Schubert */ 1036276da39aSCy Schubert if (up->fl_pps) { 1037276da39aSCy Schubert up->ppscount = min(PPS_MAXCOUNT, 1038276da39aSCy Schubert (up->ppscount + PPS_INCCOUNT)); 1039276da39aSCy Schubert if ((PPS_MAXCOUNT == up->ppscount) && up->fl_rawsti) { 1040276da39aSCy Schubert up->fl_rawsti = 0; 1041276da39aSCy Schubert msyslog(LOG_INFO, 1042276da39aSCy Schubert "%s: expect valid PPS from now", 1043276da39aSCy Schubert up->logname); 1044276da39aSCy Schubert } 1045276da39aSCy Schubert } else { 1046276da39aSCy Schubert up->ppscount = max(0, (up->ppscount - PPS_DECCOUNT)); 1047276da39aSCy Schubert if ((0 == up->ppscount) && !up->fl_rawsti) { 1048276da39aSCy Schubert up->fl_rawsti = -1; 1049276da39aSCy Schubert msyslog(LOG_WARNING, 1050276da39aSCy Schubert "%s: use TPV alone from now", 1051276da39aSCy Schubert up->logname); 1052276da39aSCy Schubert } 1053276da39aSCy Schubert } 1054276da39aSCy Schubert 1055276da39aSCy Schubert /* now eventually feed the sample */ 1056276da39aSCy Schubert if (up->fl_rawsti) 1057276da39aSCy Schubert eval_serial(peer, pp, up); 1058276da39aSCy Schubert else 1059276da39aSCy Schubert eval_strict(peer, pp, up); 1060276da39aSCy Schubert } 10612b15cb3dSCy Schubert 10622b15cb3dSCy Schubert /* ===================================================================== 10632b15cb3dSCy Schubert * JSON parsing stuff 10642b15cb3dSCy Schubert */ 10652b15cb3dSCy Schubert 1066276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1067276da39aSCy Schubert /* Parse a decimal integer with a possible sign. Works like 'strtoll()' 1068276da39aSCy Schubert * or 'strtol()', but with a fixed base of 10 and without eating away 1069276da39aSCy Schubert * leading whitespace. For the error codes, the handling of the end 1070276da39aSCy Schubert * pointer and the return values see 'strtol()'. 1071276da39aSCy Schubert */ 1072276da39aSCy Schubert static json_int 1073276da39aSCy Schubert strtojint( 1074276da39aSCy Schubert const char *cp, char **ep) 1075276da39aSCy Schubert { 1076276da39aSCy Schubert json_uint accu, limit_lo, limit_hi; 1077276da39aSCy Schubert int flags; /* bit 0: overflow; bit 1: sign */ 1078276da39aSCy Schubert const char * hold; 10792b15cb3dSCy Schubert 1080276da39aSCy Schubert /* pointer union to circumvent a tricky/sticky const issue */ 1081276da39aSCy Schubert union { const char * c; char * v; } vep; 10822b15cb3dSCy Schubert 1083276da39aSCy Schubert /* store initial value of 'cp' -- see 'strtol()' */ 1084276da39aSCy Schubert vep.c = cp; 10852b15cb3dSCy Schubert 1086276da39aSCy Schubert /* Eat away an optional sign and set the limits accordingly: The 1087276da39aSCy Schubert * high limit is the maximum absolute value that can be returned, 1088276da39aSCy Schubert * and the low limit is the biggest value that does not cause an 1089276da39aSCy Schubert * overflow when multiplied with 10. Avoid negation overflows. 1090276da39aSCy Schubert */ 1091276da39aSCy Schubert if (*cp == '-') { 1092276da39aSCy Schubert cp += 1; 1093276da39aSCy Schubert flags = 2; 1094276da39aSCy Schubert limit_hi = (json_uint)-(JSON_INT_MIN + 1) + 1; 1095276da39aSCy Schubert } else { 1096276da39aSCy Schubert cp += (*cp == '+'); 1097276da39aSCy Schubert flags = 0; 1098276da39aSCy Schubert limit_hi = (json_uint)JSON_INT_MAX; 1099276da39aSCy Schubert } 1100276da39aSCy Schubert limit_lo = limit_hi / 10; 1101276da39aSCy Schubert 1102276da39aSCy Schubert /* Now try to convert a sequence of digits. */ 1103276da39aSCy Schubert hold = cp; 1104276da39aSCy Schubert accu = 0; 11059034852cSGleb Smirnoff while (isdigit(*(const u_char*)cp)) { 1106276da39aSCy Schubert flags |= (accu > limit_lo); 11079034852cSGleb Smirnoff accu = accu * 10 + (*(const u_char*)cp++ - '0'); 1108276da39aSCy Schubert flags |= (accu > limit_hi); 1109276da39aSCy Schubert } 1110276da39aSCy Schubert /* Check for empty conversion (no digits seen). */ 1111276da39aSCy Schubert if (hold != cp) 1112276da39aSCy Schubert vep.c = cp; 1113276da39aSCy Schubert else 1114276da39aSCy Schubert errno = EINVAL; /* accu is still zero */ 1115276da39aSCy Schubert /* Check for range overflow */ 1116276da39aSCy Schubert if (flags & 1) { 1117276da39aSCy Schubert errno = ERANGE; 1118276da39aSCy Schubert accu = limit_hi; 1119276da39aSCy Schubert } 1120276da39aSCy Schubert /* If possible, store back the end-of-conversion pointer */ 1121276da39aSCy Schubert if (ep) 1122276da39aSCy Schubert *ep = vep.v; 1123276da39aSCy Schubert /* If negative, return the negated result if the accu is not 1124276da39aSCy Schubert * zero. Avoid negation overflows. 1125276da39aSCy Schubert */ 1126276da39aSCy Schubert if ((flags & 2) && accu) 1127276da39aSCy Schubert return -(json_int)(accu - 1) - 1; 1128276da39aSCy Schubert else 1129276da39aSCy Schubert return (json_int)accu; 1130276da39aSCy Schubert } 11312b15cb3dSCy Schubert 11322b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 11332b15cb3dSCy Schubert 11342b15cb3dSCy Schubert static tok_ref 11352b15cb3dSCy Schubert json_token_skip( 11362b15cb3dSCy Schubert const json_ctx * ctx, 11372b15cb3dSCy Schubert tok_ref tid) 11382b15cb3dSCy Schubert { 113968ba7e87SXin LI if (tid >= 0 && (u_int)tid < ctx->ntok) { 1140276da39aSCy Schubert int len = ctx->tok[tid].size; 1141276da39aSCy Schubert /* For arrays and objects, the size is the number of 1142276da39aSCy Schubert * ITEMS in the compound. Thats the number of objects in 1143276da39aSCy Schubert * the array, and the number of key/value pairs for 1144276da39aSCy Schubert * objects. In theory, the key must be a string, and we 1145276da39aSCy Schubert * could simply skip one token before skipping the 1146276da39aSCy Schubert * value, which can be anything. We're a bit paranoid 1147276da39aSCy Schubert * and lazy at the same time: We simply double the 1148276da39aSCy Schubert * number of tokens to skip and fall through into the 1149276da39aSCy Schubert * array processing when encountering an object. 1150276da39aSCy Schubert */ 1151276da39aSCy Schubert switch (ctx->tok[tid].type) { 1152276da39aSCy Schubert case JSMN_OBJECT: 1153276da39aSCy Schubert len *= 2; 1154276da39aSCy Schubert /* FALLTHROUGH */ 1155276da39aSCy Schubert case JSMN_ARRAY: 11562b15cb3dSCy Schubert for (++tid; len; --len) 11572b15cb3dSCy Schubert tid = json_token_skip(ctx, tid); 11582b15cb3dSCy Schubert break; 1159276da39aSCy Schubert 1160276da39aSCy Schubert default: 1161276da39aSCy Schubert ++tid; 1162276da39aSCy Schubert break; 1163276da39aSCy Schubert } 116468ba7e87SXin LI /* The next condition should never be true, but paranoia 116568ba7e87SXin LI * prevails... 116668ba7e87SXin LI */ 116768ba7e87SXin LI if (tid < 0 || (u_int)tid > ctx->ntok) 11682b15cb3dSCy Schubert tid = ctx->ntok; 1169276da39aSCy Schubert } 11702b15cb3dSCy Schubert return tid; 11712b15cb3dSCy Schubert } 11722b15cb3dSCy Schubert 11732b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 11742b15cb3dSCy Schubert 11752b15cb3dSCy Schubert static int 11762b15cb3dSCy Schubert json_object_lookup( 11772b15cb3dSCy Schubert const json_ctx * ctx , 11782b15cb3dSCy Schubert tok_ref tid , 1179276da39aSCy Schubert const char * key , 1180276da39aSCy Schubert int what) 11812b15cb3dSCy Schubert { 11822b15cb3dSCy Schubert int len; 11832b15cb3dSCy Schubert 1184276da39aSCy Schubert if (tid < 0 || tid >= ctx->ntok || 1185276da39aSCy Schubert ctx->tok[tid].type != JSMN_OBJECT) 11862b15cb3dSCy Schubert return INVALID_TOKEN; 1187276da39aSCy Schubert 11882b15cb3dSCy Schubert len = ctx->tok[tid].size; 1189276da39aSCy Schubert for (++tid; len && tid+1 < ctx->ntok; --len) { 1190276da39aSCy Schubert if (ctx->tok[tid].type != JSMN_STRING) { /* Blooper! */ 1191276da39aSCy Schubert tid = json_token_skip(ctx, tid); /* skip key */ 1192276da39aSCy Schubert tid = json_token_skip(ctx, tid); /* skip val */ 1193276da39aSCy Schubert } else if (strcmp(key, ctx->buf + ctx->tok[tid].start)) { 1194276da39aSCy Schubert tid = json_token_skip(ctx, tid+1); /* skip key+val */ 119568ba7e87SXin LI } else if (what < 0 || (u_int)what == ctx->tok[tid+1].type) { 11962b15cb3dSCy Schubert return tid + 1; 1197276da39aSCy Schubert } else { 1198276da39aSCy Schubert break; 1199276da39aSCy Schubert } 1200276da39aSCy Schubert /* if skipping ahead returned an error, bail out here. */ 1201276da39aSCy Schubert if (tid < 0) 1202276da39aSCy Schubert break; 12032b15cb3dSCy Schubert } 12042b15cb3dSCy Schubert return INVALID_TOKEN; 12052b15cb3dSCy Schubert } 12062b15cb3dSCy Schubert 12072b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 12082b15cb3dSCy Schubert 1209276da39aSCy Schubert static const char* 1210276da39aSCy Schubert json_object_lookup_primitive( 1211276da39aSCy Schubert const json_ctx * ctx, 1212276da39aSCy Schubert tok_ref tid, 1213276da39aSCy Schubert const char * key) 1214276da39aSCy Schubert { 1215276da39aSCy Schubert tid = json_object_lookup(ctx, tid, key, JSMN_PRIMITIVE); 1216276da39aSCy Schubert if (INVALID_TOKEN != tid) 1217276da39aSCy Schubert return ctx->buf + ctx->tok[tid].start; 1218276da39aSCy Schubert else 1219276da39aSCy Schubert return NULL; 1220276da39aSCy Schubert } 1221276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1222276da39aSCy Schubert /* look up a boolean value. This essentially returns a tribool: 1223276da39aSCy Schubert * 0->false, 1->true, (-1)->error/undefined 1224276da39aSCy Schubert */ 1225276da39aSCy Schubert static int 1226276da39aSCy Schubert json_object_lookup_bool( 1227276da39aSCy Schubert const json_ctx * ctx, 1228276da39aSCy Schubert tok_ref tid, 1229276da39aSCy Schubert const char * key) 1230276da39aSCy Schubert { 1231276da39aSCy Schubert const char *cp; 1232276da39aSCy Schubert cp = json_object_lookup_primitive(ctx, tid, key); 1233276da39aSCy Schubert switch ( cp ? *cp : '\0') { 1234276da39aSCy Schubert case 't': return 1; 1235276da39aSCy Schubert case 'f': return 0; 1236276da39aSCy Schubert default : return -1; 1237276da39aSCy Schubert } 1238276da39aSCy Schubert } 1239276da39aSCy Schubert 1240276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1241276da39aSCy Schubert 12422b15cb3dSCy Schubert static const char* 12432b15cb3dSCy Schubert json_object_lookup_string( 12442b15cb3dSCy Schubert const json_ctx * ctx, 12452b15cb3dSCy Schubert tok_ref tid, 12462b15cb3dSCy Schubert const char * key) 12472b15cb3dSCy Schubert { 1248276da39aSCy Schubert tid = json_object_lookup(ctx, tid, key, JSMN_STRING); 1249276da39aSCy Schubert if (INVALID_TOKEN != tid) 1250276da39aSCy Schubert return ctx->buf + ctx->tok[tid].start; 12512b15cb3dSCy Schubert return NULL; 12522b15cb3dSCy Schubert } 12532b15cb3dSCy Schubert 12542b15cb3dSCy Schubert static const char* 12552b15cb3dSCy Schubert json_object_lookup_string_default( 12562b15cb3dSCy Schubert const json_ctx * ctx, 12572b15cb3dSCy Schubert tok_ref tid, 12582b15cb3dSCy Schubert const char * key, 12592b15cb3dSCy Schubert const char * def) 12602b15cb3dSCy Schubert { 1261276da39aSCy Schubert tid = json_object_lookup(ctx, tid, key, JSMN_STRING); 1262276da39aSCy Schubert if (INVALID_TOKEN != tid) 1263276da39aSCy Schubert return ctx->buf + ctx->tok[tid].start; 12642b15cb3dSCy Schubert return def; 12652b15cb3dSCy Schubert } 12662b15cb3dSCy Schubert 12672b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 12682b15cb3dSCy Schubert 12692b15cb3dSCy Schubert static json_int 12702b15cb3dSCy Schubert json_object_lookup_int( 12712b15cb3dSCy Schubert const json_ctx * ctx, 12722b15cb3dSCy Schubert tok_ref tid, 12732b15cb3dSCy Schubert const char * key) 12742b15cb3dSCy Schubert { 12752b15cb3dSCy Schubert json_int ret; 1276276da39aSCy Schubert const char * cp; 12772b15cb3dSCy Schubert char * ep; 12782b15cb3dSCy Schubert 1279276da39aSCy Schubert cp = json_object_lookup_primitive(ctx, tid, key); 1280276da39aSCy Schubert if (NULL != cp) { 1281276da39aSCy Schubert ret = strtojint(cp, &ep); 1282276da39aSCy Schubert if (cp != ep && '\0' == *ep) 12832b15cb3dSCy Schubert return ret; 1284276da39aSCy Schubert } else { 12852b15cb3dSCy Schubert errno = EINVAL; 1286276da39aSCy Schubert } 12872b15cb3dSCy Schubert return 0; 12882b15cb3dSCy Schubert } 12892b15cb3dSCy Schubert 12902b15cb3dSCy Schubert static json_int 12912b15cb3dSCy Schubert json_object_lookup_int_default( 12922b15cb3dSCy Schubert const json_ctx * ctx, 12932b15cb3dSCy Schubert tok_ref tid, 12942b15cb3dSCy Schubert const char * key, 12952b15cb3dSCy Schubert json_int def) 12962b15cb3dSCy Schubert { 1297276da39aSCy Schubert json_int ret; 1298276da39aSCy Schubert const char * cp; 1299276da39aSCy Schubert char * ep; 13002b15cb3dSCy Schubert 1301276da39aSCy Schubert cp = json_object_lookup_primitive(ctx, tid, key); 1302276da39aSCy Schubert if (NULL != cp) { 1303276da39aSCy Schubert ret = strtojint(cp, &ep); 1304276da39aSCy Schubert if (cp != ep && '\0' == *ep) 1305276da39aSCy Schubert return ret; 1306276da39aSCy Schubert } 1307276da39aSCy Schubert return def; 13082b15cb3dSCy Schubert } 13092b15cb3dSCy Schubert 13102b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 1311276da39aSCy Schubert #if 0 /* currently unused */ 13122b15cb3dSCy Schubert static double 13132b15cb3dSCy Schubert json_object_lookup_float( 13142b15cb3dSCy Schubert const json_ctx * ctx, 13152b15cb3dSCy Schubert tok_ref tid, 13162b15cb3dSCy Schubert const char * key) 13172b15cb3dSCy Schubert { 13182b15cb3dSCy Schubert double ret; 1319276da39aSCy Schubert const char * cp; 13202b15cb3dSCy Schubert char * ep; 13212b15cb3dSCy Schubert 1322276da39aSCy Schubert cp = json_object_lookup_primitive(ctx, tid, key); 1323276da39aSCy Schubert if (NULL != cp) { 1324276da39aSCy Schubert ret = strtod(cp, &ep); 1325276da39aSCy Schubert if (cp != ep && '\0' == *ep) 13262b15cb3dSCy Schubert return ret; 1327276da39aSCy Schubert } else { 13282b15cb3dSCy Schubert errno = EINVAL; 1329276da39aSCy Schubert } 13302b15cb3dSCy Schubert return 0.0; 13312b15cb3dSCy Schubert } 1332276da39aSCy Schubert #endif 13332b15cb3dSCy Schubert 13342b15cb3dSCy Schubert static double 13352b15cb3dSCy Schubert json_object_lookup_float_default( 13362b15cb3dSCy Schubert const json_ctx * ctx, 13372b15cb3dSCy Schubert tok_ref tid, 13382b15cb3dSCy Schubert const char * key, 13392b15cb3dSCy Schubert double def) 13402b15cb3dSCy Schubert { 1341276da39aSCy Schubert double ret; 1342276da39aSCy Schubert const char * cp; 1343276da39aSCy Schubert char * ep; 13442b15cb3dSCy Schubert 1345276da39aSCy Schubert cp = json_object_lookup_primitive(ctx, tid, key); 1346276da39aSCy Schubert if (NULL != cp) { 1347276da39aSCy Schubert ret = strtod(cp, &ep); 1348276da39aSCy Schubert if (cp != ep && '\0' == *ep) 1349276da39aSCy Schubert return ret; 1350276da39aSCy Schubert } 1351276da39aSCy Schubert return def; 13522b15cb3dSCy Schubert } 13532b15cb3dSCy Schubert 13542b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 13552b15cb3dSCy Schubert 13562b15cb3dSCy Schubert static BOOL 13572b15cb3dSCy Schubert json_parse_record( 13582b15cb3dSCy Schubert json_ctx * ctx, 1359276da39aSCy Schubert char * buf, 1360276da39aSCy Schubert size_t len) 13612b15cb3dSCy Schubert { 13622b15cb3dSCy Schubert jsmn_parser jsm; 13632b15cb3dSCy Schubert int idx, rc; 13642b15cb3dSCy Schubert 13652b15cb3dSCy Schubert jsmn_init(&jsm); 1366276da39aSCy Schubert rc = jsmn_parse(&jsm, buf, len, ctx->tok, JSMN_MAXTOK); 1367276da39aSCy Schubert if (rc <= 0) 1368276da39aSCy Schubert return FALSE; 13692b15cb3dSCy Schubert ctx->buf = buf; 1370276da39aSCy Schubert ctx->ntok = rc; 1371276da39aSCy Schubert 1372276da39aSCy Schubert if (JSMN_OBJECT != ctx->tok[0].type) 1373276da39aSCy Schubert return FALSE; /* not object!?! */ 13742b15cb3dSCy Schubert 13752b15cb3dSCy Schubert /* Make all tokens NUL terminated by overwriting the 1376276da39aSCy Schubert * terminator symbol. Makes string compares and number parsing a 1377276da39aSCy Schubert * lot easier! 13782b15cb3dSCy Schubert */ 1379276da39aSCy Schubert for (idx = 0; idx < ctx->ntok; ++idx) 13802b15cb3dSCy Schubert if (ctx->tok[idx].end > ctx->tok[idx].start) 13812b15cb3dSCy Schubert ctx->buf[ctx->tok[idx].end] = '\0'; 13822b15cb3dSCy Schubert return TRUE; 13832b15cb3dSCy Schubert } 13842b15cb3dSCy Schubert 13852b15cb3dSCy Schubert 13862b15cb3dSCy Schubert /* ===================================================================== 13872b15cb3dSCy Schubert * static local helpers 13882b15cb3dSCy Schubert */ 1389276da39aSCy Schubert static BOOL 1390276da39aSCy Schubert get_binary_time( 1391276da39aSCy Schubert l_fp * const dest , 1392276da39aSCy Schubert json_ctx * const jctx , 1393276da39aSCy Schubert const char * const time_name, 1394276da39aSCy Schubert const char * const frac_name, 1395276da39aSCy Schubert long fscale ) 1396276da39aSCy Schubert { 1397276da39aSCy Schubert BOOL retv = FALSE; 1398276da39aSCy Schubert struct timespec ts; 1399276da39aSCy Schubert 1400276da39aSCy Schubert errno = 0; 1401276da39aSCy Schubert ts.tv_sec = (time_t)json_object_lookup_int(jctx, 0, time_name); 1402276da39aSCy Schubert ts.tv_nsec = (long )json_object_lookup_int(jctx, 0, frac_name); 1403276da39aSCy Schubert if (0 == errno) { 1404276da39aSCy Schubert ts.tv_nsec *= fscale; 1405276da39aSCy Schubert *dest = tspec_stamp_to_lfp(ts); 1406276da39aSCy Schubert retv = TRUE; 1407276da39aSCy Schubert } 1408276da39aSCy Schubert return retv; 1409276da39aSCy Schubert } 14102b15cb3dSCy Schubert 14112b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 14122b15cb3dSCy Schubert /* Process a WATCH record 14132b15cb3dSCy Schubert * 14142b15cb3dSCy Schubert * Currently this is only used to recognise that the device is present 14152b15cb3dSCy Schubert * and that we're listed subscribers. 14162b15cb3dSCy Schubert */ 14172b15cb3dSCy Schubert static void 14182b15cb3dSCy Schubert process_watch( 14192b15cb3dSCy Schubert peerT * const peer , 14202b15cb3dSCy Schubert json_ctx * const jctx , 14212b15cb3dSCy Schubert const l_fp * const rtime) 14222b15cb3dSCy Schubert { 14232b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 14242b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 14252b15cb3dSCy Schubert 1426276da39aSCy Schubert const char * path; 1427276da39aSCy Schubert 1428276da39aSCy Schubert path = json_object_lookup_string(jctx, 0, "device"); 1429276da39aSCy Schubert if (NULL == path || strcmp(path, up->device)) 1430276da39aSCy Schubert return; 1431276da39aSCy Schubert 1432276da39aSCy Schubert if (json_object_lookup_bool(jctx, 0, "enable") > 0 && 1433276da39aSCy Schubert json_object_lookup_bool(jctx, 0, "json" ) > 0 ) 14342b15cb3dSCy Schubert up->fl_watch = -1; 1435276da39aSCy Schubert else 1436276da39aSCy Schubert up->fl_watch = 0; 1437276da39aSCy Schubert DPRINTF(2, ("%s: process_watch, enabled=%d\n", 1438276da39aSCy Schubert up->logname, (up->fl_watch & 1))); 14392b15cb3dSCy Schubert } 14402b15cb3dSCy Schubert 14412b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 14422b15cb3dSCy Schubert 14432b15cb3dSCy Schubert static void 14442b15cb3dSCy Schubert process_version( 14452b15cb3dSCy Schubert peerT * const peer , 14462b15cb3dSCy Schubert json_ctx * const jctx , 14472b15cb3dSCy Schubert const l_fp * const rtime) 14482b15cb3dSCy Schubert { 14492b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 14502b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 14512b15cb3dSCy Schubert 14522b15cb3dSCy Schubert int len; 14532b15cb3dSCy Schubert char * buf; 14542b15cb3dSCy Schubert const char *revision; 14552b15cb3dSCy Schubert const char *release; 1456276da39aSCy Schubert uint16_t pvhi, pvlo; 14572b15cb3dSCy Schubert 14582b15cb3dSCy Schubert /* get protocol version number */ 14592b15cb3dSCy Schubert revision = json_object_lookup_string_default( 14602b15cb3dSCy Schubert jctx, 0, "rev", "(unknown)"); 14612b15cb3dSCy Schubert release = json_object_lookup_string_default( 14622b15cb3dSCy Schubert jctx, 0, "release", "(unknown)"); 14632b15cb3dSCy Schubert errno = 0; 1464276da39aSCy Schubert pvhi = (uint16_t)json_object_lookup_int(jctx, 0, "proto_major"); 1465276da39aSCy Schubert pvlo = (uint16_t)json_object_lookup_int(jctx, 0, "proto_minor"); 1466276da39aSCy Schubert 14672b15cb3dSCy Schubert if (0 == errno) { 1468276da39aSCy Schubert if ( ! up->fl_vers) 14692b15cb3dSCy Schubert msyslog(LOG_INFO, 14702b15cb3dSCy Schubert "%s: GPSD revision=%s release=%s protocol=%u.%u", 1471276da39aSCy Schubert up->logname, revision, release, 1472276da39aSCy Schubert pvhi, pvlo); 1473276da39aSCy Schubert up->proto_version = PROTO_VERSION(pvhi, pvlo); 1474276da39aSCy Schubert up->fl_vers = -1; 1475276da39aSCy Schubert } else { 1476276da39aSCy Schubert if (syslogok(pp, up)) 1477276da39aSCy Schubert msyslog(LOG_INFO, 1478276da39aSCy Schubert "%s: could not evaluate version data", 1479276da39aSCy Schubert up->logname); 1480276da39aSCy Schubert return; 14812b15cb3dSCy Schubert } 1482276da39aSCy Schubert /* With the 3.9 GPSD protocol, '*_musec' vanished from the PPS 1483276da39aSCy Schubert * record and was replace by '*_nsec'. 14842b15cb3dSCy Schubert */ 1485276da39aSCy Schubert up->pf_nsec = -(up->proto_version >= PROTO_VERSION(3,9)); 14862b15cb3dSCy Schubert 1487276da39aSCy Schubert /* With the 3.10 protocol we can get TOFF records for better 1488276da39aSCy Schubert * timing information. 1489276da39aSCy Schubert */ 1490276da39aSCy Schubert up->pf_toff = -(up->proto_version >= PROTO_VERSION(3,10)); 14912b15cb3dSCy Schubert 1492276da39aSCy Schubert /* request watch for our GPS device if not yet watched. 1493276da39aSCy Schubert * 1494276da39aSCy Schubert * The version string is also sent as a life signal, if we have 1495276da39aSCy Schubert * seen useable data. So if we're already watching the device, 1496276da39aSCy Schubert * skip the request. 1497276da39aSCy Schubert * 14982b15cb3dSCy Schubert * Reuse the input buffer, which is no longer needed in the 14992b15cb3dSCy Schubert * current cycle. Also assume that we can write the watch 15002b15cb3dSCy Schubert * request in one sweep into the socket; since we do not do 15012b15cb3dSCy Schubert * output otherwise, this should always work. (Unless the 15022b15cb3dSCy Schubert * TCP/IP window size gets lower than the length of the 15032b15cb3dSCy Schubert * request. We handle that when it happens.) 15042b15cb3dSCy Schubert */ 1505276da39aSCy Schubert if (up->fl_watch) 1506276da39aSCy Schubert return; 1507276da39aSCy Schubert 150868ba7e87SXin LI /* The logon string is actually the ?WATCH command of GPSD, 150968ba7e87SXin LI * using JSON data and selecting the GPS device name we created 151068ba7e87SXin LI * from our unit number. We have an old a newer version that 151168ba7e87SXin LI * request PPS (and TOFF) transmission. 151268ba7e87SXin LI */ 15132b15cb3dSCy Schubert snprintf(up->buffer, sizeof(up->buffer), 151468ba7e87SXin LI "?WATCH={\"device\":\"%s\",\"enable\":true,\"json\":true%s};\r\n", 151568ba7e87SXin LI up->device, (up->pf_toff ? ",\"pps\":true" : "")); 15162b15cb3dSCy Schubert buf = up->buffer; 15172b15cb3dSCy Schubert len = strlen(buf); 1518276da39aSCy Schubert log_data(peer, "send", buf, len); 1519276da39aSCy Schubert if (len != write(pp->io.fd, buf, len) && (syslogok(pp, up))) { 15202b15cb3dSCy Schubert /* Note: if the server fails to read our request, the 15212b15cb3dSCy Schubert * resulting data timeout will take care of the 15222b15cb3dSCy Schubert * connection! 15232b15cb3dSCy Schubert */ 1524276da39aSCy Schubert msyslog(LOG_ERR, "%s: failed to write watch request (%m)", 1525276da39aSCy Schubert up->logname); 15262b15cb3dSCy Schubert } 15272b15cb3dSCy Schubert } 15282b15cb3dSCy Schubert 15292b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 15302b15cb3dSCy Schubert 15312b15cb3dSCy Schubert static void 15322b15cb3dSCy Schubert process_tpv( 15332b15cb3dSCy Schubert peerT * const peer , 15342b15cb3dSCy Schubert json_ctx * const jctx , 15352b15cb3dSCy Schubert const l_fp * const rtime) 15362b15cb3dSCy Schubert { 15372b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 15382b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 15392b15cb3dSCy Schubert 15402b15cb3dSCy Schubert const char * gps_time; 15412b15cb3dSCy Schubert int gps_mode; 1542276da39aSCy Schubert double ept; 15432b15cb3dSCy Schubert int xlog2; 15442b15cb3dSCy Schubert 15452b15cb3dSCy Schubert gps_mode = (int)json_object_lookup_int_default( 15462b15cb3dSCy Schubert jctx, 0, "mode", 0); 15472b15cb3dSCy Schubert 1548276da39aSCy Schubert gps_time = json_object_lookup_string( 1549276da39aSCy Schubert jctx, 0, "time"); 15502b15cb3dSCy Schubert 1551276da39aSCy Schubert /* accept time stamps only in 2d or 3d fix */ 1552276da39aSCy Schubert if (gps_mode < 2 || NULL == gps_time) { 15532b15cb3dSCy Schubert /* receiver has no fix; tell about and avoid stale data */ 1554276da39aSCy Schubert if ( ! up->pf_toff) 1555276da39aSCy Schubert ++up->tc_sti_recv; 1556276da39aSCy Schubert ++up->tc_nosync; 1557276da39aSCy Schubert up->fl_sti = 0; 15582b15cb3dSCy Schubert up->fl_pps = 0; 1559276da39aSCy Schubert up->fl_nosync = -1; 15602b15cb3dSCy Schubert return; 15612b15cb3dSCy Schubert } 1562276da39aSCy Schubert up->fl_nosync = 0; 15632b15cb3dSCy Schubert 1564276da39aSCy Schubert /* convert clock and set resulting ref time, but only if the 1565276da39aSCy Schubert * TOFF sentence is *not* available 1566276da39aSCy Schubert */ 1567276da39aSCy Schubert if ( ! up->pf_toff) { 1568276da39aSCy Schubert ++up->tc_sti_recv; 15692b15cb3dSCy Schubert /* save last time code to clock data */ 15702b15cb3dSCy Schubert save_ltc(pp, gps_time); 1571276da39aSCy Schubert /* now parse the time string */ 1572276da39aSCy Schubert if (convert_ascii_time(&up->sti_stamp, gps_time)) { 1573276da39aSCy Schubert DPRINTF(2, ("%s: process_tpv, stamp='%s'," 1574276da39aSCy Schubert " recvt='%s' mode=%u\n", 1575276da39aSCy Schubert up->logname, 1576276da39aSCy Schubert gmprettydate(&up->sti_stamp), 1577276da39aSCy Schubert gmprettydate(&up->sti_recvt), 15782b15cb3dSCy Schubert gps_mode)); 15792b15cb3dSCy Schubert 1580276da39aSCy Schubert /* have to use local receive time as substitute 1581276da39aSCy Schubert * for the real receive time: TPV does not tell 1582276da39aSCy Schubert * us. 1583276da39aSCy Schubert */ 1584276da39aSCy Schubert up->sti_local = *rtime; 1585276da39aSCy Schubert up->sti_recvt = *rtime; 1586276da39aSCy Schubert L_SUB(&up->sti_recvt, &up->sti_fudge); 1587276da39aSCy Schubert up->fl_sti = -1; 15882b15cb3dSCy Schubert } else { 1589276da39aSCy Schubert ++up->tc_breply; 1590276da39aSCy Schubert up->fl_sti = 0; 1591276da39aSCy Schubert } 15922b15cb3dSCy Schubert } 15932b15cb3dSCy Schubert 15942b15cb3dSCy Schubert /* Set the precision from the GPSD data 1595276da39aSCy Schubert * Use the ETP field for an estimation of the precision of the 1596276da39aSCy Schubert * serial data. If ETP is not available, use the default serial 1597276da39aSCy Schubert * data presion instead. (Note: The PPS branch has a different 1598276da39aSCy Schubert * precision estimation, since it gets the proper value directly 1599276da39aSCy Schubert * from GPSD!) 16002b15cb3dSCy Schubert */ 1601276da39aSCy Schubert ept = json_object_lookup_float_default(jctx, 0, "ept", 2.0e-3); 1602276da39aSCy Schubert ept = frexp(fabs(ept)*0.70710678, &xlog2); /* ~ sqrt(0.5) */ 1603276da39aSCy Schubert if (ept < 0.25) 1604276da39aSCy Schubert xlog2 = INT_MIN; 1605276da39aSCy Schubert if (ept > 2.0) 1606276da39aSCy Schubert xlog2 = INT_MAX; 1607276da39aSCy Schubert up->sti_prec = clamped_precision(xlog2); 16082b15cb3dSCy Schubert } 16092b15cb3dSCy Schubert 16102b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 16112b15cb3dSCy Schubert 16122b15cb3dSCy Schubert static void 16132b15cb3dSCy Schubert process_pps( 16142b15cb3dSCy Schubert peerT * const peer , 16152b15cb3dSCy Schubert json_ctx * const jctx , 16162b15cb3dSCy Schubert const l_fp * const rtime) 16172b15cb3dSCy Schubert { 16182b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 16192b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 16202b15cb3dSCy Schubert 1621276da39aSCy Schubert int xlog2; 16222b15cb3dSCy Schubert 1623276da39aSCy Schubert ++up->tc_pps_recv; 16242b15cb3dSCy Schubert 1625276da39aSCy Schubert /* Bail out if there's indication that time sync is bad or 1626276da39aSCy Schubert * if we're explicitely requested to ignore PPS data. 1627276da39aSCy Schubert */ 1628276da39aSCy Schubert if (up->fl_nosync) 1629276da39aSCy Schubert return; 16302b15cb3dSCy Schubert 16312b15cb3dSCy Schubert up->pps_local = *rtime; 1632276da39aSCy Schubert /* Now grab the time values. 'clock_*' is the event time of the 1633276da39aSCy Schubert * pulse measured on the local system clock; 'real_*' is the GPS 1634276da39aSCy Schubert * reference time GPSD associated with the pulse. 1635276da39aSCy Schubert */ 1636276da39aSCy Schubert if (up->pf_nsec) { 1637276da39aSCy Schubert if ( ! get_binary_time(&up->pps_recvt2, jctx, 1638276da39aSCy Schubert "clock_sec", "clock_nsec", 1)) 1639276da39aSCy Schubert goto fail; 1640276da39aSCy Schubert if ( ! get_binary_time(&up->pps_stamp2, jctx, 1641276da39aSCy Schubert "real_sec", "real_nsec", 1)) 1642276da39aSCy Schubert goto fail; 1643276da39aSCy Schubert } else { 1644276da39aSCy Schubert if ( ! get_binary_time(&up->pps_recvt2, jctx, 1645276da39aSCy Schubert "clock_sec", "clock_musec", 1000)) 1646276da39aSCy Schubert goto fail; 1647276da39aSCy Schubert if ( ! get_binary_time(&up->pps_stamp2, jctx, 1648276da39aSCy Schubert "real_sec", "real_musec", 1000)) 1649276da39aSCy Schubert goto fail; 1650276da39aSCy Schubert } 16512b15cb3dSCy Schubert 1652276da39aSCy Schubert /* Try to read the precision field from the PPS record. If it's 1653276da39aSCy Schubert * not there, take the precision from the serial data. 1654276da39aSCy Schubert */ 1655276da39aSCy Schubert xlog2 = json_object_lookup_int_default( 1656276da39aSCy Schubert jctx, 0, "precision", up->sti_prec); 1657276da39aSCy Schubert up->pps_prec = clamped_precision(xlog2); 1658276da39aSCy Schubert 1659276da39aSCy Schubert /* Get fudged receive times for primary & secondary unit */ 1660276da39aSCy Schubert up->pps_recvt = up->pps_recvt2; 1661276da39aSCy Schubert L_SUB(&up->pps_recvt , &up->pps_fudge ); 1662276da39aSCy Schubert L_SUB(&up->pps_recvt2, &up->pps_fudge2); 1663276da39aSCy Schubert pp->lastrec = up->pps_recvt; 1664276da39aSCy Schubert 1665276da39aSCy Schubert /* Map to nearest full second as reference time stamp for the 1666276da39aSCy Schubert * primary channel. Sanity checks are done in evaluation step. 1667276da39aSCy Schubert */ 16682b15cb3dSCy Schubert up->pps_stamp = up->pps_recvt; 16692b15cb3dSCy Schubert L_ADDUF(&up->pps_stamp, 0x80000000u); 16702b15cb3dSCy Schubert up->pps_stamp.l_uf = 0; 16712b15cb3dSCy Schubert 1672276da39aSCy Schubert if (NULL != up->pps_peer) 1673276da39aSCy Schubert save_ltc(up->pps_peer->procptr, 1674276da39aSCy Schubert gmprettydate(&up->pps_stamp2)); 1675276da39aSCy Schubert DPRINTF(2, ("%s: PPS record processed," 1676276da39aSCy Schubert " stamp='%s', recvt='%s'\n", 1677276da39aSCy Schubert up->logname, 1678276da39aSCy Schubert gmprettydate(&up->pps_stamp2), 1679276da39aSCy Schubert gmprettydate(&up->pps_recvt2))); 16802b15cb3dSCy Schubert 1681276da39aSCy Schubert up->fl_pps = (0 != (pp->sloppyclockflag & CLK_FLAG2)) - 1; 1682276da39aSCy Schubert up->fl_pps2 = -1; 16832b15cb3dSCy Schubert return; 16842b15cb3dSCy Schubert 16852b15cb3dSCy Schubert fail: 1686276da39aSCy Schubert DPRINTF(1, ("%s: PPS record processing FAILED\n", 1687276da39aSCy Schubert up->logname)); 1688276da39aSCy Schubert ++up->tc_breply; 1689276da39aSCy Schubert } 1690276da39aSCy Schubert 1691276da39aSCy Schubert /* ------------------------------------------------------------------ */ 1692276da39aSCy Schubert 1693276da39aSCy Schubert static void 1694276da39aSCy Schubert process_toff( 1695276da39aSCy Schubert peerT * const peer , 1696276da39aSCy Schubert json_ctx * const jctx , 1697276da39aSCy Schubert const l_fp * const rtime) 1698276da39aSCy Schubert { 1699276da39aSCy Schubert clockprocT * const pp = peer->procptr; 1700276da39aSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 1701276da39aSCy Schubert 1702276da39aSCy Schubert ++up->tc_sti_recv; 1703276da39aSCy Schubert 1704276da39aSCy Schubert /* remember this! */ 1705276da39aSCy Schubert up->pf_toff = -1; 1706276da39aSCy Schubert 1707276da39aSCy Schubert /* bail out if there's indication that time sync is bad */ 1708276da39aSCy Schubert if (up->fl_nosync) 1709276da39aSCy Schubert return; 1710276da39aSCy Schubert 1711276da39aSCy Schubert if ( ! get_binary_time(&up->sti_recvt, jctx, 1712276da39aSCy Schubert "clock_sec", "clock_nsec", 1)) 1713276da39aSCy Schubert goto fail; 1714276da39aSCy Schubert if ( ! get_binary_time(&up->sti_stamp, jctx, 1715276da39aSCy Schubert "real_sec", "real_nsec", 1)) 1716276da39aSCy Schubert goto fail; 1717276da39aSCy Schubert L_SUB(&up->sti_recvt, &up->sti_fudge); 1718276da39aSCy Schubert up->sti_local = *rtime; 1719276da39aSCy Schubert up->fl_sti = -1; 1720276da39aSCy Schubert 1721276da39aSCy Schubert save_ltc(pp, gmprettydate(&up->sti_stamp)); 1722276da39aSCy Schubert DPRINTF(2, ("%s: TOFF record processed," 1723276da39aSCy Schubert " stamp='%s', recvt='%s'\n", 1724276da39aSCy Schubert up->logname, 1725276da39aSCy Schubert gmprettydate(&up->sti_stamp), 1726276da39aSCy Schubert gmprettydate(&up->sti_recvt))); 1727276da39aSCy Schubert return; 1728276da39aSCy Schubert 1729276da39aSCy Schubert fail: 1730276da39aSCy Schubert DPRINTF(1, ("%s: TOFF record processing FAILED\n", 1731276da39aSCy Schubert up->logname)); 1732276da39aSCy Schubert ++up->tc_breply; 17332b15cb3dSCy Schubert } 17342b15cb3dSCy Schubert 17352b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 17362b15cb3dSCy Schubert 17372b15cb3dSCy Schubert static void 17382b15cb3dSCy Schubert gpsd_parse( 17392b15cb3dSCy Schubert peerT * const peer , 17402b15cb3dSCy Schubert const l_fp * const rtime) 17412b15cb3dSCy Schubert { 17422b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 17432b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 17442b15cb3dSCy Schubert 17452b15cb3dSCy Schubert const char * clsid; 17462b15cb3dSCy Schubert 1747276da39aSCy Schubert DPRINTF(2, ("%s: gpsd_parse: time %s '%.*s'\n", 1748276da39aSCy Schubert up->logname, ulfptoa(rtime, 6), 1749276da39aSCy Schubert up->buflen, up->buffer)); 17502b15cb3dSCy Schubert 1751276da39aSCy Schubert /* See if we can grab anything potentially useful. JSMN does not 1752276da39aSCy Schubert * need a trailing NUL, but it needs the number of bytes to 1753276da39aSCy Schubert * process. */ 1754276da39aSCy Schubert if (!json_parse_record(&up->json_parse, up->buffer, up->buflen)) { 1755276da39aSCy Schubert ++up->tc_breply; 17562b15cb3dSCy Schubert return; 1757276da39aSCy Schubert } 17582b15cb3dSCy Schubert 17592b15cb3dSCy Schubert /* Now dispatch over the objects we know */ 1760276da39aSCy Schubert clsid = json_object_lookup_string(&up->json_parse, 0, "class"); 1761276da39aSCy Schubert if (NULL == clsid) { 1762276da39aSCy Schubert ++up->tc_breply; 1763276da39aSCy Schubert return; 1764276da39aSCy Schubert } 17652b15cb3dSCy Schubert 1766276da39aSCy Schubert if (!strcmp("TPV", clsid)) 1767276da39aSCy Schubert process_tpv(peer, &up->json_parse, rtime); 17682b15cb3dSCy Schubert else if (!strcmp("PPS", clsid)) 1769276da39aSCy Schubert process_pps(peer, &up->json_parse, rtime); 1770276da39aSCy Schubert else if (!strcmp("TOFF", clsid)) 1771276da39aSCy Schubert process_toff(peer, &up->json_parse, rtime); 1772276da39aSCy Schubert else if (!strcmp("VERSION", clsid)) 1773276da39aSCy Schubert process_version(peer, &up->json_parse, rtime); 17742b15cb3dSCy Schubert else if (!strcmp("WATCH", clsid)) 1775276da39aSCy Schubert process_watch(peer, &up->json_parse, rtime); 17762b15cb3dSCy Schubert else 17772b15cb3dSCy Schubert return; /* nothing we know about... */ 1778276da39aSCy Schubert ++up->tc_recv; 17792b15cb3dSCy Schubert 1780276da39aSCy Schubert /* if possible, feed the PPS side channel */ 1781276da39aSCy Schubert if (up->pps_peer) 1782276da39aSCy Schubert eval_pps_secondary( 1783276da39aSCy Schubert up->pps_peer, up->pps_peer->procptr, up); 17842b15cb3dSCy Schubert 1785276da39aSCy Schubert /* check PPS vs. STI receive times: 1786276da39aSCy Schubert * If STI is before PPS, then clearly the STI is too old. If PPS 1787276da39aSCy Schubert * is before STI by more than one second, then PPS is too old. 1788276da39aSCy Schubert * Weed out stale time stamps & flags. 1789276da39aSCy Schubert */ 1790276da39aSCy Schubert if (up->fl_pps && up->fl_sti) { 1791276da39aSCy Schubert l_fp diff; 1792276da39aSCy Schubert diff = up->sti_local; 1793276da39aSCy Schubert L_SUB(&diff, &up->pps_local); 1794276da39aSCy Schubert if (diff.l_i > 0) 1795276da39aSCy Schubert up->fl_pps = 0; /* pps too old */ 1796276da39aSCy Schubert else if (diff.l_i < 0) 1797276da39aSCy Schubert up->fl_sti = 0; /* serial data too old */ 17982b15cb3dSCy Schubert } 1799276da39aSCy Schubert 1800276da39aSCy Schubert /* dispatch to the mode-dependent processing functions */ 1801276da39aSCy Schubert switch (up->mode) { 1802276da39aSCy Schubert default: 1803276da39aSCy Schubert case MODE_OP_STI: 1804276da39aSCy Schubert eval_serial(peer, pp, up); 1805276da39aSCy Schubert break; 1806276da39aSCy Schubert 1807276da39aSCy Schubert case MODE_OP_STRICT: 1808276da39aSCy Schubert eval_strict(peer, pp, up); 1809276da39aSCy Schubert break; 1810276da39aSCy Schubert 1811276da39aSCy Schubert case MODE_OP_AUTO: 1812276da39aSCy Schubert eval_auto(peer, pp, up); 1813276da39aSCy Schubert break; 18142b15cb3dSCy Schubert } 18152b15cb3dSCy Schubert } 18162b15cb3dSCy Schubert 18172b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 18182b15cb3dSCy Schubert 18192b15cb3dSCy Schubert static void 18202b15cb3dSCy Schubert gpsd_stop_socket( 18212b15cb3dSCy Schubert peerT * const peer) 18222b15cb3dSCy Schubert { 18232b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 18242b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 18252b15cb3dSCy Schubert 1826276da39aSCy Schubert if (-1 != pp->io.fd) { 18272b15cb3dSCy Schubert if (syslogok(pp, up)) 18282b15cb3dSCy Schubert msyslog(LOG_INFO, 1829276da39aSCy Schubert "%s: closing socket to GPSD, fd=%d", 1830276da39aSCy Schubert up->logname, pp->io.fd); 1831276da39aSCy Schubert else 1832276da39aSCy Schubert DPRINTF(1, ("%s: closing socket to GPSD, fd=%d\n", 1833276da39aSCy Schubert up->logname, pp->io.fd)); 1834276da39aSCy Schubert io_closeclock(&pp->io); 1835276da39aSCy Schubert pp->io.fd = -1; 1836276da39aSCy Schubert } 18372b15cb3dSCy Schubert up->tickover = up->tickpres; 18382b15cb3dSCy Schubert up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH); 18392b15cb3dSCy Schubert up->fl_vers = 0; 1840276da39aSCy Schubert up->fl_sti = 0; 18412b15cb3dSCy Schubert up->fl_pps = 0; 18422b15cb3dSCy Schubert up->fl_watch = 0; 18432b15cb3dSCy Schubert } 18442b15cb3dSCy Schubert 18452b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 18462b15cb3dSCy Schubert 18472b15cb3dSCy Schubert static void 18482b15cb3dSCy Schubert gpsd_init_socket( 18492b15cb3dSCy Schubert peerT * const peer) 18502b15cb3dSCy Schubert { 18512b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 18522b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 18532b15cb3dSCy Schubert addrinfoT * ai; 18542b15cb3dSCy Schubert int rc; 18552b15cb3dSCy Schubert int ov; 18562b15cb3dSCy Schubert 18572b15cb3dSCy Schubert /* draw next address to try */ 18582b15cb3dSCy Schubert if (NULL == up->addr) 18592b15cb3dSCy Schubert up->addr = s_gpsd_addr; 18602b15cb3dSCy Schubert ai = up->addr; 18612b15cb3dSCy Schubert up->addr = ai->ai_next; 18622b15cb3dSCy Schubert 18632b15cb3dSCy Schubert /* try to create a matching socket */ 18642b15cb3dSCy Schubert up->fdt = socket( 18652b15cb3dSCy Schubert ai->ai_family, ai->ai_socktype, ai->ai_protocol); 18662b15cb3dSCy Schubert if (-1 == up->fdt) { 18672b15cb3dSCy Schubert if (syslogok(pp, up)) 18682b15cb3dSCy Schubert msyslog(LOG_ERR, 18692b15cb3dSCy Schubert "%s: cannot create GPSD socket: %m", 1870276da39aSCy Schubert up->logname); 18712b15cb3dSCy Schubert goto no_socket; 18722b15cb3dSCy Schubert } 18732b15cb3dSCy Schubert 1874276da39aSCy Schubert /* Make sure the socket is non-blocking. Connect/reconnect and 1875276da39aSCy Schubert * IO happen in an event-driven environment, and synchronous 1876276da39aSCy Schubert * operations wreak havoc on that. 1877276da39aSCy Schubert */ 18782b15cb3dSCy Schubert rc = fcntl(up->fdt, F_SETFL, O_NONBLOCK, 1); 18792b15cb3dSCy Schubert if (-1 == rc) { 18802b15cb3dSCy Schubert if (syslogok(pp, up)) 18812b15cb3dSCy Schubert msyslog(LOG_ERR, 18822b15cb3dSCy Schubert "%s: cannot set GPSD socket to non-blocking: %m", 1883276da39aSCy Schubert up->logname); 18842b15cb3dSCy Schubert goto no_socket; 18852b15cb3dSCy Schubert } 1886276da39aSCy Schubert /* Disable nagling. The way both GPSD and NTPD handle the 1887276da39aSCy Schubert * protocol makes it record-oriented, and in most cases 1888276da39aSCy Schubert * complete records (JSON serialised objects) will be sent in 1889276da39aSCy Schubert * one sweep. Nagling gives not much advantage but adds another 1890276da39aSCy Schubert * delay, which can worsen the situation for some packets. 1891276da39aSCy Schubert */ 18922b15cb3dSCy Schubert ov = 1; 18932b15cb3dSCy Schubert rc = setsockopt(up->fdt, IPPROTO_TCP, TCP_NODELAY, 18942b15cb3dSCy Schubert (char*)&ov, sizeof(ov)); 18952b15cb3dSCy Schubert if (-1 == rc) { 18962b15cb3dSCy Schubert if (syslogok(pp, up)) 18972b15cb3dSCy Schubert msyslog(LOG_INFO, 18982b15cb3dSCy Schubert "%s: cannot disable TCP nagle: %m", 1899276da39aSCy Schubert up->logname); 19002b15cb3dSCy Schubert } 19012b15cb3dSCy Schubert 1902276da39aSCy Schubert /* Start a non-blocking connect. There might be a synchronous 1903276da39aSCy Schubert * connection result we have to handle. 1904276da39aSCy Schubert */ 19052b15cb3dSCy Schubert rc = connect(up->fdt, ai->ai_addr, ai->ai_addrlen); 1906276da39aSCy Schubert if (-1 == rc) { 1907276da39aSCy Schubert if (errno == EINPROGRESS) { 1908276da39aSCy Schubert DPRINTF(1, ("%s: async connect pending, fd=%d\n", 1909276da39aSCy Schubert up->logname, up->fdt)); 1910276da39aSCy Schubert return; 1911276da39aSCy Schubert } 1912276da39aSCy Schubert 19132b15cb3dSCy Schubert if (syslogok(pp, up)) 19142b15cb3dSCy Schubert msyslog(LOG_ERR, 19152b15cb3dSCy Schubert "%s: cannot connect GPSD socket: %m", 1916276da39aSCy Schubert up->logname); 1917276da39aSCy Schubert goto no_socket; 1918276da39aSCy Schubert } 1919276da39aSCy Schubert 1920276da39aSCy Schubert /* We had a successful synchronous connect, so we add the 1921276da39aSCy Schubert * refclock processing ASAP. We still have to wait for the 1922276da39aSCy Schubert * version string and apply the watch command later on, but we 1923276da39aSCy Schubert * might as well get the show on the road now. 1924276da39aSCy Schubert */ 1925276da39aSCy Schubert DPRINTF(1, ("%s: new socket connection, fd=%d\n", 1926276da39aSCy Schubert up->logname, up->fdt)); 1927276da39aSCy Schubert 1928276da39aSCy Schubert pp->io.fd = up->fdt; 1929276da39aSCy Schubert up->fdt = -1; 1930276da39aSCy Schubert if (0 == io_addclock(&pp->io)) { 1931276da39aSCy Schubert if (syslogok(pp, up)) 1932276da39aSCy Schubert msyslog(LOG_ERR, 1933276da39aSCy Schubert "%s: failed to register with I/O engine", 1934276da39aSCy Schubert up->logname); 19352b15cb3dSCy Schubert goto no_socket; 19362b15cb3dSCy Schubert } 19372b15cb3dSCy Schubert 19382b15cb3dSCy Schubert return; 19392b15cb3dSCy Schubert 19402b15cb3dSCy Schubert no_socket: 1941276da39aSCy Schubert if (-1 != pp->io.fd) 1942276da39aSCy Schubert close(pp->io.fd); 19432b15cb3dSCy Schubert if (-1 != up->fdt) 19442b15cb3dSCy Schubert close(up->fdt); 1945276da39aSCy Schubert pp->io.fd = -1; 19462b15cb3dSCy Schubert up->fdt = -1; 19472b15cb3dSCy Schubert up->tickover = up->tickpres; 19482b15cb3dSCy Schubert up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH); 19492b15cb3dSCy Schubert } 19502b15cb3dSCy Schubert 19512b15cb3dSCy Schubert /* ------------------------------------------------------------------ */ 19522b15cb3dSCy Schubert 19532b15cb3dSCy Schubert static void 19542b15cb3dSCy Schubert gpsd_test_socket( 19552b15cb3dSCy Schubert peerT * const peer) 19562b15cb3dSCy Schubert { 19572b15cb3dSCy Schubert clockprocT * const pp = peer->procptr; 19582b15cb3dSCy Schubert gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; 19592b15cb3dSCy Schubert 19602b15cb3dSCy Schubert int ec, rc; 19612b15cb3dSCy Schubert socklen_t lc; 19622b15cb3dSCy Schubert 19632b15cb3dSCy Schubert /* Check if the non-blocking connect was finished by testing the 19642b15cb3dSCy Schubert * socket for writeability. Use the 'poll()' API if available 19652b15cb3dSCy Schubert * and 'select()' otherwise. 19662b15cb3dSCy Schubert */ 1967276da39aSCy Schubert DPRINTF(2, ("%s: check connect, fd=%d\n", 1968276da39aSCy Schubert up->logname, up->fdt)); 19692b15cb3dSCy Schubert 19702b15cb3dSCy Schubert #if defined(HAVE_SYS_POLL_H) 19712b15cb3dSCy Schubert { 19722b15cb3dSCy Schubert struct pollfd pfd; 19732b15cb3dSCy Schubert 19742b15cb3dSCy Schubert pfd.events = POLLOUT; 19752b15cb3dSCy Schubert pfd.fd = up->fdt; 19762b15cb3dSCy Schubert rc = poll(&pfd, 1, 0); 19772b15cb3dSCy Schubert if (1 != rc || !(pfd.revents & POLLOUT)) 19782b15cb3dSCy Schubert return; 19792b15cb3dSCy Schubert } 19802b15cb3dSCy Schubert #elif defined(HAVE_SYS_SELECT_H) 19812b15cb3dSCy Schubert { 19822b15cb3dSCy Schubert struct timeval tout; 19832b15cb3dSCy Schubert fd_set wset; 19842b15cb3dSCy Schubert 19852b15cb3dSCy Schubert memset(&tout, 0, sizeof(tout)); 19862b15cb3dSCy Schubert FD_ZERO(&wset); 19872b15cb3dSCy Schubert FD_SET(up->fdt, &wset); 19882b15cb3dSCy Schubert rc = select(up->fdt+1, NULL, &wset, NULL, &tout); 19892b15cb3dSCy Schubert if (0 == rc || !(FD_ISSET(up->fdt, &wset))) 19902b15cb3dSCy Schubert return; 19912b15cb3dSCy Schubert } 19922b15cb3dSCy Schubert #else 19932b15cb3dSCy Schubert # error Blooper! That should have been found earlier! 19942b15cb3dSCy Schubert #endif 19952b15cb3dSCy Schubert 19962b15cb3dSCy Schubert /* next timeout is a full one... */ 19972b15cb3dSCy Schubert up->tickover = TICKOVER_LOW; 19982b15cb3dSCy Schubert 19992b15cb3dSCy Schubert /* check for socket error */ 20002b15cb3dSCy Schubert ec = 0; 20012b15cb3dSCy Schubert lc = sizeof(ec); 20022b15cb3dSCy Schubert rc = getsockopt(up->fdt, SOL_SOCKET, SO_ERROR, &ec, &lc); 20032b15cb3dSCy Schubert if (-1 == rc || 0 != ec) { 2004276da39aSCy Schubert const char *errtxt; 2005276da39aSCy Schubert if (0 == ec) 2006276da39aSCy Schubert ec = errno; 2007276da39aSCy Schubert errtxt = strerror(ec); 20082b15cb3dSCy Schubert if (syslogok(pp, up)) 20092b15cb3dSCy Schubert msyslog(LOG_ERR, 2010276da39aSCy Schubert "%s: async connect to GPSD failed," 2011276da39aSCy Schubert " fd=%d, ec=%d(%s)", 2012276da39aSCy Schubert up->logname, up->fdt, ec, errtxt); 2013276da39aSCy Schubert else 2014276da39aSCy Schubert DPRINTF(1, ("%s: async connect to GPSD failed," 2015276da39aSCy Schubert " fd=%d, ec=%d(%s)\n", 2016276da39aSCy Schubert up->logname, up->fdt, ec, errtxt)); 20172b15cb3dSCy Schubert goto no_socket; 2018276da39aSCy Schubert } else { 2019276da39aSCy Schubert DPRINTF(1, ("%s: async connect to GPSD succeeded, fd=%d\n", 2020276da39aSCy Schubert up->logname, up->fdt)); 20212b15cb3dSCy Schubert } 2022276da39aSCy Schubert 20232b15cb3dSCy Schubert /* swap socket FDs, and make sure the clock was added */ 20242b15cb3dSCy Schubert pp->io.fd = up->fdt; 20252b15cb3dSCy Schubert up->fdt = -1; 20262b15cb3dSCy Schubert if (0 == io_addclock(&pp->io)) { 20272b15cb3dSCy Schubert if (syslogok(pp, up)) 20282b15cb3dSCy Schubert msyslog(LOG_ERR, 20292b15cb3dSCy Schubert "%s: failed to register with I/O engine", 2030276da39aSCy Schubert up->logname); 20312b15cb3dSCy Schubert goto no_socket; 20322b15cb3dSCy Schubert } 20332b15cb3dSCy Schubert return; 20342b15cb3dSCy Schubert 20352b15cb3dSCy Schubert no_socket: 2036276da39aSCy Schubert if (-1 != up->fdt) { 2037276da39aSCy Schubert DPRINTF(1, ("%s: closing socket, fd=%d\n", 2038276da39aSCy Schubert up->logname, up->fdt)); 20392b15cb3dSCy Schubert close(up->fdt); 2040276da39aSCy Schubert } 20412b15cb3dSCy Schubert up->fdt = -1; 20422b15cb3dSCy Schubert up->tickover = up->tickpres; 20432b15cb3dSCy Schubert up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH); 20442b15cb3dSCy Schubert } 20452b15cb3dSCy Schubert 20462b15cb3dSCy Schubert /* ===================================================================== 20472b15cb3dSCy Schubert * helper stuff 20482b15cb3dSCy Schubert */ 20492b15cb3dSCy Schubert 2050276da39aSCy Schubert /* ------------------------------------------------------------------- 2051276da39aSCy Schubert * store a properly clamped precision value 20522b15cb3dSCy Schubert */ 2053276da39aSCy Schubert static int16_t 2054276da39aSCy Schubert clamped_precision( 2055276da39aSCy Schubert int rawprec) 20562b15cb3dSCy Schubert { 2057276da39aSCy Schubert if (rawprec > 0) 2058276da39aSCy Schubert rawprec = 0; 2059276da39aSCy Schubert if (rawprec < -32) 2060276da39aSCy Schubert rawprec = -32; 2061276da39aSCy Schubert return (int16_t)rawprec; 20622b15cb3dSCy Schubert } 20632b15cb3dSCy Schubert 20642b15cb3dSCy Schubert /* ------------------------------------------------------------------- 2065276da39aSCy Schubert * Convert a GPSD timestamp (ISO8601 Format) to an l_fp 20662b15cb3dSCy Schubert */ 20672b15cb3dSCy Schubert static BOOL 20682b15cb3dSCy Schubert convert_ascii_time( 20692b15cb3dSCy Schubert l_fp * fp , 20702b15cb3dSCy Schubert const char * gps_time) 20712b15cb3dSCy Schubert { 20722b15cb3dSCy Schubert char *ep; 20732b15cb3dSCy Schubert struct tm gd; 20742b15cb3dSCy Schubert struct timespec ts; 2075276da39aSCy Schubert uint32_t dw; 20762b15cb3dSCy Schubert 20772b15cb3dSCy Schubert /* Use 'strptime' to take the brunt of the work, then parse 20782b15cb3dSCy Schubert * the fractional part manually, starting with a digit weight of 20792b15cb3dSCy Schubert * 10^8 nanoseconds. 20802b15cb3dSCy Schubert */ 20812b15cb3dSCy Schubert ts.tv_nsec = 0; 20822b15cb3dSCy Schubert ep = strptime(gps_time, "%Y-%m-%dT%H:%M:%S", &gd); 2083276da39aSCy Schubert if (NULL == ep) 2084276da39aSCy Schubert return FALSE; /* could not parse the mandatory stuff! */ 20852b15cb3dSCy Schubert if (*ep == '.') { 2086276da39aSCy Schubert dw = 100000000u; 20879034852cSGleb Smirnoff while (isdigit(*(u_char*)++ep)) { 20889034852cSGleb Smirnoff ts.tv_nsec += (*(u_char*)ep - '0') * dw; 2089276da39aSCy Schubert dw /= 10u; 20902b15cb3dSCy Schubert } 20912b15cb3dSCy Schubert } 20922b15cb3dSCy Schubert if (ep[0] != 'Z' || ep[1] != '\0') 2093276da39aSCy Schubert return FALSE; /* trailing garbage */ 20942b15cb3dSCy Schubert 2095276da39aSCy Schubert /* Now convert the whole thing into a 'l_fp'. We do not use 2096276da39aSCy Schubert * 'mkgmtime()' since its not standard and going through the 2097276da39aSCy Schubert * calendar routines is not much effort, either. 2098276da39aSCy Schubert */ 20992b15cb3dSCy Schubert ts.tv_sec = (ntpcal_tm_to_rd(&gd) - DAY_NTP_STARTS) * SECSPERDAY 21002b15cb3dSCy Schubert + ntpcal_tm_to_daysec(&gd); 21012b15cb3dSCy Schubert *fp = tspec_intv_to_lfp(ts); 21022b15cb3dSCy Schubert 21032b15cb3dSCy Schubert return TRUE; 21042b15cb3dSCy Schubert } 21052b15cb3dSCy Schubert 21062b15cb3dSCy Schubert /* ------------------------------------------------------------------- 21072b15cb3dSCy Schubert * Save the last timecode string, making sure it's properly truncated 21082b15cb3dSCy Schubert * if necessary and NUL terminated in any case. 21092b15cb3dSCy Schubert */ 21102b15cb3dSCy Schubert static void 21112b15cb3dSCy Schubert save_ltc( 21122b15cb3dSCy Schubert clockprocT * const pp, 21132b15cb3dSCy Schubert const char * const tc) 21142b15cb3dSCy Schubert { 2115*f0574f5cSXin LI size_t len = 0; 21162b15cb3dSCy Schubert 2117*f0574f5cSXin LI if (tc) { 2118*f0574f5cSXin LI len = strlen(tc); 21192b15cb3dSCy Schubert if (len >= sizeof(pp->a_lastcode)) 21202b15cb3dSCy Schubert len = sizeof(pp->a_lastcode) - 1; 21212b15cb3dSCy Schubert memcpy(pp->a_lastcode, tc, len); 2122*f0574f5cSXin LI } 2123*f0574f5cSXin LI pp->lencode = (u_short)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) { 21929034852cSGleb Smirnoff u_char uch = (u_char)*sptr++; 21939034852cSGleb Smirnoff if (uch == '\\') { 2194276da39aSCy Schubert dptr = add_string(dptr, dtop, "\\\\"); 21959034852cSGleb Smirnoff } else if (isprint(uch)) { 21969034852cSGleb Smirnoff *dptr++ = (char)uch; 2197276da39aSCy Schubert } else { 2198276da39aSCy Schubert char fbuf[6]; 21999034852cSGleb 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