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