xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_gpsdjson.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: refclock_gpsdjson.c,v 1.14 2024/08/18 20:47:18 christos Exp $	*/
2b8ecfcfeSchristos 
3b8ecfcfeSchristos /*
4b8ecfcfeSchristos  * refclock_gpsdjson.c - clock driver as GPSD JSON client
5b8ecfcfeSchristos  *	Juergen Perlinger (perlinger@ntp.org)
6b8ecfcfeSchristos  *	Feb 11, 2014 for the NTP project.
7b8ecfcfeSchristos  *      The contents of 'html/copyright.html' apply.
8b8ecfcfeSchristos  *
9b8ecfcfeSchristos  *	Heavily inspired by refclock_nmea.c
10b8ecfcfeSchristos  *
115d681e99Schristos  * Special thanks to Gary Miller and Hal Murray for their comments and
125d681e99Schristos  * ideas.
135d681e99Schristos  *
14b8ecfcfeSchristos  * Note: This will currently NOT work with Windows due to some
15b8ecfcfeSchristos  * limitations:
16b8ecfcfeSchristos  *
17b8ecfcfeSchristos  *  - There is no GPSD for Windows. (There is an unofficial port to
18b8ecfcfeSchristos  *    cygwin, but Windows is not officially supported.)
19b8ecfcfeSchristos  *
205d681e99Schristos  *  - To work properly, this driver needs PPS and TPV/TOFF sentences
215d681e99Schristos  *    from GPSD. I don't see how the cygwin port should deal with the
225d681e99Schristos  *    PPS signal.
23b8ecfcfeSchristos  *
24b8ecfcfeSchristos  *  - The device name matching must be done in a different way for
25b8ecfcfeSchristos  *    Windows. (Can be done with COMxx matching, as done for NMEA.)
26b8ecfcfeSchristos  *
27b8ecfcfeSchristos  * Apart from those minor hickups, once GPSD has been fully ported to
285d681e99Schristos  * Windows, there's no reason why this should not work there ;-) If this
295d681e99Schristos  * is ever to happen at all is a different question.
305d681e99Schristos  *
315d681e99Schristos  * ---------------------------------------------------------------------
325d681e99Schristos  *
335d681e99Schristos  * This driver works slightly different from most others, as the PPS
345d681e99Schristos  * information (if available) is also coming from GPSD via the data
355d681e99Schristos  * connection. This makes using both the PPS data and the serial data
365d681e99Schristos  * easier, but OTOH it's not possible to use the ATOM driver to feed a
375d681e99Schristos  * raw PPS stream to the core of NTPD.
385d681e99Schristos  *
395d681e99Schristos  * To go around this, the driver can use a secondary clock unit
405d681e99Schristos  * (units>=128) that operate in tandem with the primary clock unit
415d681e99Schristos  * (unit%128). The primary clock unit does all the IO stuff and data
425d681e99Schristos  * decoding; if a a secondary unit is attached to a primary unit, this
435d681e99Schristos  * secondary unit is feed with the PPS samples only and can act as a PPS
445d681e99Schristos  * source to the clock selection.
455d681e99Schristos  *
465d681e99Schristos  * The drawback is that the primary unit must be present for the
475d681e99Schristos  * secondary unit to work.
485d681e99Schristos  *
495d681e99Schristos  * This design is a compromise to reduce the IO load for both NTPD and
505d681e99Schristos  * GPSD; it also ensures that data is transmitted and evaluated only
515d681e99Schristos  * once on the side of NTPD.
525d681e99Schristos  *
535d681e99Schristos  * ---------------------------------------------------------------------
545d681e99Schristos  *
555d681e99Schristos  * trouble shooting hints:
565d681e99Schristos  *
575d681e99Schristos  *   Enable and check the clock stats. Check if there are bad replies;
585d681e99Schristos  *   there should be none. If there are actually bad replies, then the
595d681e99Schristos  *   driver cannot parse all JSON records from GPSD, and some record
605d681e99Schristos  *   types are vital for the operation of the driver. This indicates a
615d681e99Schristos  *   problem on the protocol level.
625d681e99Schristos  *
635d681e99Schristos  *   When started on the command line with a debug level >= 2, the
645d681e99Schristos  *   driver dumps the raw received data and the parser input to
655d681e99Schristos  *   stdout. Since the debug level is global, NTPD starts to create a
665d681e99Schristos  *   *lot* of output. It makes sense to pipe it through '(f)grep
675d681e99Schristos  *   GPSD_JSON' before writing the result to disk.
685d681e99Schristos  *
695d681e99Schristos  *   A bit less intrusive is using netcat or telnet to connect to GPSD
705d681e99Schristos  *   and snoop what NTPD would get. If you try this, you have to send a
715d681e99Schristos  *   WATCH command to GPSD:
725d681e99Schristos  *
735d681e99Schristos  * ?WATCH={"device":"/dev/gps0","enable":true,"json":true,"pps":true};<CRLF>
745d681e99Schristos  *
755d681e99Schristos  *   should show you what GPSD has to say to NTPD. Replace "/dev/gps0"
765d681e99Schristos  *   with the device link used by GPSD, if necessary.
77b8ecfcfeSchristos  */
78b8ecfcfeSchristos 
795d681e99Schristos 
80b8ecfcfeSchristos #ifdef HAVE_CONFIG_H
81b8ecfcfeSchristos #include <config.h>
82b8ecfcfeSchristos #endif
83b8ecfcfeSchristos 
84b8ecfcfeSchristos #include "ntp_types.h"
85b8ecfcfeSchristos 
86b8ecfcfeSchristos #if defined(REFCLOCK) && defined(CLOCK_GPSDJSON) && !defined(SYS_WINNT)
87b8ecfcfeSchristos 
88b8ecfcfeSchristos /* =====================================================================
895d681e99Schristos  * Get the little JSMN library directly into our guts. Use the 'parent
905d681e99Schristos  * link' feature for maximum speed.
91b8ecfcfeSchristos  */
925d681e99Schristos #define JSMN_PARENT_LINKS
93b8ecfcfeSchristos #include "../libjsmn/jsmn.c"
94b8ecfcfeSchristos 
95b8ecfcfeSchristos /* =====================================================================
965d681e99Schristos  * JSON parsing stuff
975d681e99Schristos  */
985d681e99Schristos 
995d681e99Schristos #define JSMN_MAXTOK	350
1005d681e99Schristos #define INVALID_TOKEN (-1)
1015d681e99Schristos 
1025d681e99Schristos typedef struct json_ctx {
1035d681e99Schristos 	char        * buf;
1045d681e99Schristos 	int           ntok;
1055d681e99Schristos 	jsmntok_t     tok[JSMN_MAXTOK];
1065d681e99Schristos } json_ctx;
1075d681e99Schristos 
1085d681e99Schristos typedef int tok_ref;
1095d681e99Schristos 
1105d681e99Schristos /* Not all targets have 'long long', and not all of them have 'strtoll'.
1115d681e99Schristos  * Sigh. We roll our own integer number parser.
1125d681e99Schristos  */
1135d681e99Schristos #ifdef HAVE_LONG_LONG
1145d681e99Schristos typedef signed   long long int json_int;
1155d681e99Schristos typedef unsigned long long int json_uint;
1165d681e99Schristos #define JSON_INT_MAX LLONG_MAX
1175d681e99Schristos #define JSON_INT_MIN LLONG_MIN
1185d681e99Schristos #else
1195d681e99Schristos typedef signed   long int json_int;
1205d681e99Schristos typedef unsigned long int json_uint;
1215d681e99Schristos #define JSON_INT_MAX LONG_MAX
1225d681e99Schristos #define JSON_INT_MIN LONG_MIN
1235d681e99Schristos #endif
1245d681e99Schristos 
1255d681e99Schristos /* =====================================================================
126b8ecfcfeSchristos  * header stuff we need
127b8ecfcfeSchristos  */
128b8ecfcfeSchristos 
129b8ecfcfeSchristos #include <netdb.h>
130b8ecfcfeSchristos #include <unistd.h>
131b8ecfcfeSchristos #include <fcntl.h>
132b8ecfcfeSchristos #include <string.h>
133b8ecfcfeSchristos #include <ctype.h>
1345d681e99Schristos #include <math.h>
135b8ecfcfeSchristos 
136b8ecfcfeSchristos #include <sys/types.h>
137b8ecfcfeSchristos #include <sys/socket.h>
138b8ecfcfeSchristos #include <sys/stat.h>
139b8ecfcfeSchristos #include <netinet/tcp.h>
140b8ecfcfeSchristos 
141b8ecfcfeSchristos #if defined(HAVE_SYS_POLL_H)
142b8ecfcfeSchristos # include <sys/poll.h>
1437476e6e4Schristos #elif defined(HAVE_SYS_SELECT_H)
144b8ecfcfeSchristos # include <sys/select.h>
145b8ecfcfeSchristos #else
146b8ecfcfeSchristos # error need poll() or select()
147b8ecfcfeSchristos #endif
148b8ecfcfeSchristos 
149b8ecfcfeSchristos #include "ntpd.h"
150b8ecfcfeSchristos #include "ntp_io.h"
151b8ecfcfeSchristos #include "ntp_unixtime.h"
152b8ecfcfeSchristos #include "ntp_refclock.h"
153b8ecfcfeSchristos #include "ntp_stdlib.h"
154b8ecfcfeSchristos #include "ntp_calendar.h"
155*eabc0478Schristos #include "ntp_clockdev.h"
156b8ecfcfeSchristos #include "timespecops.h"
157b8ecfcfeSchristos 
1585d681e99Schristos /* get operation modes from mode word.
1595d681e99Schristos 
1605d681e99Schristos  * + SERIAL (default) evaluates only serial time information ('STI') as
1615d681e99Schristos  *   provided by TPV and TOFF records. TPV evaluation suffers from a
1625d681e99Schristos  *   bigger jitter than TOFF, sine it does not contain the receive time
1635d681e99Schristos  *   from GPSD and therefore the receive time of NTPD must be
1645d681e99Schristos  *   substituted for it. The network latency makes this a second rate
1655d681e99Schristos  *   guess.
1665d681e99Schristos  *
1675d681e99Schristos  *   If TOFF records are detected in the data stream, the timing
1685d681e99Schristos  *   information is gleaned from this record -- it contains the local
1695d681e99Schristos  *   receive time stamp from GPSD and therefore eliminates the
1705d681e99Schristos  *   transmission latency between GPSD and NTPD. The timing information
1715d681e99Schristos  *   from TPV is ignored once a TOFF is detected or expected.
1725d681e99Schristos  *
1735d681e99Schristos  *   TPV is still used to check the fix status, so the driver can stop
1745d681e99Schristos  *   feeding samples when GPSD says that the time information is
1755d681e99Schristos  *   effectively unreliable.
1765d681e99Schristos  *
1775d681e99Schristos  * + STRICT means only feed clock samples when a valid STI/PPS pair is
1785d681e99Schristos  *   available. Combines the reference time from STI with the pulse time
1795d681e99Schristos  *   from PPS. Masks the serial data jitter as long PPS is available,
1805d681e99Schristos  *   but can rapidly deteriorate once PPS drops out.
1815d681e99Schristos  *
1825d681e99Schristos  * + AUTO tries to use STI/PPS pairs if available for some time, and if
1835d681e99Schristos  *   this fails for too long switches back to STI only until the PPS
1845d681e99Schristos  *   signal becomes available again. See the HTML docs for this driver
1855d681e99Schristos  *   about the gotchas and why this is not the default.
1865d681e99Schristos  */
1875d681e99Schristos #define MODE_OP_MASK   0x03
1885d681e99Schristos #define MODE_OP_STI    0
1895d681e99Schristos #define MODE_OP_STRICT 1
1905d681e99Schristos #define MODE_OP_AUTO   2
1915d681e99Schristos #define MODE_OP_MAXVAL 2
1925d681e99Schristos #define MODE_OP_MODE(x)		((x) & MODE_OP_MASK)
1935d681e99Schristos 
194b8ecfcfeSchristos #define	PRECISION	(-9)	/* precision assumed (about 2 ms) */
195b8ecfcfeSchristos #define	PPS_PRECISION	(-20)	/* precision assumed (about 1 us) */
196b8ecfcfeSchristos #define	REFID		"GPSD"	/* reference id */
197b8ecfcfeSchristos #define	DESCRIPTION	"GPSD JSON client clock" /* who we are */
198b8ecfcfeSchristos 
199*eabc0478Schristos #define MAX_PDU_LEN	8192	/* multi-GNSS reports can be HUGE */
200b8ecfcfeSchristos #define TICKOVER_LOW	10
201b8ecfcfeSchristos #define TICKOVER_HIGH	120
202b8ecfcfeSchristos #define LOGTHROTTLE	3600
203b8ecfcfeSchristos 
2045d681e99Schristos /* Primary channel PPS avilability dance:
2055d681e99Schristos  * Every good PPS sample gets us a credit of PPS_INCCOUNT points, every
2065d681e99Schristos  * bad/missing PPS sample costs us a debit of PPS_DECCOUNT points. When
2075d681e99Schristos  * the account reaches the upper limit we change to a mode where only
2085d681e99Schristos  * PPS-augmented samples are fed to the core; when the account drops to
2095d681e99Schristos  * zero we switch to a mode where TPV-only timestamps are fed to the
2105d681e99Schristos  * core.
2115d681e99Schristos  * This reduces the chance of rapid alternation between raw and
2125d681e99Schristos  * PPS-augmented time stamps.
2135d681e99Schristos  */
2145d681e99Schristos #define PPS_MAXCOUNT	60	/* upper limit of account  */
2155d681e99Schristos #define PPS_INCCOUNT     3	/* credit for good samples */
2165d681e99Schristos #define PPS_DECCOUNT     1	/* debit for bad samples   */
2175d681e99Schristos 
2185d681e99Schristos /* The secondary (PPS) channel uses a different strategy to avoid old
2195d681e99Schristos  * PPS samples in the median filter.
2205d681e99Schristos  */
2215d681e99Schristos #define PPS2_MAXCOUNT 10
222b8ecfcfeSchristos 
223b8ecfcfeSchristos #ifndef BOOL
224b8ecfcfeSchristos # define BOOL int
225b8ecfcfeSchristos #endif
226b8ecfcfeSchristos #ifndef TRUE
227b8ecfcfeSchristos # define TRUE 1
228b8ecfcfeSchristos #endif
229b8ecfcfeSchristos #ifndef FALSE
230b8ecfcfeSchristos # define FALSE 0
231b8ecfcfeSchristos #endif
232b8ecfcfeSchristos 
2335d681e99Schristos #define PROTO_VERSION(hi,lo) \
2345d681e99Schristos 	    ((((uint32_t)(hi) << 16) & 0xFFFF0000u) | \
2355d681e99Schristos 	     ((uint32_t)(lo) & 0x0FFFFu))
2365d681e99Schristos 
237b8ecfcfeSchristos /* some local typedefs: The NTPD formatting style cries for short type
238b8ecfcfeSchristos  * names, and we provide them locally. Note:the suffix '_t' is reserved
239b8ecfcfeSchristos  * for the standard; I use a capital T instead.
240b8ecfcfeSchristos  */
241b8ecfcfeSchristos typedef struct peer         peerT;
242b8ecfcfeSchristos typedef struct refclockproc clockprocT;
243b8ecfcfeSchristos typedef struct addrinfo     addrinfoT;
244b8ecfcfeSchristos 
245b8ecfcfeSchristos /* =====================================================================
246b8ecfcfeSchristos  * We use the same device name scheme as does the NMEA driver; since
247b8ecfcfeSchristos  * GPSD supports the same links, we can select devices by a fixed name.
248b8ecfcfeSchristos  */
249b8ecfcfeSchristos static const char * s_dev_stem = "/dev/gps";
250b8ecfcfeSchristos 
251b8ecfcfeSchristos /* =====================================================================
252b8ecfcfeSchristos  * forward declarations for transfer vector and the vector itself
253b8ecfcfeSchristos  */
254b8ecfcfeSchristos 
255b8ecfcfeSchristos static	void	gpsd_init	(void);
256b8ecfcfeSchristos static	int	gpsd_start	(int, peerT *);
257b8ecfcfeSchristos static	void	gpsd_shutdown	(int, peerT *);
258b8ecfcfeSchristos static	void	gpsd_receive	(struct recvbuf *);
259b8ecfcfeSchristos static	void	gpsd_poll	(int, peerT *);
260b8ecfcfeSchristos static	void	gpsd_control	(int, const struct refclockstat *,
261b8ecfcfeSchristos 				 struct refclockstat *, peerT *);
262b8ecfcfeSchristos static	void	gpsd_timer	(int, peerT *);
263b8ecfcfeSchristos 
2645d681e99Schristos static  int     myasprintf(char**, char const*, ...) NTP_PRINTF(2, 3);
2655d681e99Schristos 
2665d681e99Schristos static void     enter_opmode(peerT *peer, int mode);
2675d681e99Schristos static void	leave_opmode(peerT *peer, int mode);
268b8ecfcfeSchristos 
269b8ecfcfeSchristos struct refclock refclock_gpsdjson = {
270b8ecfcfeSchristos 	gpsd_start,		/* start up driver */
271b8ecfcfeSchristos 	gpsd_shutdown,		/* shut down driver */
272b8ecfcfeSchristos 	gpsd_poll,		/* transmit poll message */
273b8ecfcfeSchristos 	gpsd_control,		/* fudge control */
274b8ecfcfeSchristos 	gpsd_init,		/* initialize driver */
275b8ecfcfeSchristos 	noentry,		/* buginfo */
276b8ecfcfeSchristos 	gpsd_timer		/* called once per second */
277b8ecfcfeSchristos };
278b8ecfcfeSchristos 
279b8ecfcfeSchristos /* =====================================================================
280b8ecfcfeSchristos  * our local clock unit and data
281b8ecfcfeSchristos  */
2825d681e99Schristos struct gpsd_unit;
2835d681e99Schristos typedef struct gpsd_unit gpsd_unitT;
284b8ecfcfeSchristos 
2855d681e99Schristos struct gpsd_unit {
2865d681e99Schristos 	/* links for sharing between master/slave units */
2875d681e99Schristos 	gpsd_unitT *next_unit;
2885d681e99Schristos 	size_t      refcount;
2895d681e99Schristos 
2905d681e99Schristos 	/* data for the secondary PPS channel */
2915d681e99Schristos 	peerT      *pps_peer;
2925d681e99Schristos 
2935d681e99Schristos 	/* unit and operation modes */
2945d681e99Schristos 	int      unit;
2955d681e99Schristos 	int      mode;
2965d681e99Schristos 	char    *logname;	/* cached name for log/print */
2975d681e99Schristos 	char    * device;	/* device name of unit */
2985d681e99Schristos 
2995d681e99Schristos 	/* current line protocol version */
3005d681e99Schristos 	uint32_t proto_version;
3015d681e99Schristos 
3025d681e99Schristos 	/* PPS time stamps primary + secondary channel */
303b8ecfcfeSchristos 	l_fp pps_local;	/* when we received the PPS message */
304b8ecfcfeSchristos 	l_fp pps_stamp;	/* related reference time */
305b8ecfcfeSchristos 	l_fp pps_recvt;	/* when GPSD detected the pulse */
3065d681e99Schristos 	l_fp pps_stamp2;/* related reference time (secondary) */
3075d681e99Schristos 	l_fp pps_recvt2;/* when GPSD detected the pulse (secondary)*/
3085d681e99Schristos 	int  ppscount;	/* PPS counter (primary unit) */
3095d681e99Schristos 	int  ppscount2;	/* PPS counter (secondary unit) */
310b8ecfcfeSchristos 
3115d681e99Schristos 	/* TPV or TOFF serial time information */
3125d681e99Schristos 	l_fp sti_local;	/* when we received the TPV/TOFF message */
3135d681e99Schristos 	l_fp sti_stamp;	/* effective GPS time stamp */
3145d681e99Schristos 	l_fp sti_recvt;	/* when GPSD got the fix */
3155d681e99Schristos 
3165d681e99Schristos 	/* precision estimates */
3175d681e99Schristos 	int16_t	    sti_prec;	/* serial precision based on EPT */
3185d681e99Schristos 	int16_t     pps_prec;	/* PPS precision from GPSD or above */
319b8ecfcfeSchristos 
320b8ecfcfeSchristos 	/* fudge values for correction, mirrored as 'l_fp' */
3215d681e99Schristos 	l_fp pps_fudge;		/* PPS fudge primary channel */
3225d681e99Schristos 	l_fp pps_fudge2;	/* PPS fudge secondary channel */
3235d681e99Schristos 	l_fp sti_fudge;		/* TPV/TOFF serial data fudge */
324b8ecfcfeSchristos 
325b8ecfcfeSchristos 	/* Flags to indicate available data */
3265d681e99Schristos 	int fl_nosync: 1;	/* GPSD signals bad quality */
3275d681e99Schristos 	int fl_sti   : 1;	/* valid TPV/TOFF seen (have time) */
328b8ecfcfeSchristos 	int fl_pps   : 1;	/* valid pulse seen */
3295d681e99Schristos 	int fl_pps2  : 1;	/* valid pulse seen for PPS channel */
3305d681e99Schristos 	int fl_rawsti: 1;	/* permit raw TPV/TOFF time stamps */
331b8ecfcfeSchristos 	int fl_vers  : 1;	/* have protocol version */
332b8ecfcfeSchristos 	int fl_watch : 1;	/* watch reply seen */
3335d681e99Schristos 	/* protocol flags */
3345d681e99Schristos 	int pf_nsec  : 1;	/* have nanosec PPS info */
3355d681e99Schristos 	int pf_toff  : 1;	/* have TOFF record for timing */
336b8ecfcfeSchristos 
337b8ecfcfeSchristos 	/* admin stuff for sockets and device selection */
338b8ecfcfeSchristos 	int         fdt;	/* current connecting socket */
339b8ecfcfeSchristos 	addrinfoT * addr;	/* next address to try */
340b8ecfcfeSchristos 	u_int       tickover;	/* timeout countdown */
341b8ecfcfeSchristos 	u_int       tickpres;	/* timeout preset */
342b8ecfcfeSchristos 
343b8ecfcfeSchristos 	/* tallies for the various events */
344b8ecfcfeSchristos 	u_int       tc_recv;	/* received known records */
3455d681e99Schristos 	u_int       tc_breply;	/* bad replies / parsing errors */
3465d681e99Schristos 	u_int       tc_nosync;	/* TPV / sample cycles w/o fix */
3475d681e99Schristos 	u_int       tc_sti_recv;/* received serial time info records */
3485d681e99Schristos 	u_int       tc_sti_used;/* used        --^-- */
3495d681e99Schristos 	u_int       tc_pps_recv;/* received PPS timing info records */
3505d681e99Schristos 	u_int       tc_pps_used;/* used        --^-- */
351b8ecfcfeSchristos 
352b8ecfcfeSchristos 	/* log bloat throttle */
353b8ecfcfeSchristos 	u_int       logthrottle;/* seconds to next log slot */
354b8ecfcfeSchristos 
3555d681e99Schristos 	/* The parse context for the current record */
3565d681e99Schristos 	json_ctx    json_parse;
3575d681e99Schristos 
358b8ecfcfeSchristos 	/* record assemby buffer and saved length */
359b8ecfcfeSchristos 	int  buflen;
360b8ecfcfeSchristos 	char buffer[MAX_PDU_LEN];
3615d681e99Schristos };
362b8ecfcfeSchristos 
363b8ecfcfeSchristos /* =====================================================================
364b8ecfcfeSchristos  * static local helpers forward decls
365b8ecfcfeSchristos  */
366b8ecfcfeSchristos static void gpsd_init_socket(peerT * const peer);
367b8ecfcfeSchristos static void gpsd_test_socket(peerT * const peer);
368b8ecfcfeSchristos static void gpsd_stop_socket(peerT * const peer);
369b8ecfcfeSchristos 
370b8ecfcfeSchristos static void gpsd_parse(peerT * const peer,
371b8ecfcfeSchristos 		       const l_fp  * const rtime);
372b8ecfcfeSchristos static BOOL convert_ascii_time(l_fp * fp, const char * gps_time);
373b8ecfcfeSchristos static void save_ltc(clockprocT * const pp, const char * const tc);
374b8ecfcfeSchristos static int  syslogok(clockprocT * const pp, gpsd_unitT * const up);
375*eabc0478Schristos static void log_data(peerT *peer, int level, const char *what,
3765d681e99Schristos 		     const char *buf, size_t len);
3775d681e99Schristos static int16_t clamped_precision(int rawprec);
378b8ecfcfeSchristos 
379b8ecfcfeSchristos /* =====================================================================
380b8ecfcfeSchristos  * local / static stuff
381b8ecfcfeSchristos  */
382b8ecfcfeSchristos 
3835d681e99Schristos static const char * const s_req_version =
3845d681e99Schristos     "?VERSION;\r\n";
3855d681e99Schristos 
3865d681e99Schristos /* We keep a static list of network addresses for 'localhost:gpsd' or a
3875d681e99Schristos  * fallback alias of it, and we try to connect to them in round-robin
3885d681e99Schristos  * fashion. The service lookup is done during the driver init
3895d681e99Schristos  * function to minmise the impact of 'getaddrinfo()'.
3905d681e99Schristos  *
3915d681e99Schristos  * Alas, the init function is called even if there are no clocks
3925d681e99Schristos  * configured for this driver. So it makes sense to defer the logging of
3935d681e99Schristos  * any errors or other notifications until the first clock unit is
3945d681e99Schristos  * started -- otherwise there might be syslog entries from a driver that
3955d681e99Schristos  * is not used at all.
396b8ecfcfeSchristos  */
397b8ecfcfeSchristos static addrinfoT  *s_gpsd_addr;
3985d681e99Schristos static gpsd_unitT *s_clock_units;
3995d681e99Schristos 
4005d681e99Schristos /* list of service/socket names we want to resolve against */
4015d681e99Schristos static const char * const s_svctab[][2] = {
4025d681e99Schristos 	{ "localhost", "gpsd" },
4035d681e99Schristos 	{ "localhost", "2947" },
4045d681e99Schristos 	{ "127.0.0.1", "2947" },
4055d681e99Schristos 	{ NULL, NULL }
4065d681e99Schristos };
4075d681e99Schristos 
4085d681e99Schristos /* list of address resolution errors and index of service entry that
4095d681e99Schristos  * finally worked.
4105d681e99Schristos  */
4115d681e99Schristos static int s_svcerr[sizeof(s_svctab)/sizeof(s_svctab[0])];
4125d681e99Schristos static int s_svcidx;
413b8ecfcfeSchristos 
414b8ecfcfeSchristos /* =====================================================================
415b8ecfcfeSchristos  * log throttling
416b8ecfcfeSchristos  */
417b8ecfcfeSchristos static int/*BOOL*/
418b8ecfcfeSchristos syslogok(
419b8ecfcfeSchristos 	clockprocT * const pp,
420b8ecfcfeSchristos 	gpsd_unitT * const up)
421b8ecfcfeSchristos {
422b8ecfcfeSchristos 	int res = (0 != (pp->sloppyclockflag & CLK_FLAG3))
423b8ecfcfeSchristos 	       || (0           == up->logthrottle )
424b8ecfcfeSchristos 	       || (LOGTHROTTLE == up->logthrottle );
425b8ecfcfeSchristos 	if (res)
426b8ecfcfeSchristos 		up->logthrottle = LOGTHROTTLE;
427b8ecfcfeSchristos 	return res;
428b8ecfcfeSchristos }
429b8ecfcfeSchristos 
430b8ecfcfeSchristos /* =====================================================================
431b8ecfcfeSchristos  * the clock functions
432b8ecfcfeSchristos  */
433b8ecfcfeSchristos 
434b8ecfcfeSchristos /* ---------------------------------------------------------------------
435b8ecfcfeSchristos  * Init: This currently just gets the socket address for the GPS daemon
436b8ecfcfeSchristos  */
437b8ecfcfeSchristos static void
438b8ecfcfeSchristos gpsd_init(void)
439b8ecfcfeSchristos {
440b8ecfcfeSchristos 	addrinfoT   hints;
4415d681e99Schristos 	int         rc, idx;
442b8ecfcfeSchristos 
4435d681e99Schristos 	memset(s_svcerr, 0, sizeof(s_svcerr));
444b8ecfcfeSchristos 	memset(&hints, 0, sizeof(hints));
445b8ecfcfeSchristos 	hints.ai_family   = AF_UNSPEC;
446b8ecfcfeSchristos 	hints.ai_protocol = IPPROTO_TCP;
447b8ecfcfeSchristos 	hints.ai_socktype = SOCK_STREAM;
448b8ecfcfeSchristos 
4495d681e99Schristos 	for (idx = 0; s_svctab[idx][0] && !s_gpsd_addr; idx++) {
4505d681e99Schristos 		rc = getaddrinfo(s_svctab[idx][0], s_svctab[idx][1],
4515d681e99Schristos 				 &hints, &s_gpsd_addr);
4525d681e99Schristos 		s_svcerr[idx] = rc;
4535d681e99Schristos 		if (0 == rc)
4545d681e99Schristos 			break;
455b8ecfcfeSchristos 		s_gpsd_addr = NULL;
456b8ecfcfeSchristos 	}
4575d681e99Schristos 	s_svcidx = idx;
4585d681e99Schristos }
4595d681e99Schristos 
4605d681e99Schristos /* ---------------------------------------------------------------------
4615d681e99Schristos  * Init Check: flush pending log messages and check if we can proceed
4625d681e99Schristos  */
4635d681e99Schristos static int/*BOOL*/
4645d681e99Schristos gpsd_init_check(void)
4655d681e99Schristos {
4665d681e99Schristos 	int idx;
4675d681e99Schristos 
4685d681e99Schristos 	/* Check if there is something to log */
4695d681e99Schristos 	if (s_svcidx == 0)
4705d681e99Schristos 		return (s_gpsd_addr != NULL);
4715d681e99Schristos 
4725d681e99Schristos 	/* spool out the resolver errors */
4735d681e99Schristos 	for (idx = 0; idx < s_svcidx; ++idx) {
4745d681e99Schristos 		msyslog(LOG_WARNING,
4755d681e99Schristos 			"GPSD_JSON: failed to resolve '%s:%s', rc=%d (%s)",
4765d681e99Schristos 			s_svctab[idx][0], s_svctab[idx][1],
4775d681e99Schristos 			s_svcerr[idx], gai_strerror(s_svcerr[idx]));
4785d681e99Schristos 	}
4795d681e99Schristos 
4805d681e99Schristos 	/* check if it was fatal, or if we can proceed */
4815d681e99Schristos 	if (s_gpsd_addr == NULL)
4825d681e99Schristos 		msyslog(LOG_ERR, "%s",
4835d681e99Schristos 			"GPSD_JSON: failed to get socket address, giving up.");
4845d681e99Schristos 	else if (idx != 0)
4855d681e99Schristos 		msyslog(LOG_WARNING,
4865d681e99Schristos 			"GPSD_JSON: using '%s:%s' instead of '%s:%s'",
4875d681e99Schristos 			s_svctab[idx][0], s_svctab[idx][1],
4885d681e99Schristos 			s_svctab[0][0], s_svctab[0][1]);
4895d681e99Schristos 
4905d681e99Schristos 	/* make sure this gets logged only once and tell if we can
4915d681e99Schristos 	 * proceed or not
4925d681e99Schristos 	 */
4935d681e99Schristos 	s_svcidx = 0;
4945d681e99Schristos 	return (s_gpsd_addr != NULL);
4955d681e99Schristos }
496b8ecfcfeSchristos 
497b8ecfcfeSchristos /* ---------------------------------------------------------------------
498b8ecfcfeSchristos  * Start: allocate a unit pointer and set up the runtime data
499b8ecfcfeSchristos  */
500b8ecfcfeSchristos static int
501b8ecfcfeSchristos gpsd_start(
502b8ecfcfeSchristos 	int     unit,
503b8ecfcfeSchristos 	peerT * peer)
504b8ecfcfeSchristos {
505b8ecfcfeSchristos 	clockprocT  * const pp = peer->procptr;
5065d681e99Schristos 	gpsd_unitT  * up;
5075d681e99Schristos 	gpsd_unitT ** uscan    = &s_clock_units;
508*eabc0478Schristos 	const char  *tmpName;
509b8ecfcfeSchristos 
510b8ecfcfeSchristos 	struct stat	sb;
511*eabc0478Schristos 	char *		devname = NULL;
512b8ecfcfeSchristos 
5135d681e99Schristos 	/* check if we can proceed at all or if init failed */
5145d681e99Schristos 	if ( ! gpsd_init_check())
5155d681e99Schristos 		return FALSE;
5165d681e99Schristos 
5175d681e99Schristos 	/* search for matching unit */
5185d681e99Schristos 	while ((up = *uscan) != NULL && up->unit != (unit & 0x7F))
5195d681e99Schristos 		uscan = &up->next_unit;
5205d681e99Schristos 	if (up == NULL) {
5215d681e99Schristos 		/* alloc unit, add to list and increment use count ASAP. */
5225d681e99Schristos 		up = emalloc_zero(sizeof(*up));
5235d681e99Schristos 		*uscan = up;
5245d681e99Schristos 		++up->refcount;
5255d681e99Schristos 
526b8ecfcfeSchristos 		/* initialize the unit structure */
5275d681e99Schristos 		up->logname  = estrdup(refnumtoa(&peer->srcadr));
5285d681e99Schristos 		up->unit     = unit & 0x7F;
529b8ecfcfeSchristos 		up->fdt      = -1;
530b8ecfcfeSchristos 		up->addr     = s_gpsd_addr;
531b8ecfcfeSchristos 		up->tickpres = TICKOVER_LOW;
532b8ecfcfeSchristos 
5335d681e99Schristos 		/* Create the device name and check for a Character
5345d681e99Schristos 		 * Device. It's assumed that GPSD was started with the
5355d681e99Schristos 		 * same link, so the names match. (If this is not
5365d681e99Schristos 		 * practicable, we will have to read the symlink, if
5375d681e99Schristos 		 * any, so we can get the true device file.)
5385d681e99Schristos 		 */
539*eabc0478Schristos 		tmpName = clockdev_lookup(&peer->srcadr, 0);
540*eabc0478Schristos 		if (NULL != tmpName) {
541*eabc0478Schristos 			up->device = estrdup(tmpName);
542*eabc0478Schristos 		} else if (-1 == myasprintf(&up->device, "%s%u", s_dev_stem, up->unit)) {
5435d681e99Schristos 			msyslog(LOG_ERR, "%s: clock device name too long",
5445d681e99Schristos 				up->logname);
5455d681e99Schristos 			goto dev_fail;
5465d681e99Schristos 		}
547*eabc0478Schristos 		devname = up->device;
548*eabc0478Schristos 		up->device = ntp_realpath(devname);
549*eabc0478Schristos 		if (NULL == up->device) {
550*eabc0478Schristos 			msyslog(LOG_ERR, "%s: '%s' has no absolute path",
551*eabc0478Schristos 				up->logname, devname);
552*eabc0478Schristos 			goto dev_fail;
553*eabc0478Schristos 		}
554*eabc0478Schristos 		free(devname);
555*eabc0478Schristos 		devname = NULL;
556*eabc0478Schristos 		if (-1 == lstat(up->device, &sb)) {
557*eabc0478Schristos 			msyslog(LOG_ERR, "%s: '%s' not accessible",
558*eabc0478Schristos 				up->logname, up->device);
559*eabc0478Schristos 			goto dev_fail;
560*eabc0478Schristos 		}
561*eabc0478Schristos 		if (!S_ISCHR(sb.st_mode)) {
5625d681e99Schristos 			msyslog(LOG_ERR, "%s: '%s' is not a character device",
5635d681e99Schristos 				up->logname, up->device);
5645d681e99Schristos 			goto dev_fail;
5655d681e99Schristos 		}
5665d681e99Schristos 	} else {
5675d681e99Schristos 		/* All set up, just increment use count. */
5685d681e99Schristos 		++up->refcount;
5695d681e99Schristos 	}
5705d681e99Schristos 
571b8ecfcfeSchristos 	/* setup refclock processing */
572b8ecfcfeSchristos 	pp->unitptr = (caddr_t)up;
573b8ecfcfeSchristos 	pp->io.fd         = -1;
574b8ecfcfeSchristos 	pp->io.clock_recv = gpsd_receive;
575b8ecfcfeSchristos 	pp->io.srcclock   = peer;
576b8ecfcfeSchristos 	pp->io.datalen    = 0;
577b8ecfcfeSchristos 	pp->a_lastcode[0] = '\0';
578b8ecfcfeSchristos 	pp->lencode       = 0;
579b8ecfcfeSchristos 	pp->clockdesc     = DESCRIPTION;
580b8ecfcfeSchristos 	memcpy(&pp->refid, REFID, 4);
581b8ecfcfeSchristos 
582b8ecfcfeSchristos 	/* Initialize miscellaneous variables */
5835d681e99Schristos 	if (unit >= 128)
5845d681e99Schristos 		peer->precision = PPS_PRECISION;
5855d681e99Schristos 	else
586b8ecfcfeSchristos 		peer->precision = PRECISION;
587b8ecfcfeSchristos 
5885d681e99Schristos 	/* If the daemon name lookup failed, just give up now. */
5895d681e99Schristos 	if (NULL == up->addr) {
5905d681e99Schristos 		msyslog(LOG_ERR, "%s: no GPSD socket address, giving up",
5915d681e99Schristos 			up->logname);
592b8ecfcfeSchristos 		goto dev_fail;
593b8ecfcfeSchristos 	}
5945d681e99Schristos 
595b8ecfcfeSchristos 	LOGIF(CLOCKINFO,
596b8ecfcfeSchristos 	      (LOG_NOTICE, "%s: startup, device is '%s'",
597b8ecfcfeSchristos 	       refnumtoa(&peer->srcadr), up->device));
5985d681e99Schristos 	up->mode = MODE_OP_MODE(peer->ttl);
5995d681e99Schristos 	if (up->mode > MODE_OP_MAXVAL)
6005d681e99Schristos 		up->mode = 0;
6015d681e99Schristos 	if (unit >= 128)
6025d681e99Schristos 		up->pps_peer = peer;
6035d681e99Schristos 	else
6045d681e99Schristos 		enter_opmode(peer, up->mode);
605b8ecfcfeSchristos 	return TRUE;
606b8ecfcfeSchristos 
607b8ecfcfeSchristos dev_fail:
608b8ecfcfeSchristos 	/* On failure, remove all UNIT ressources and declare defeat. */
609*eabc0478Schristos 	free(devname);
610b8ecfcfeSchristos 	INSIST (up);
6115d681e99Schristos 	if (!--up->refcount) {
6125d681e99Schristos 		*uscan = up->next_unit;
613b8ecfcfeSchristos 		free(up->device);
614b8ecfcfeSchristos 		free(up);
6155d681e99Schristos 	}
616b8ecfcfeSchristos 
617b8ecfcfeSchristos 	pp->unitptr = (caddr_t)NULL;
618b8ecfcfeSchristos 	return FALSE;
619b8ecfcfeSchristos }
620b8ecfcfeSchristos 
621b8ecfcfeSchristos /* ------------------------------------------------------------------ */
622b8ecfcfeSchristos 
623b8ecfcfeSchristos static void
624b8ecfcfeSchristos gpsd_shutdown(
625b8ecfcfeSchristos 	int     unit,
626b8ecfcfeSchristos 	peerT * peer)
627b8ecfcfeSchristos {
628b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
629b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
6305d681e99Schristos 	gpsd_unitT ** uscan   = &s_clock_units;
631b8ecfcfeSchristos 
632b8ecfcfeSchristos 	UNUSED_ARG(unit);
633b8ecfcfeSchristos 
6345d681e99Schristos 	/* The unit pointer might have been removed already. */
6355d681e99Schristos 	if (up == NULL)
6365d681e99Schristos 		return;
6375d681e99Schristos 
6385d681e99Schristos 	/* now check if we must close IO resources */
6395d681e99Schristos 	if (peer != up->pps_peer) {
6405d681e99Schristos 		if (-1 != pp->io.fd) {
6415d681e99Schristos 			DPRINTF(1, ("%s: closing clock, fd=%d\n",
6425d681e99Schristos 				    up->logname, pp->io.fd));
6435d681e99Schristos 			io_closeclock(&pp->io);
6445d681e99Schristos 			pp->io.fd = -1;
6455d681e99Schristos 		}
6465d681e99Schristos 		if (up->fdt != -1)
6475d681e99Schristos 			close(up->fdt);
6485d681e99Schristos 	}
6495d681e99Schristos 	/* decrement use count and eventually remove this unit. */
6505d681e99Schristos 	if (!--up->refcount) {
6515d681e99Schristos 		/* unlink this unit */
6525d681e99Schristos 		while (*uscan != NULL)
6535d681e99Schristos 			if (*uscan == up)
6545d681e99Schristos 				*uscan = up->next_unit;
6555d681e99Schristos 			else
6565d681e99Schristos 				uscan = &(*uscan)->next_unit;
6575d681e99Schristos 		free(up->logname);
658b8ecfcfeSchristos 		free(up->device);
659b8ecfcfeSchristos 		free(up);
660b8ecfcfeSchristos 	}
661b8ecfcfeSchristos 	pp->unitptr = (caddr_t)NULL;
662b8ecfcfeSchristos 	LOGIF(CLOCKINFO,
663b8ecfcfeSchristos 	      (LOG_NOTICE, "%s: shutdown", refnumtoa(&peer->srcadr)));
664b8ecfcfeSchristos }
665b8ecfcfeSchristos 
666b8ecfcfeSchristos /* ------------------------------------------------------------------ */
667b8ecfcfeSchristos 
668b8ecfcfeSchristos static void
669b8ecfcfeSchristos gpsd_receive(
670b8ecfcfeSchristos 	struct recvbuf * rbufp)
671b8ecfcfeSchristos {
672b8ecfcfeSchristos 	/* declare & init control structure ptrs */
673b8ecfcfeSchristos 	peerT	   * const peer = rbufp->recv_peer;
674b8ecfcfeSchristos 	clockprocT * const pp   = peer->procptr;
675b8ecfcfeSchristos 	gpsd_unitT * const up   = (gpsd_unitT *)pp->unitptr;
676b8ecfcfeSchristos 
677b8ecfcfeSchristos 	const char *psrc, *esrc;
678b8ecfcfeSchristos 	char       *pdst, *edst, ch;
679b8ecfcfeSchristos 
6805d681e99Schristos 	/* log the data stream, if this is enabled */
681*eabc0478Schristos 	log_data(peer, 3, "recv", (const char*)rbufp->recv_buffer,
6825d681e99Schristos 		 (size_t)rbufp->recv_length);
6835d681e99Schristos 
6845d681e99Schristos 
685b8ecfcfeSchristos 	/* Since we're getting a raw stream data, we must assemble lines
686b8ecfcfeSchristos 	 * in our receive buffer. We can't use neither 'refclock_gtraw'
687b8ecfcfeSchristos 	 * not 'refclock_gtlin' here...  We process chars until we reach
688b8ecfcfeSchristos 	 * an EoL (that is, line feed) but we truncate the message if it
689b8ecfcfeSchristos 	 * does not fit the buffer.  GPSD might truncate messages, too,
690b8ecfcfeSchristos 	 * so dealing with truncated buffers is necessary anyway.
691b8ecfcfeSchristos 	 */
692b8ecfcfeSchristos 	psrc = (const char*)rbufp->recv_buffer;
693b8ecfcfeSchristos 	esrc = psrc + rbufp->recv_length;
694b8ecfcfeSchristos 
695b8ecfcfeSchristos 	pdst = up->buffer + up->buflen;
696*eabc0478Schristos 	edst = up->buffer + sizeof(up->buffer) - 1; /* for trailing NUL */
697b8ecfcfeSchristos 
698b8ecfcfeSchristos 	while (psrc != esrc) {
699b8ecfcfeSchristos 		ch = *psrc++;
700b8ecfcfeSchristos 		if (ch == '\n') {
701b8ecfcfeSchristos 			/* trim trailing whitespace & terminate buffer */
702b8ecfcfeSchristos 			while (pdst != up->buffer && pdst[-1] <= ' ')
703b8ecfcfeSchristos 				--pdst;
704b8ecfcfeSchristos 			*pdst = '\0';
705b8ecfcfeSchristos 			/* process data and reset buffer */
7065d681e99Schristos 			up->buflen = pdst - up->buffer;
707b8ecfcfeSchristos 			gpsd_parse(peer, &rbufp->recv_time);
708b8ecfcfeSchristos 			pdst = up->buffer;
709b8ecfcfeSchristos 		} else if (pdst != edst) {
710b8ecfcfeSchristos 			/* add next char, ignoring leading whitespace */
711b8ecfcfeSchristos 			if (ch > ' ' || pdst != up->buffer)
712b8ecfcfeSchristos 				*pdst++ = ch;
713b8ecfcfeSchristos 		}
714b8ecfcfeSchristos 	}
715b8ecfcfeSchristos 	up->buflen   = pdst - up->buffer;
716b8ecfcfeSchristos 	up->tickover = TICKOVER_LOW;
717b8ecfcfeSchristos }
718b8ecfcfeSchristos 
719b8ecfcfeSchristos /* ------------------------------------------------------------------ */
720b8ecfcfeSchristos 
721b8ecfcfeSchristos static void
7225d681e99Schristos poll_primary(
7235d681e99Schristos 	peerT      * const peer ,
7245d681e99Schristos 	clockprocT * const pp   ,
7255d681e99Schristos 	gpsd_unitT * const up   )
7265d681e99Schristos {
7275d681e99Schristos 	if (pp->coderecv != pp->codeproc) {
7285d681e99Schristos 		/* all is well */
7295d681e99Schristos 		pp->lastref = pp->lastrec;
7305d681e99Schristos 		refclock_report(peer, CEVNT_NOMINAL);
7315d681e99Schristos 		refclock_receive(peer);
7325d681e99Schristos 	} else {
7335d681e99Schristos 		/* Not working properly, admit to it. If we have no
7345d681e99Schristos 		 * connection to GPSD, declare the clock as faulty. If
7355d681e99Schristos 		 * there were bad replies, this is handled as the major
7365d681e99Schristos 		 * cause, and everything else is just a timeout.
7375d681e99Schristos 		 */
7385d681e99Schristos 		peer->precision = PRECISION;
7395d681e99Schristos 		if (-1 == pp->io.fd)
7405d681e99Schristos 			refclock_report(peer, CEVNT_FAULT);
7415d681e99Schristos 		else if (0 != up->tc_breply)
7425d681e99Schristos 			refclock_report(peer, CEVNT_BADREPLY);
7435d681e99Schristos 		else
7445d681e99Schristos 			refclock_report(peer, CEVNT_TIMEOUT);
7455d681e99Schristos 	}
7465d681e99Schristos 
7475d681e99Schristos 	if (pp->sloppyclockflag & CLK_FLAG4)
7485d681e99Schristos 		mprintf_clock_stats(
7495d681e99Schristos 			&peer->srcadr,"%u %u %u %u %u %u %u",
7505d681e99Schristos 			up->tc_recv,
7515d681e99Schristos 			up->tc_breply, up->tc_nosync,
7525d681e99Schristos 			up->tc_sti_recv, up->tc_sti_used,
7535d681e99Schristos 			up->tc_pps_recv, up->tc_pps_used);
7545d681e99Schristos 
7555d681e99Schristos 	/* clear tallies for next round */
7565d681e99Schristos 	up->tc_breply   = 0;
7575d681e99Schristos 	up->tc_recv     = 0;
7585d681e99Schristos 	up->tc_nosync   = 0;
7595d681e99Schristos 	up->tc_sti_recv = 0;
7605d681e99Schristos 	up->tc_sti_used = 0;
7615d681e99Schristos 	up->tc_pps_recv = 0;
7625d681e99Schristos 	up->tc_pps_used = 0;
7635d681e99Schristos }
7645d681e99Schristos 
7655d681e99Schristos static void
7665d681e99Schristos poll_secondary(
7675d681e99Schristos 	peerT      * const peer ,
7685d681e99Schristos 	clockprocT * const pp   ,
7695d681e99Schristos 	gpsd_unitT * const up   )
7705d681e99Schristos {
7715d681e99Schristos 	if (pp->coderecv != pp->codeproc) {
7725d681e99Schristos 		/* all is well */
7735d681e99Schristos 		pp->lastref = pp->lastrec;
7745d681e99Schristos 		refclock_report(peer, CEVNT_NOMINAL);
7755d681e99Schristos 		refclock_receive(peer);
7765d681e99Schristos 	} else {
7775d681e99Schristos 		peer->precision = PPS_PRECISION;
7785d681e99Schristos 		peer->flags &= ~FLAG_PPS;
7795d681e99Schristos 		refclock_report(peer, CEVNT_TIMEOUT);
7805d681e99Schristos 	}
7815d681e99Schristos }
7825d681e99Schristos 
7835d681e99Schristos static void
784b8ecfcfeSchristos gpsd_poll(
785b8ecfcfeSchristos 	int     unit,
786b8ecfcfeSchristos 	peerT * peer)
787b8ecfcfeSchristos {
788b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
789b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
790b8ecfcfeSchristos 
791b8ecfcfeSchristos 	++pp->polls;
7925d681e99Schristos 	if (peer == up->pps_peer)
7935d681e99Schristos 		poll_secondary(peer, pp, up);
7945d681e99Schristos 	else
7955d681e99Schristos 		poll_primary(peer, pp, up);
796b8ecfcfeSchristos }
797b8ecfcfeSchristos 
798b8ecfcfeSchristos /* ------------------------------------------------------------------ */
799b8ecfcfeSchristos 
800b8ecfcfeSchristos static void
801b8ecfcfeSchristos gpsd_control(
802b8ecfcfeSchristos 	int                         unit,
803b8ecfcfeSchristos 	const struct refclockstat * in_st,
804b8ecfcfeSchristos 	struct refclockstat       * out_st,
805b8ecfcfeSchristos 	peerT                     * peer  )
806b8ecfcfeSchristos {
807b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
808b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
809b8ecfcfeSchristos 
8105d681e99Schristos 	if (peer == up->pps_peer) {
8115d681e99Schristos 		DTOLFP(pp->fudgetime1, &up->pps_fudge2);
8125d681e99Schristos 		if ( ! (pp->sloppyclockflag & CLK_FLAG1))
8135d681e99Schristos 			peer->flags &= ~FLAG_PPS;
8145d681e99Schristos 	} else {
815b8ecfcfeSchristos 		/* save preprocessed fudge times */
816b8ecfcfeSchristos 		DTOLFP(pp->fudgetime1, &up->pps_fudge);
8175d681e99Schristos 		DTOLFP(pp->fudgetime2, &up->sti_fudge);
8185d681e99Schristos 
8195d681e99Schristos 		if (MODE_OP_MODE(up->mode ^ peer->ttl)) {
8205d681e99Schristos 			leave_opmode(peer, up->mode);
8215d681e99Schristos 			up->mode = MODE_OP_MODE(peer->ttl);
8225d681e99Schristos 			enter_opmode(peer, up->mode);
8235d681e99Schristos 		}
8245d681e99Schristos 	}
825b8ecfcfeSchristos  }
826b8ecfcfeSchristos 
827b8ecfcfeSchristos /* ------------------------------------------------------------------ */
828b8ecfcfeSchristos 
829b8ecfcfeSchristos static void
8305d681e99Schristos timer_primary(
8315d681e99Schristos 	peerT      * const peer ,
8325d681e99Schristos 	clockprocT * const pp   ,
8335d681e99Schristos 	gpsd_unitT * const up   )
834b8ecfcfeSchristos {
835b8ecfcfeSchristos 	int rc;
836b8ecfcfeSchristos 
837b8ecfcfeSchristos 	/* This is used for timeout handling. Nothing that needs
838b8ecfcfeSchristos 	 * sub-second precison happens here, so receive/connect/retry
839b8ecfcfeSchristos 	 * timeouts are simply handled by a count down, and then we
840b8ecfcfeSchristos 	 * decide what to do by the socket values.
841b8ecfcfeSchristos 	 *
842b8ecfcfeSchristos 	 * Note that the timer stays at zero here, unless some of the
843b8ecfcfeSchristos 	 * functions set it to another value.
844b8ecfcfeSchristos 	 */
845b8ecfcfeSchristos 	if (up->logthrottle)
846b8ecfcfeSchristos 		--up->logthrottle;
847b8ecfcfeSchristos 	if (up->tickover)
848b8ecfcfeSchristos 		--up->tickover;
849b8ecfcfeSchristos 	switch (up->tickover) {
850b8ecfcfeSchristos 	case 4:
8515d681e99Schristos 		/* If we are connected to GPSD, try to get a live signal
8525d681e99Schristos 		 * by querying the version. Otherwise just check the
8535d681e99Schristos 		 * socket to become ready.
854b8ecfcfeSchristos 		 */
855b8ecfcfeSchristos 		if (-1 != pp->io.fd) {
8565d681e99Schristos 			size_t rlen = strlen(s_req_version);
8575d681e99Schristos 			DPRINTF(2, ("%s: timer livecheck: '%s'\n",
8585d681e99Schristos 				    up->logname, s_req_version));
859*eabc0478Schristos 			log_data(peer, 2, "send", s_req_version, rlen);
8605d681e99Schristos 			rc = write(pp->io.fd, s_req_version, rlen);
861b8ecfcfeSchristos 			(void)rc;
862b8ecfcfeSchristos 		} else if (-1 != up->fdt) {
863b8ecfcfeSchristos 			gpsd_test_socket(peer);
864b8ecfcfeSchristos 		}
865b8ecfcfeSchristos 		break;
866b8ecfcfeSchristos 
867b8ecfcfeSchristos 	case 0:
868b8ecfcfeSchristos 		if (-1 != pp->io.fd)
869b8ecfcfeSchristos 			gpsd_stop_socket(peer);
870b8ecfcfeSchristos 		else if (-1 != up->fdt)
871b8ecfcfeSchristos 			gpsd_test_socket(peer);
872b8ecfcfeSchristos 		else if (NULL != s_gpsd_addr)
873b8ecfcfeSchristos 			gpsd_init_socket(peer);
874b8ecfcfeSchristos 		break;
875b8ecfcfeSchristos 
876b8ecfcfeSchristos 	default:
877b8ecfcfeSchristos 		if (-1 == pp->io.fd && -1 != up->fdt)
878b8ecfcfeSchristos 			gpsd_test_socket(peer);
879b8ecfcfeSchristos 	}
8805d681e99Schristos }
881b8ecfcfeSchristos 
8825d681e99Schristos static void
8835d681e99Schristos timer_secondary(
8845d681e99Schristos 	peerT      * const peer ,
8855d681e99Schristos 	clockprocT * const pp   ,
8865d681e99Schristos 	gpsd_unitT * const up   )
8875d681e99Schristos {
8885d681e99Schristos 	/* Reduce the count by one. Flush sample buffer and clear PPS
8895d681e99Schristos 	 * flag when this happens.
8905d681e99Schristos 	 */
8915d681e99Schristos 	up->ppscount2 = max(0, (up->ppscount2 - 1));
8925d681e99Schristos 	if (0 == up->ppscount2) {
8935d681e99Schristos 		if (pp->coderecv != pp->codeproc) {
8945d681e99Schristos 			refclock_report(peer, CEVNT_TIMEOUT);
8955d681e99Schristos 			pp->coderecv = pp->codeproc;
8965d681e99Schristos 		}
897b8ecfcfeSchristos 		peer->flags &= ~FLAG_PPS;
898b8ecfcfeSchristos 	}
8995d681e99Schristos }
9005d681e99Schristos 
9015d681e99Schristos static void
9025d681e99Schristos gpsd_timer(
9035d681e99Schristos 	int     unit,
9045d681e99Schristos 	peerT * peer)
9055d681e99Schristos {
9065d681e99Schristos 	clockprocT * const pp = peer->procptr;
9075d681e99Schristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
9085d681e99Schristos 
9095d681e99Schristos 	if (peer == up->pps_peer)
9105d681e99Schristos 		timer_secondary(peer, pp, up);
9115d681e99Schristos 	else
9125d681e99Schristos 		timer_primary(peer, pp, up);
9135d681e99Schristos }
9145d681e99Schristos 
9155d681e99Schristos /* =====================================================================
9165d681e99Schristos  * handle opmode switches
9175d681e99Schristos  */
9185d681e99Schristos 
9195d681e99Schristos static void
9205d681e99Schristos enter_opmode(
9215d681e99Schristos 	peerT *peer,
9225d681e99Schristos 	int    mode)
9235d681e99Schristos {
9245d681e99Schristos 	clockprocT * const pp = peer->procptr;
9255d681e99Schristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
9265d681e99Schristos 
9275d681e99Schristos 	DPRINTF(1, ("%s: enter operation mode %d\n",
9285d681e99Schristos 		    up->logname, MODE_OP_MODE(mode)));
9295d681e99Schristos 
9305d681e99Schristos 	if (MODE_OP_MODE(mode) == MODE_OP_AUTO) {
9315d681e99Schristos 		up->fl_rawsti = 0;
9325d681e99Schristos 		up->ppscount  = PPS_MAXCOUNT / 2;
9335d681e99Schristos 	}
9345d681e99Schristos 	up->fl_pps = 0;
9355d681e99Schristos 	up->fl_sti = 0;
9365d681e99Schristos }
9375d681e99Schristos 
9385d681e99Schristos /* ------------------------------------------------------------------ */
9395d681e99Schristos 
9405d681e99Schristos static void
9415d681e99Schristos leave_opmode(
9425d681e99Schristos 	peerT *peer,
9435d681e99Schristos 	int    mode)
9445d681e99Schristos {
9455d681e99Schristos 	clockprocT * const pp = peer->procptr;
9465d681e99Schristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
9475d681e99Schristos 
9485d681e99Schristos 	DPRINTF(1, ("%s: leaving operation mode %d\n",
9495d681e99Schristos 		    up->logname, MODE_OP_MODE(mode)));
9505d681e99Schristos 
9515d681e99Schristos 	if (MODE_OP_MODE(mode) == MODE_OP_AUTO) {
9525d681e99Schristos 		up->fl_rawsti = 0;
9535d681e99Schristos 		up->ppscount  = 0;
9545d681e99Schristos 	}
9555d681e99Schristos 	up->fl_pps = 0;
9565d681e99Schristos 	up->fl_sti = 0;
9575d681e99Schristos }
9585d681e99Schristos 
9595d681e99Schristos /* =====================================================================
9605d681e99Schristos  * operation mode specific evaluation
9615d681e99Schristos  */
9625d681e99Schristos 
9635d681e99Schristos static void
9645d681e99Schristos add_clock_sample(
9655d681e99Schristos 	peerT      * const peer ,
9665d681e99Schristos 	clockprocT * const pp   ,
9675d681e99Schristos 	l_fp               stamp,
9685d681e99Schristos 	l_fp               recvt)
9695d681e99Schristos {
9705d681e99Schristos 	pp->lastref = stamp;
9715d681e99Schristos 	if (pp->coderecv == pp->codeproc)
9725d681e99Schristos 		refclock_report(peer, CEVNT_NOMINAL);
973cdfa2a7eSchristos 	refclock_process_offset(pp, stamp, recvt, 0.0);
9745d681e99Schristos }
9755d681e99Schristos 
9765d681e99Schristos /* ------------------------------------------------------------------ */
9775d681e99Schristos 
9785d681e99Schristos static void
9795d681e99Schristos eval_strict(
9805d681e99Schristos 	peerT      * const peer ,
9815d681e99Schristos 	clockprocT * const pp   ,
9825d681e99Schristos 	gpsd_unitT * const up   )
9835d681e99Schristos {
9845d681e99Schristos 	if (up->fl_sti && up->fl_pps) {
9855d681e99Schristos 		/* use TPV reference time + PPS receive time */
9865d681e99Schristos 		add_clock_sample(peer, pp, up->sti_stamp, up->pps_recvt);
9875d681e99Schristos 		peer->precision = up->pps_prec;
9885d681e99Schristos 		/* both packets consumed now... */
9895d681e99Schristos 		up->fl_pps = 0;
9905d681e99Schristos 		up->fl_sti = 0;
9915d681e99Schristos 		++up->tc_sti_used;
9925d681e99Schristos 	}
9935d681e99Schristos }
9945d681e99Schristos 
9955d681e99Schristos /* ------------------------------------------------------------------ */
9965d681e99Schristos /* PPS processing for the secondary channel. GPSD provides us with full
9975d681e99Schristos  * timing information, so there's no danger of PLL-locking to the wrong
9985d681e99Schristos  * second. The belts and suspenders needed for the raw ATOM clock are
9995d681e99Schristos  * unnecessary here.
10005d681e99Schristos  */
10015d681e99Schristos static void
10025d681e99Schristos eval_pps_secondary(
10035d681e99Schristos 	peerT      * const peer ,
10045d681e99Schristos 	clockprocT * const pp   ,
10055d681e99Schristos 	gpsd_unitT * const up   )
10065d681e99Schristos {
10075d681e99Schristos 	if (up->fl_pps2) {
10085d681e99Schristos 		/* feed data */
10095d681e99Schristos 		add_clock_sample(peer, pp, up->pps_stamp2, up->pps_recvt2);
10105d681e99Schristos 		peer->precision = up->pps_prec;
10115d681e99Schristos 		/* PPS peer flag logic */
10125d681e99Schristos 		up->ppscount2 = min(PPS2_MAXCOUNT, (up->ppscount2 + 2));
10135d681e99Schristos 		if ((PPS2_MAXCOUNT == up->ppscount2) &&
10145d681e99Schristos 		    (pp->sloppyclockflag & CLK_FLAG1) )
10155d681e99Schristos 			peer->flags |= FLAG_PPS;
10165d681e99Schristos 		/* mark time stamp as burned... */
10175d681e99Schristos 		up->fl_pps2 = 0;
10185d681e99Schristos 		++up->tc_pps_used;
10195d681e99Schristos 	}
10205d681e99Schristos }
10215d681e99Schristos 
10225d681e99Schristos /* ------------------------------------------------------------------ */
10235d681e99Schristos 
10245d681e99Schristos static void
10255d681e99Schristos eval_serial(
10265d681e99Schristos 	peerT      * const peer ,
10275d681e99Schristos 	clockprocT * const pp   ,
10285d681e99Schristos 	gpsd_unitT * const up   )
10295d681e99Schristos {
10305d681e99Schristos 	if (up->fl_sti) {
10315d681e99Schristos 		add_clock_sample(peer, pp, up->sti_stamp, up->sti_recvt);
10325d681e99Schristos 		peer->precision = up->sti_prec;
10335d681e99Schristos 		/* mark time stamp as burned... */
10345d681e99Schristos 		up->fl_sti = 0;
10355d681e99Schristos 		++up->tc_sti_used;
10365d681e99Schristos 	}
10375d681e99Schristos }
10385d681e99Schristos 
10395d681e99Schristos /* ------------------------------------------------------------------ */
10405d681e99Schristos static void
10415d681e99Schristos eval_auto(
10425d681e99Schristos 	peerT      * const peer ,
10435d681e99Schristos 	clockprocT * const pp   ,
10445d681e99Schristos 	gpsd_unitT * const up   )
10455d681e99Schristos {
10465d681e99Schristos 	/* If there's no TPV available, stop working here... */
10475d681e99Schristos 	if (!up->fl_sti)
10485d681e99Schristos 		return;
10495d681e99Schristos 
10505d681e99Schristos 	/* check how to handle STI+PPS: Can PPS be used to augment STI
10515d681e99Schristos 	 * (or vice versae), do we drop the sample because there is a
10525d681e99Schristos 	 * temporary missing PPS signal, or do we feed on STI time
10535d681e99Schristos 	 * stamps alone?
10545d681e99Schristos 	 *
10555d681e99Schristos 	 * Do a counter/threshold dance to decide how to proceed.
10565d681e99Schristos 	 */
10575d681e99Schristos 	if (up->fl_pps) {
10585d681e99Schristos 		up->ppscount = min(PPS_MAXCOUNT,
10595d681e99Schristos 				   (up->ppscount + PPS_INCCOUNT));
10605d681e99Schristos 		if ((PPS_MAXCOUNT == up->ppscount) && up->fl_rawsti) {
10615d681e99Schristos 			up->fl_rawsti = 0;
10625d681e99Schristos 			msyslog(LOG_INFO,
10635d681e99Schristos 				"%s: expect valid PPS from now",
10645d681e99Schristos 				up->logname);
10655d681e99Schristos 		}
10665d681e99Schristos 	} else {
10675d681e99Schristos 		up->ppscount = max(0, (up->ppscount - PPS_DECCOUNT));
10685d681e99Schristos 		if ((0 == up->ppscount) && !up->fl_rawsti) {
10695d681e99Schristos 			up->fl_rawsti = -1;
10705d681e99Schristos 			msyslog(LOG_WARNING,
10715d681e99Schristos 				"%s: use TPV alone from now",
10725d681e99Schristos 				up->logname);
10735d681e99Schristos 		}
10745d681e99Schristos 	}
10755d681e99Schristos 
10765d681e99Schristos 	/* now eventually feed the sample */
10775d681e99Schristos 	if (up->fl_rawsti)
10785d681e99Schristos 		eval_serial(peer, pp, up);
10795d681e99Schristos 	else
10805d681e99Schristos 		eval_strict(peer, pp, up);
10815d681e99Schristos }
1082b8ecfcfeSchristos 
1083b8ecfcfeSchristos /* =====================================================================
1084b8ecfcfeSchristos  * JSON parsing stuff
1085b8ecfcfeSchristos  */
1086b8ecfcfeSchristos 
10875d681e99Schristos /* ------------------------------------------------------------------ */
10885d681e99Schristos /* Parse a decimal integer with a possible sign. Works like 'strtoll()'
10895d681e99Schristos  * or 'strtol()', but with a fixed base of 10 and without eating away
10905d681e99Schristos  * leading whitespace. For the error codes, the handling of the end
10915d681e99Schristos  * pointer and the return values see 'strtol()'.
10925d681e99Schristos  */
10935d681e99Schristos static json_int
10945d681e99Schristos strtojint(
10955d681e99Schristos 	const char *cp, char **ep)
10965d681e99Schristos {
10975d681e99Schristos 	json_uint     accu, limit_lo, limit_hi;
10985d681e99Schristos 	int           flags; /* bit 0: overflow; bit 1: sign */
10995d681e99Schristos 	const char  * hold;
1100b8ecfcfeSchristos 
11015d681e99Schristos 	/* pointer union to circumvent a tricky/sticky const issue */
11025d681e99Schristos 	union {	const char * c; char * v; } vep;
1103b8ecfcfeSchristos 
11045d681e99Schristos 	/* store initial value of 'cp' -- see 'strtol()' */
11055d681e99Schristos 	vep.c = cp;
1106b8ecfcfeSchristos 
11075d681e99Schristos 	/* Eat away an optional sign and set the limits accordingly: The
11085d681e99Schristos 	 * high limit is the maximum absolute value that can be returned,
11095d681e99Schristos 	 * and the low limit is the biggest value that does not cause an
11105d681e99Schristos 	 * overflow when multiplied with 10. Avoid negation overflows.
11115d681e99Schristos 	 */
11125d681e99Schristos 	if (*cp == '-') {
11135d681e99Schristos 		cp += 1;
11145d681e99Schristos 		flags    = 2;
11155d681e99Schristos 		limit_hi = (json_uint)-(JSON_INT_MIN + 1) + 1;
11165d681e99Schristos 	} else {
11175d681e99Schristos 		cp += (*cp == '+');
11185d681e99Schristos 		flags    = 0;
11195d681e99Schristos 		limit_hi = (json_uint)JSON_INT_MAX;
11205d681e99Schristos 	}
11215d681e99Schristos 	limit_lo = limit_hi / 10;
11225d681e99Schristos 
11235d681e99Schristos 	/* Now try to convert a sequence of digits. */
11245d681e99Schristos 	hold = cp;
11255d681e99Schristos 	accu = 0;
1126af12ab5eSchristos 	while (isdigit(*(const u_char*)cp)) {
11275d681e99Schristos 		flags |= (accu > limit_lo);
1128af12ab5eSchristos 		accu = accu * 10 + (*(const u_char*)cp++ - '0');
11295d681e99Schristos 		flags |= (accu > limit_hi);
11305d681e99Schristos 	}
11315d681e99Schristos 	/* Check for empty conversion (no digits seen). */
11325d681e99Schristos 	if (hold != cp)
11335d681e99Schristos 		vep.c = cp;
11345d681e99Schristos 	else
11355d681e99Schristos 		errno = EINVAL;	/* accu is still zero */
11365d681e99Schristos 	/* Check for range overflow */
11375d681e99Schristos 	if (flags & 1) {
11385d681e99Schristos 		errno = ERANGE;
11395d681e99Schristos 		accu  = limit_hi;
11405d681e99Schristos 	}
11415d681e99Schristos 	/* If possible, store back the end-of-conversion pointer */
11425d681e99Schristos 	if (ep)
11435d681e99Schristos 		*ep = vep.v;
11445d681e99Schristos 	/* If negative, return the negated result if the accu is not
11455d681e99Schristos 	 * zero. Avoid negation overflows.
11465d681e99Schristos 	 */
11475d681e99Schristos 	if ((flags & 2) && accu)
11485d681e99Schristos 		return -(json_int)(accu - 1) - 1;
11495d681e99Schristos 	else
11505d681e99Schristos 		return (json_int)accu;
11515d681e99Schristos }
1152b8ecfcfeSchristos 
1153b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1154b8ecfcfeSchristos 
1155b8ecfcfeSchristos static tok_ref
1156b8ecfcfeSchristos json_token_skip(
1157b8ecfcfeSchristos 	const json_ctx * ctx,
1158b8ecfcfeSchristos 	tok_ref          tid)
1159b8ecfcfeSchristos {
11605d681e99Schristos 	if (tid >= 0 && tid < ctx->ntok) {
11615d681e99Schristos 		int len = ctx->tok[tid].size;
11625d681e99Schristos 		/* For arrays and objects, the size is the number of
11635d681e99Schristos 		 * ITEMS in the compound. Thats the number of objects in
11645d681e99Schristos 		 * the array, and the number of key/value pairs for
11655d681e99Schristos 		 * objects. In theory, the key must be a string, and we
11665d681e99Schristos 		 * could simply skip one token before skipping the
11675d681e99Schristos 		 * value, which can be anything. We're a bit paranoid
11685d681e99Schristos 		 * and lazy at the same time: We simply double the
11695d681e99Schristos 		 * number of tokens to skip and fall through into the
11705d681e99Schristos 		 * array processing when encountering an object.
11715d681e99Schristos 		 */
11725d681e99Schristos 		switch (ctx->tok[tid].type) {
11735d681e99Schristos 		case JSMN_OBJECT:
11745d681e99Schristos 			len *= 2;
11755d681e99Schristos 			/* FALLTHROUGH */
11765d681e99Schristos 		case JSMN_ARRAY:
1177b8ecfcfeSchristos 			for (++tid; len; --len)
1178b8ecfcfeSchristos 				tid = json_token_skip(ctx, tid);
1179b8ecfcfeSchristos 			break;
11805d681e99Schristos 
11815d681e99Schristos 		default:
11825d681e99Schristos 			++tid;
11835d681e99Schristos 			break;
11845d681e99Schristos 		}
118568dbbb44Schristos 		/* The next condition should never be true, but paranoia
118668dbbb44Schristos 		 * prevails...
118768dbbb44Schristos 		 */
118868dbbb44Schristos 		if (tid < 0 || tid > ctx->ntok)
1189b8ecfcfeSchristos 			tid = ctx->ntok;
11905d681e99Schristos 	}
1191b8ecfcfeSchristos 	return tid;
1192b8ecfcfeSchristos }
1193b8ecfcfeSchristos 
1194b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1195b8ecfcfeSchristos 
1196b8ecfcfeSchristos static int
1197b8ecfcfeSchristos json_object_lookup(
1198b8ecfcfeSchristos 	const json_ctx * ctx ,
1199b8ecfcfeSchristos 	tok_ref          tid ,
12005d681e99Schristos 	const char     * key ,
12015d681e99Schristos 	int              what)
1202b8ecfcfeSchristos {
1203b8ecfcfeSchristos 	int len;
1204b8ecfcfeSchristos 
12055d681e99Schristos 	if (tid < 0 || tid >= ctx->ntok ||
12065d681e99Schristos 	    ctx->tok[tid].type != JSMN_OBJECT)
1207b8ecfcfeSchristos 		return INVALID_TOKEN;
12085d681e99Schristos 
1209b8ecfcfeSchristos 	len = ctx->tok[tid].size;
12105d681e99Schristos 	for (++tid; len && tid+1 < ctx->ntok; --len) {
12115d681e99Schristos 		if (ctx->tok[tid].type != JSMN_STRING) { /* Blooper! */
12125d681e99Schristos 			tid = json_token_skip(ctx, tid); /* skip key */
12135d681e99Schristos 			tid = json_token_skip(ctx, tid); /* skip val */
12145d681e99Schristos 		} else if (strcmp(key, ctx->buf + ctx->tok[tid].start)) {
12155d681e99Schristos 			tid = json_token_skip(ctx, tid+1); /* skip key+val */
121668dbbb44Schristos 		} else if (what < 0 || (u_int)what == ctx->tok[tid+1].type) {
1217b8ecfcfeSchristos 			return tid + 1;
12185d681e99Schristos 		} else {
12195d681e99Schristos 			break;
12205d681e99Schristos 		}
12215d681e99Schristos 		/* if skipping ahead returned an error, bail out here. */
12225d681e99Schristos 		if (tid < 0)
12235d681e99Schristos 			break;
1224b8ecfcfeSchristos 	}
1225b8ecfcfeSchristos 	return INVALID_TOKEN;
1226b8ecfcfeSchristos }
1227b8ecfcfeSchristos 
1228b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1229b8ecfcfeSchristos 
12305d681e99Schristos static const char*
12315d681e99Schristos json_object_lookup_primitive(
12325d681e99Schristos 	const json_ctx * ctx,
12335d681e99Schristos 	tok_ref          tid,
12345d681e99Schristos 	const char     * key)
12355d681e99Schristos {
12365d681e99Schristos 	tid = json_object_lookup(ctx, tid, key, JSMN_PRIMITIVE);
12375d681e99Schristos 	if (INVALID_TOKEN  != tid)
12385d681e99Schristos 		return ctx->buf + ctx->tok[tid].start;
12395d681e99Schristos 	else
12405d681e99Schristos 		return NULL;
12415d681e99Schristos }
12425d681e99Schristos /* ------------------------------------------------------------------ */
12435d681e99Schristos /* look up a boolean value. This essentially returns a tribool:
12445d681e99Schristos  * 0->false, 1->true, (-1)->error/undefined
12455d681e99Schristos  */
12465d681e99Schristos static int
12475d681e99Schristos json_object_lookup_bool(
12485d681e99Schristos 	const json_ctx * ctx,
12495d681e99Schristos 	tok_ref          tid,
12505d681e99Schristos 	const char     * key)
12515d681e99Schristos {
12525d681e99Schristos 	const char *cp;
12535d681e99Schristos 	cp  = json_object_lookup_primitive(ctx, tid, key);
12545d681e99Schristos 	switch ( cp ? *cp : '\0') {
12555d681e99Schristos 	case 't': return  1;
12565d681e99Schristos 	case 'f': return  0;
12575d681e99Schristos 	default : return -1;
12585d681e99Schristos 	}
12595d681e99Schristos }
12605d681e99Schristos 
12615d681e99Schristos /* ------------------------------------------------------------------ */
12625d681e99Schristos 
1263b8ecfcfeSchristos static const char*
1264b8ecfcfeSchristos json_object_lookup_string(
1265b8ecfcfeSchristos 	const json_ctx * ctx,
1266b8ecfcfeSchristos 	tok_ref          tid,
1267b8ecfcfeSchristos 	const char     * key)
1268b8ecfcfeSchristos {
12695d681e99Schristos 	tid = json_object_lookup(ctx, tid, key, JSMN_STRING);
12705d681e99Schristos 	if (INVALID_TOKEN != tid)
12715d681e99Schristos 		return ctx->buf + ctx->tok[tid].start;
1272b8ecfcfeSchristos 	return NULL;
1273b8ecfcfeSchristos }
1274b8ecfcfeSchristos 
1275b8ecfcfeSchristos static const char*
1276b8ecfcfeSchristos json_object_lookup_string_default(
1277b8ecfcfeSchristos 	const json_ctx * ctx,
1278b8ecfcfeSchristos 	tok_ref          tid,
1279b8ecfcfeSchristos 	const char     * key,
1280b8ecfcfeSchristos 	const char     * def)
1281b8ecfcfeSchristos {
12825d681e99Schristos 	tid = json_object_lookup(ctx, tid, key, JSMN_STRING);
12835d681e99Schristos 	if (INVALID_TOKEN != tid)
12845d681e99Schristos 		return ctx->buf + ctx->tok[tid].start;
1285b8ecfcfeSchristos 	return def;
1286b8ecfcfeSchristos }
1287b8ecfcfeSchristos 
1288b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1289b8ecfcfeSchristos 
1290b8ecfcfeSchristos static json_int
1291b8ecfcfeSchristos json_object_lookup_int(
1292b8ecfcfeSchristos 	const json_ctx * ctx,
1293b8ecfcfeSchristos 	tok_ref          tid,
1294b8ecfcfeSchristos 	const char     * key)
1295b8ecfcfeSchristos {
1296b8ecfcfeSchristos 	json_int     ret;
12975d681e99Schristos 	const char * cp;
1298b8ecfcfeSchristos 	char       * ep;
1299b8ecfcfeSchristos 
13005d681e99Schristos 	cp = json_object_lookup_primitive(ctx, tid, key);
13015d681e99Schristos 	if (NULL != cp) {
13025d681e99Schristos 		ret = strtojint(cp, &ep);
13035d681e99Schristos 		if (cp != ep && '\0' == *ep)
1304b8ecfcfeSchristos 			return ret;
13055d681e99Schristos 	} else {
1306b8ecfcfeSchristos 		errno = EINVAL;
13075d681e99Schristos 	}
1308b8ecfcfeSchristos 	return 0;
1309b8ecfcfeSchristos }
1310b8ecfcfeSchristos 
1311b8ecfcfeSchristos static json_int
1312b8ecfcfeSchristos json_object_lookup_int_default(
1313b8ecfcfeSchristos 	const json_ctx * ctx,
1314b8ecfcfeSchristos 	tok_ref          tid,
1315b8ecfcfeSchristos 	const char     * key,
1316b8ecfcfeSchristos 	json_int         def)
1317b8ecfcfeSchristos {
13185d681e99Schristos 	json_int     ret;
13195d681e99Schristos 	const char * cp;
13205d681e99Schristos 	char       * ep;
1321b8ecfcfeSchristos 
13225d681e99Schristos 	cp = json_object_lookup_primitive(ctx, tid, key);
13235d681e99Schristos 	if (NULL != cp) {
13245d681e99Schristos 		ret = strtojint(cp, &ep);
13255d681e99Schristos 		if (cp != ep && '\0' == *ep)
13265d681e99Schristos 			return ret;
13275d681e99Schristos 	}
13285d681e99Schristos 	return def;
1329b8ecfcfeSchristos }
1330b8ecfcfeSchristos 
1331b8ecfcfeSchristos /* ------------------------------------------------------------------ */
13325d681e99Schristos #if 0 /* currently unused */
1333b8ecfcfeSchristos static double
1334b8ecfcfeSchristos json_object_lookup_float(
1335b8ecfcfeSchristos 	const json_ctx * ctx,
1336b8ecfcfeSchristos 	tok_ref          tid,
1337b8ecfcfeSchristos 	const char     * key)
1338b8ecfcfeSchristos {
1339b8ecfcfeSchristos 	double       ret;
13405d681e99Schristos 	const char * cp;
1341b8ecfcfeSchristos 	char       * ep;
1342b8ecfcfeSchristos 
13435d681e99Schristos 	cp = json_object_lookup_primitive(ctx, tid, key);
13445d681e99Schristos 	if (NULL != cp) {
13455d681e99Schristos 		ret = strtod(cp, &ep);
13465d681e99Schristos 		if (cp != ep && '\0' == *ep)
1347b8ecfcfeSchristos 			return ret;
13485d681e99Schristos 	} else {
1349b8ecfcfeSchristos 		errno = EINVAL;
13505d681e99Schristos 	}
1351b8ecfcfeSchristos 	return 0.0;
1352b8ecfcfeSchristos }
13535d681e99Schristos #endif
1354b8ecfcfeSchristos 
1355b8ecfcfeSchristos static double
1356b8ecfcfeSchristos json_object_lookup_float_default(
1357b8ecfcfeSchristos 	const json_ctx * ctx,
1358b8ecfcfeSchristos 	tok_ref          tid,
1359b8ecfcfeSchristos 	const char     * key,
1360b8ecfcfeSchristos 	double           def)
1361b8ecfcfeSchristos {
13625d681e99Schristos 	double       ret;
13635d681e99Schristos 	const char * cp;
13645d681e99Schristos 	char       * ep;
1365b8ecfcfeSchristos 
13665d681e99Schristos 	cp = json_object_lookup_primitive(ctx, tid, key);
13675d681e99Schristos 	if (NULL != cp) {
13685d681e99Schristos 		ret = strtod(cp, &ep);
13695d681e99Schristos 		if (cp != ep && '\0' == *ep)
13705d681e99Schristos 			return ret;
13715d681e99Schristos 	}
13725d681e99Schristos 	return def;
1373b8ecfcfeSchristos }
1374b8ecfcfeSchristos 
1375b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1376b8ecfcfeSchristos 
1377b8ecfcfeSchristos static BOOL
1378b8ecfcfeSchristos json_parse_record(
1379b8ecfcfeSchristos 	json_ctx * ctx,
13805d681e99Schristos 	char     * buf,
13815d681e99Schristos 	size_t     len)
1382b8ecfcfeSchristos {
1383b8ecfcfeSchristos 	jsmn_parser jsm;
1384b8ecfcfeSchristos 	int         idx, rc;
1385b8ecfcfeSchristos 
1386b8ecfcfeSchristos 	jsmn_init(&jsm);
13875d681e99Schristos 	rc = jsmn_parse(&jsm, buf, len, ctx->tok, JSMN_MAXTOK);
13885d681e99Schristos 	if (rc <= 0)
13895d681e99Schristos 		return FALSE;
1390b8ecfcfeSchristos 	ctx->buf  = buf;
13915d681e99Schristos 	ctx->ntok = rc;
13925d681e99Schristos 
13935d681e99Schristos 	if (JSMN_OBJECT != ctx->tok[0].type)
13945d681e99Schristos 		return FALSE; /* not object!?! */
1395b8ecfcfeSchristos 
1396b8ecfcfeSchristos 	/* Make all tokens NUL terminated by overwriting the
13975d681e99Schristos 	 * terminator symbol. Makes string compares and number parsing a
13985d681e99Schristos 	 * lot easier!
1399b8ecfcfeSchristos 	 */
14005d681e99Schristos 	for (idx = 0; idx < ctx->ntok; ++idx)
1401b8ecfcfeSchristos 		if (ctx->tok[idx].end > ctx->tok[idx].start)
1402b8ecfcfeSchristos 			ctx->buf[ctx->tok[idx].end] = '\0';
1403b8ecfcfeSchristos 	return TRUE;
1404b8ecfcfeSchristos }
1405b8ecfcfeSchristos 
1406b8ecfcfeSchristos 
1407b8ecfcfeSchristos /* =====================================================================
1408b8ecfcfeSchristos  * static local helpers
1409b8ecfcfeSchristos  */
14105d681e99Schristos static BOOL
14115d681e99Schristos get_binary_time(
14125d681e99Schristos 	l_fp       * const dest     ,
14135d681e99Schristos 	json_ctx   * const jctx     ,
14145d681e99Schristos 	const char * const time_name,
14155d681e99Schristos 	const char * const frac_name,
14165d681e99Schristos 	long               fscale   )
14175d681e99Schristos {
14185d681e99Schristos 	BOOL            retv = FALSE;
14195d681e99Schristos 	struct timespec ts;
14205d681e99Schristos 
14215d681e99Schristos 	errno = 0;
14225d681e99Schristos 	ts.tv_sec  = (time_t)json_object_lookup_int(jctx, 0, time_name);
14235d681e99Schristos 	ts.tv_nsec = (long  )json_object_lookup_int(jctx, 0, frac_name);
14245d681e99Schristos 	if (0 == errno) {
14255d681e99Schristos 		ts.tv_nsec *= fscale;
14265d681e99Schristos 		*dest = tspec_stamp_to_lfp(ts);
14275d681e99Schristos 		retv  = TRUE;
14285d681e99Schristos 	}
14295d681e99Schristos 	return retv;
14305d681e99Schristos }
1431b8ecfcfeSchristos 
1432b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1433b8ecfcfeSchristos /* Process a WATCH record
1434b8ecfcfeSchristos  *
1435b8ecfcfeSchristos  * Currently this is only used to recognise that the device is present
1436b8ecfcfeSchristos  * and that we're listed subscribers.
1437b8ecfcfeSchristos  */
1438b8ecfcfeSchristos static void
1439b8ecfcfeSchristos process_watch(
1440b8ecfcfeSchristos 	peerT      * const peer ,
1441b8ecfcfeSchristos 	json_ctx   * const jctx ,
1442b8ecfcfeSchristos 	const l_fp * const rtime)
1443b8ecfcfeSchristos {
1444b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
1445b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1446b8ecfcfeSchristos 
14475d681e99Schristos 	const char * path;
14485d681e99Schristos 
14495d681e99Schristos 	path = json_object_lookup_string(jctx, 0, "device");
14505d681e99Schristos 	if (NULL == path || strcmp(path, up->device))
14515d681e99Schristos 		return;
14525d681e99Schristos 
14535d681e99Schristos 	if (json_object_lookup_bool(jctx, 0, "enable") > 0 &&
14545d681e99Schristos 	    json_object_lookup_bool(jctx, 0, "json"  ) > 0  )
1455b8ecfcfeSchristos 		up->fl_watch = -1;
14565d681e99Schristos 	else
14575d681e99Schristos 		up->fl_watch = 0;
14585d681e99Schristos 	DPRINTF(2, ("%s: process_watch, enabled=%d\n",
14595d681e99Schristos 		    up->logname, (up->fl_watch & 1)));
1460b8ecfcfeSchristos }
1461b8ecfcfeSchristos 
1462b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1463b8ecfcfeSchristos 
1464b8ecfcfeSchristos static void
1465b8ecfcfeSchristos process_version(
1466b8ecfcfeSchristos 	peerT      * const peer ,
1467b8ecfcfeSchristos 	json_ctx   * const jctx ,
1468b8ecfcfeSchristos 	const l_fp * const rtime)
1469b8ecfcfeSchristos {
1470b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
1471b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1472b8ecfcfeSchristos 
1473b8ecfcfeSchristos 	int    len;
1474b8ecfcfeSchristos 	char * buf;
1475b8ecfcfeSchristos 	const char *revision;
1476b8ecfcfeSchristos 	const char *release;
14775d681e99Schristos 	uint16_t    pvhi, pvlo;
1478b8ecfcfeSchristos 
1479b8ecfcfeSchristos 	/* get protocol version number */
1480b8ecfcfeSchristos 	revision = json_object_lookup_string_default(
1481b8ecfcfeSchristos 		jctx, 0, "rev", "(unknown)");
1482b8ecfcfeSchristos 	release  = json_object_lookup_string_default(
1483b8ecfcfeSchristos 		jctx, 0, "release", "(unknown)");
1484b8ecfcfeSchristos 	errno = 0;
14855d681e99Schristos 	pvhi = (uint16_t)json_object_lookup_int(jctx, 0, "proto_major");
14865d681e99Schristos 	pvlo = (uint16_t)json_object_lookup_int(jctx, 0, "proto_minor");
14875d681e99Schristos 
1488b8ecfcfeSchristos 	if (0 == errno) {
14895d681e99Schristos 		if ( ! up->fl_vers)
1490b8ecfcfeSchristos 			msyslog(LOG_INFO,
1491b8ecfcfeSchristos 				"%s: GPSD revision=%s release=%s protocol=%u.%u",
14925d681e99Schristos 				up->logname, revision, release,
14935d681e99Schristos 				pvhi, pvlo);
14945d681e99Schristos 		up->proto_version = PROTO_VERSION(pvhi, pvlo);
14955d681e99Schristos 		up->fl_vers = -1;
14965d681e99Schristos 	} else {
14975d681e99Schristos 		if (syslogok(pp, up))
14985d681e99Schristos 			msyslog(LOG_INFO,
14995d681e99Schristos 				"%s: could not evaluate version data",
15005d681e99Schristos 				up->logname);
15015d681e99Schristos 		return;
1502b8ecfcfeSchristos 	}
15035d681e99Schristos 	/* With the 3.9 GPSD protocol, '*_musec' vanished from the PPS
15045d681e99Schristos 	 * record and was replace by '*_nsec'.
1505b8ecfcfeSchristos 	 */
15065d681e99Schristos 	up->pf_nsec = -(up->proto_version >= PROTO_VERSION(3,9));
1507b8ecfcfeSchristos 
15085d681e99Schristos 	/* With the 3.10 protocol we can get TOFF records for better
15095d681e99Schristos 	 * timing information.
15105d681e99Schristos 	 */
15115d681e99Schristos 	up->pf_toff = -(up->proto_version >= PROTO_VERSION(3,10));
1512b8ecfcfeSchristos 
15135d681e99Schristos 	/* request watch for our GPS device if not yet watched.
15145d681e99Schristos 	 *
15155d681e99Schristos 	 * The version string is also sent as a life signal, if we have
15165d681e99Schristos 	 * seen useable data. So if we're already watching the device,
15175d681e99Schristos 	 * skip the request.
15185d681e99Schristos 	 *
1519b8ecfcfeSchristos 	 * Reuse the input buffer, which is no longer needed in the
1520b8ecfcfeSchristos 	 * current cycle. Also assume that we can write the watch
1521b8ecfcfeSchristos 	 * request in one sweep into the socket; since we do not do
1522b8ecfcfeSchristos 	 * output otherwise, this should always work.  (Unless the
1523b8ecfcfeSchristos 	 * TCP/IP window size gets lower than the length of the
1524b8ecfcfeSchristos 	 * request. We handle that when it happens.)
1525b8ecfcfeSchristos 	 */
15265d681e99Schristos 	if (up->fl_watch)
15275d681e99Schristos 		return;
15285d681e99Schristos 
152968dbbb44Schristos 	/* The logon string is actually the ?WATCH command of GPSD,
153068dbbb44Schristos 	 * using JSON data and selecting the GPS device name we created
1531*eabc0478Schristos 	 * from our unit number. We have an old and a newer version that
153268dbbb44Schristos 	 * request PPS (and TOFF) transmission.
15335d681e99Schristos 	 */
1534b8ecfcfeSchristos 	snprintf(up->buffer, sizeof(up->buffer),
15355d681e99Schristos 		 "?WATCH={\"device\":\"%s\",\"enable\":true,\"json\":true%s};\r\n",
153668dbbb44Schristos 		 up->device, (up->pf_toff ? ",\"pps\":true" : ""));
1537b8ecfcfeSchristos 	buf = up->buffer;
1538b8ecfcfeSchristos 	len = strlen(buf);
1539*eabc0478Schristos 	log_data(peer, 2, "send", buf, len);
15405d681e99Schristos 	if (len != write(pp->io.fd, buf, len) && (syslogok(pp, up))) {
1541b8ecfcfeSchristos 		/* Note: if the server fails to read our request, the
1542b8ecfcfeSchristos 		 * resulting data timeout will take care of the
1543b8ecfcfeSchristos 		 * connection!
1544b8ecfcfeSchristos 		 */
15455d681e99Schristos 		msyslog(LOG_ERR, "%s: failed to write watch request (%m)",
15465d681e99Schristos 			up->logname);
1547b8ecfcfeSchristos 	}
1548b8ecfcfeSchristos }
1549b8ecfcfeSchristos 
1550b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1551b8ecfcfeSchristos 
1552b8ecfcfeSchristos static void
1553b8ecfcfeSchristos process_tpv(
1554b8ecfcfeSchristos 	peerT      * const peer ,
1555b8ecfcfeSchristos 	json_ctx   * const jctx ,
1556b8ecfcfeSchristos 	const l_fp * const rtime)
1557b8ecfcfeSchristos {
1558b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
1559b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1560b8ecfcfeSchristos 
1561b8ecfcfeSchristos 	const char * gps_time;
1562b8ecfcfeSchristos 	int          gps_mode;
15635d681e99Schristos 	double       ept;
156422b6c4fcSchristos 	int          xlog2;
1565b8ecfcfeSchristos 
1566b8ecfcfeSchristos 	gps_mode = (int)json_object_lookup_int_default(
1567b8ecfcfeSchristos 		jctx, 0, "mode", 0);
1568b8ecfcfeSchristos 
15695d681e99Schristos 	gps_time = json_object_lookup_string(
15705d681e99Schristos 		jctx, 0, "time");
1571b8ecfcfeSchristos 
15725d681e99Schristos 	/* accept time stamps only in 2d or 3d fix */
15735d681e99Schristos 	if (gps_mode < 2 || NULL == gps_time) {
1574b8ecfcfeSchristos 		/* receiver has no fix; tell about and avoid stale data */
15755d681e99Schristos 		if ( ! up->pf_toff)
15765d681e99Schristos 			++up->tc_sti_recv;
15775d681e99Schristos 		++up->tc_nosync;
15785d681e99Schristos 		up->fl_sti    = 0;
1579b8ecfcfeSchristos 		up->fl_pps    = 0;
15805d681e99Schristos 		up->fl_nosync = -1;
1581b8ecfcfeSchristos 		return;
1582b8ecfcfeSchristos 	}
15835d681e99Schristos 	up->fl_nosync = 0;
1584b8ecfcfeSchristos 
15855d681e99Schristos 	/* convert clock and set resulting ref time, but only if the
15865d681e99Schristos 	 * TOFF sentence is *not* available
15875d681e99Schristos 	 */
15885d681e99Schristos 	if ( ! up->pf_toff) {
15895d681e99Schristos 		++up->tc_sti_recv;
1590b8ecfcfeSchristos 		/* save last time code to clock data */
1591b8ecfcfeSchristos 		save_ltc(pp, gps_time);
15925d681e99Schristos 		/* now parse the time string */
15935d681e99Schristos 		if (convert_ascii_time(&up->sti_stamp, gps_time)) {
15945d681e99Schristos 			DPRINTF(2, ("%s: process_tpv, stamp='%s',"
15955d681e99Schristos 				    " recvt='%s' mode=%u\n",
15965d681e99Schristos 				    up->logname,
15975d681e99Schristos 				    gmprettydate(&up->sti_stamp),
15985d681e99Schristos 				    gmprettydate(&up->sti_recvt),
1599b8ecfcfeSchristos 				    gps_mode));
1600b8ecfcfeSchristos 
16015d681e99Schristos 			/* have to use local receive time as substitute
16025d681e99Schristos 			 * for the real receive time: TPV does not tell
16035d681e99Schristos 			 * us.
16045d681e99Schristos 			 */
16055d681e99Schristos 			up->sti_local = *rtime;
16065d681e99Schristos 			up->sti_recvt = *rtime;
16075d681e99Schristos 			L_SUB(&up->sti_recvt, &up->sti_fudge);
16085d681e99Schristos 			up->fl_sti = -1;
1609b8ecfcfeSchristos 		} else {
16105d681e99Schristos 			++up->tc_breply;
16115d681e99Schristos 			up->fl_sti = 0;
16125d681e99Schristos 		}
1613b8ecfcfeSchristos 	}
1614b8ecfcfeSchristos 
1615b8ecfcfeSchristos 	/* Set the precision from the GPSD data
16165d681e99Schristos 	 * Use the ETP field for an estimation of the precision of the
16175d681e99Schristos 	 * serial data. If ETP is not available, use the default serial
16185d681e99Schristos 	 * data presion instead. (Note: The PPS branch has a different
16195d681e99Schristos 	 * precision estimation, since it gets the proper value directly
16205d681e99Schristos 	 * from GPSD!)
1621b8ecfcfeSchristos 	 */
16225d681e99Schristos 	ept = json_object_lookup_float_default(jctx, 0, "ept", 2.0e-3);
16235d681e99Schristos 	ept = frexp(fabs(ept)*0.70710678, &xlog2); /* ~ sqrt(0.5) */
16245d681e99Schristos 	if (ept < 0.25)
16255d681e99Schristos 		xlog2 = INT_MIN;
16265d681e99Schristos 	if (ept > 2.0)
16275d681e99Schristos 		xlog2 = INT_MAX;
16285d681e99Schristos 	up->sti_prec = clamped_precision(xlog2);
1629b8ecfcfeSchristos }
1630b8ecfcfeSchristos 
1631b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1632b8ecfcfeSchristos 
1633b8ecfcfeSchristos static void
1634b8ecfcfeSchristos process_pps(
1635b8ecfcfeSchristos 	peerT      * const peer ,
1636b8ecfcfeSchristos 	json_ctx   * const jctx ,
1637b8ecfcfeSchristos 	const l_fp * const rtime)
1638b8ecfcfeSchristos {
1639b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
1640b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1641b8ecfcfeSchristos 
16425d681e99Schristos 	int xlog2;
1643b8ecfcfeSchristos 
16445d681e99Schristos 	++up->tc_pps_recv;
1645b8ecfcfeSchristos 
16465d681e99Schristos 	/* Bail out if there's indication that time sync is bad or
16475d681e99Schristos 	 * if we're explicitely requested to ignore PPS data.
16485d681e99Schristos 	 */
16495d681e99Schristos 	if (up->fl_nosync)
16505d681e99Schristos 		return;
1651b8ecfcfeSchristos 
1652b8ecfcfeSchristos 	up->pps_local = *rtime;
16535d681e99Schristos 	/* Now grab the time values. 'clock_*' is the event time of the
16545d681e99Schristos 	 * pulse measured on the local system clock; 'real_*' is the GPS
16555d681e99Schristos 	 * reference time GPSD associated with the pulse.
16565d681e99Schristos 	 */
16575d681e99Schristos 	if (up->pf_nsec) {
16585d681e99Schristos 		if ( ! get_binary_time(&up->pps_recvt2, jctx,
16595d681e99Schristos 				       "clock_sec", "clock_nsec", 1))
16605d681e99Schristos 			goto fail;
16615d681e99Schristos 		if ( ! get_binary_time(&up->pps_stamp2, jctx,
16625d681e99Schristos 				       "real_sec", "real_nsec", 1))
16635d681e99Schristos 			goto fail;
16645d681e99Schristos 	} else {
16655d681e99Schristos 		if ( ! get_binary_time(&up->pps_recvt2, jctx,
16665d681e99Schristos 				       "clock_sec", "clock_musec", 1000))
16675d681e99Schristos 			goto fail;
16685d681e99Schristos 		if ( ! get_binary_time(&up->pps_stamp2, jctx,
16695d681e99Schristos 				       "real_sec", "real_musec", 1000))
16705d681e99Schristos 			goto fail;
16715d681e99Schristos 	}
1672b8ecfcfeSchristos 
16735d681e99Schristos 	/* Try to read the precision field from the PPS record. If it's
16745d681e99Schristos 	 * not there, take the precision from the serial data.
16755d681e99Schristos 	 */
16765d681e99Schristos 	xlog2 = json_object_lookup_int_default(
16775d681e99Schristos 			jctx, 0, "precision", up->sti_prec);
16785d681e99Schristos 	up->pps_prec = clamped_precision(xlog2);
16795d681e99Schristos 
16805d681e99Schristos 	/* Get fudged receive times for primary & secondary unit */
16815d681e99Schristos 	up->pps_recvt = up->pps_recvt2;
16825d681e99Schristos 	L_SUB(&up->pps_recvt , &up->pps_fudge );
16835d681e99Schristos 	L_SUB(&up->pps_recvt2, &up->pps_fudge2);
16845d681e99Schristos 	pp->lastrec = up->pps_recvt;
16855d681e99Schristos 
16865d681e99Schristos 	/* Map to nearest full second as reference time stamp for the
16875d681e99Schristos 	 * primary channel. Sanity checks are done in evaluation step.
16885d681e99Schristos 	 */
1689b8ecfcfeSchristos 	up->pps_stamp = up->pps_recvt;
1690b8ecfcfeSchristos 	L_ADDUF(&up->pps_stamp, 0x80000000u);
1691b8ecfcfeSchristos 	up->pps_stamp.l_uf = 0;
1692b8ecfcfeSchristos 
16935d681e99Schristos 	if (NULL != up->pps_peer)
16945d681e99Schristos 		save_ltc(up->pps_peer->procptr,
16955d681e99Schristos 			 gmprettydate(&up->pps_stamp2));
16965d681e99Schristos 	DPRINTF(2, ("%s: PPS record processed,"
16975d681e99Schristos 		    " stamp='%s', recvt='%s'\n",
16985d681e99Schristos 		    up->logname,
16995d681e99Schristos 		    gmprettydate(&up->pps_stamp2),
17005d681e99Schristos 		    gmprettydate(&up->pps_recvt2)));
1701b8ecfcfeSchristos 
17025d681e99Schristos 	up->fl_pps  = (0 != (pp->sloppyclockflag & CLK_FLAG2)) - 1;
17035d681e99Schristos 	up->fl_pps2 = -1;
1704b8ecfcfeSchristos 	return;
1705b8ecfcfeSchristos 
1706b8ecfcfeSchristos   fail:
17075d681e99Schristos 	DPRINTF(1, ("%s: PPS record processing FAILED\n",
17085d681e99Schristos 		    up->logname));
17095d681e99Schristos 	++up->tc_breply;
17105d681e99Schristos }
17115d681e99Schristos 
17125d681e99Schristos /* ------------------------------------------------------------------ */
17135d681e99Schristos 
17145d681e99Schristos static void
17155d681e99Schristos process_toff(
17165d681e99Schristos 	peerT      * const peer ,
17175d681e99Schristos 	json_ctx   * const jctx ,
17185d681e99Schristos 	const l_fp * const rtime)
17195d681e99Schristos {
17205d681e99Schristos 	clockprocT * const pp = peer->procptr;
17215d681e99Schristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
17225d681e99Schristos 
17235d681e99Schristos 	++up->tc_sti_recv;
17245d681e99Schristos 
17255d681e99Schristos 	/* remember this! */
17265d681e99Schristos 	up->pf_toff = -1;
17275d681e99Schristos 
17285d681e99Schristos 	/* bail out if there's indication that time sync is bad */
17295d681e99Schristos 	if (up->fl_nosync)
17305d681e99Schristos 		return;
17315d681e99Schristos 
17325d681e99Schristos 	if ( ! get_binary_time(&up->sti_recvt, jctx,
17335d681e99Schristos 			       "clock_sec", "clock_nsec", 1))
17345d681e99Schristos 			goto fail;
17355d681e99Schristos 	if ( ! get_binary_time(&up->sti_stamp, jctx,
17365d681e99Schristos 			       "real_sec", "real_nsec", 1))
17375d681e99Schristos 			goto fail;
17385d681e99Schristos 	L_SUB(&up->sti_recvt, &up->sti_fudge);
17395d681e99Schristos 	up->sti_local = *rtime;
17405d681e99Schristos 	up->fl_sti    = -1;
17415d681e99Schristos 
17425d681e99Schristos 	save_ltc(pp, gmprettydate(&up->sti_stamp));
17435d681e99Schristos 	DPRINTF(2, ("%s: TOFF record processed,"
17445d681e99Schristos 		    " stamp='%s', recvt='%s'\n",
17455d681e99Schristos 		    up->logname,
17465d681e99Schristos 		    gmprettydate(&up->sti_stamp),
17475d681e99Schristos 		    gmprettydate(&up->sti_recvt)));
17485d681e99Schristos 	return;
17495d681e99Schristos 
17505d681e99Schristos   fail:
17515d681e99Schristos 	DPRINTF(1, ("%s: TOFF record processing FAILED\n",
17525d681e99Schristos 		    up->logname));
17535d681e99Schristos 	++up->tc_breply;
1754b8ecfcfeSchristos }
1755b8ecfcfeSchristos 
1756b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1757b8ecfcfeSchristos 
1758b8ecfcfeSchristos static void
1759b8ecfcfeSchristos gpsd_parse(
1760b8ecfcfeSchristos 	peerT      * const peer ,
1761b8ecfcfeSchristos 	const l_fp * const rtime)
1762b8ecfcfeSchristos {
1763b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
1764b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1765b8ecfcfeSchristos 
1766b8ecfcfeSchristos 	const char * clsid;
1767b8ecfcfeSchristos 
17685d681e99Schristos         DPRINTF(2, ("%s: gpsd_parse: time %s '%.*s'\n",
17695d681e99Schristos                     up->logname, ulfptoa(rtime, 6),
17705d681e99Schristos 		    up->buflen, up->buffer));
1771b8ecfcfeSchristos 
17725d681e99Schristos 	/* See if we can grab anything potentially useful. JSMN does not
17735d681e99Schristos 	 * need a trailing NUL, but it needs the number of bytes to
17745d681e99Schristos 	 * process. */
17755d681e99Schristos 	if (!json_parse_record(&up->json_parse, up->buffer, up->buflen)) {
17765d681e99Schristos 		++up->tc_breply;
1777b8ecfcfeSchristos 		return;
17785d681e99Schristos 	}
1779b8ecfcfeSchristos 
1780b8ecfcfeSchristos 	/* Now dispatch over the objects we know */
17815d681e99Schristos 	clsid = json_object_lookup_string(&up->json_parse, 0, "class");
17825d681e99Schristos 	if (NULL == clsid) {
17835d681e99Schristos 		++up->tc_breply;
17845d681e99Schristos 		return;
17855d681e99Schristos 	}
1786b8ecfcfeSchristos 
17875d681e99Schristos 	if      (!strcmp("TPV", clsid))
17885d681e99Schristos 		process_tpv(peer, &up->json_parse, rtime);
1789b8ecfcfeSchristos 	else if (!strcmp("PPS", clsid))
17905d681e99Schristos 		process_pps(peer, &up->json_parse, rtime);
17915d681e99Schristos 	else if (!strcmp("TOFF", clsid))
17925d681e99Schristos 		process_toff(peer, &up->json_parse, rtime);
17935d681e99Schristos 	else if (!strcmp("VERSION", clsid))
17945d681e99Schristos 		process_version(peer, &up->json_parse, rtime);
1795b8ecfcfeSchristos 	else if (!strcmp("WATCH", clsid))
17965d681e99Schristos 		process_watch(peer, &up->json_parse, rtime);
1797b8ecfcfeSchristos 	else
1798b8ecfcfeSchristos 		return; /* nothing we know about... */
17995d681e99Schristos 	++up->tc_recv;
1800b8ecfcfeSchristos 
18015d681e99Schristos 	/* if possible, feed the PPS side channel */
18025d681e99Schristos 	if (up->pps_peer)
18035d681e99Schristos 		eval_pps_secondary(
18045d681e99Schristos 			up->pps_peer, up->pps_peer->procptr, up);
1805b8ecfcfeSchristos 
18065d681e99Schristos 	/* check PPS vs. STI receive times:
18075d681e99Schristos 	 * If STI is before PPS, then clearly the STI is too old. If PPS
18085d681e99Schristos 	 * is before STI by more than one second, then PPS is too old.
18095d681e99Schristos 	 * Weed out stale time stamps & flags.
18105d681e99Schristos 	 */
18115d681e99Schristos 	if (up->fl_pps && up->fl_sti) {
18125d681e99Schristos 		l_fp diff;
18135d681e99Schristos 		diff = up->sti_local;
18145d681e99Schristos 		L_SUB(&diff, &up->pps_local);
18155d681e99Schristos 		if (diff.l_i > 0)
18165d681e99Schristos 			up->fl_pps = 0; /* pps too old */
18175d681e99Schristos 		else if (diff.l_i < 0)
18185d681e99Schristos 			up->fl_sti = 0; /* serial data too old */
1819b8ecfcfeSchristos 	}
18205d681e99Schristos 
18215d681e99Schristos 	/* dispatch to the mode-dependent processing functions */
18225d681e99Schristos 	switch (up->mode) {
18235d681e99Schristos 	default:
18245d681e99Schristos 	case MODE_OP_STI:
18255d681e99Schristos 		eval_serial(peer, pp, up);
18265d681e99Schristos 		break;
18275d681e99Schristos 
18285d681e99Schristos 	case MODE_OP_STRICT:
18295d681e99Schristos 		eval_strict(peer, pp, up);
18305d681e99Schristos 		break;
18315d681e99Schristos 
18325d681e99Schristos 	case MODE_OP_AUTO:
18335d681e99Schristos 		eval_auto(peer, pp, up);
18345d681e99Schristos 		break;
1835b8ecfcfeSchristos 	}
1836b8ecfcfeSchristos }
1837b8ecfcfeSchristos 
1838b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1839b8ecfcfeSchristos 
1840b8ecfcfeSchristos static void
1841b8ecfcfeSchristos gpsd_stop_socket(
1842b8ecfcfeSchristos 	peerT * const peer)
1843b8ecfcfeSchristos {
1844b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
1845b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1846b8ecfcfeSchristos 
18475d681e99Schristos 	if (-1 != pp->io.fd) {
1848b8ecfcfeSchristos 		if (syslogok(pp, up))
1849b8ecfcfeSchristos 			msyslog(LOG_INFO,
18505d681e99Schristos 				"%s: closing socket to GPSD, fd=%d",
18515d681e99Schristos 				up->logname, pp->io.fd);
18525d681e99Schristos 		else
18535d681e99Schristos 			DPRINTF(1, ("%s: closing socket to GPSD, fd=%d\n",
18545d681e99Schristos 				    up->logname, pp->io.fd));
18555d681e99Schristos 		io_closeclock(&pp->io);
18565d681e99Schristos 		pp->io.fd = -1;
18575d681e99Schristos 	}
1858b8ecfcfeSchristos 	up->tickover = up->tickpres;
1859b8ecfcfeSchristos 	up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH);
1860b8ecfcfeSchristos 	up->fl_vers  = 0;
18615d681e99Schristos 	up->fl_sti   = 0;
1862b8ecfcfeSchristos 	up->fl_pps   = 0;
1863b8ecfcfeSchristos 	up->fl_watch = 0;
1864b8ecfcfeSchristos }
1865b8ecfcfeSchristos 
1866b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1867b8ecfcfeSchristos 
1868b8ecfcfeSchristos static void
1869b8ecfcfeSchristos gpsd_init_socket(
1870b8ecfcfeSchristos 	peerT * const peer)
1871b8ecfcfeSchristos {
1872b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
1873b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1874b8ecfcfeSchristos 	addrinfoT  * ai;
1875b8ecfcfeSchristos 	int          rc;
1876b8ecfcfeSchristos 	int          ov;
1877b8ecfcfeSchristos 
1878b8ecfcfeSchristos 	/* draw next address to try */
1879b8ecfcfeSchristos 	if (NULL == up->addr)
1880b8ecfcfeSchristos 		up->addr = s_gpsd_addr;
1881b8ecfcfeSchristos 	ai = up->addr;
1882b8ecfcfeSchristos 	up->addr = ai->ai_next;
1883b8ecfcfeSchristos 
1884b8ecfcfeSchristos 	/* try to create a matching socket */
1885b8ecfcfeSchristos 	up->fdt = socket(
1886b8ecfcfeSchristos 		ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1887b8ecfcfeSchristos 	if (-1 == up->fdt) {
1888b8ecfcfeSchristos 		if (syslogok(pp, up))
1889b8ecfcfeSchristos 			msyslog(LOG_ERR,
1890b8ecfcfeSchristos 				"%s: cannot create GPSD socket: %m",
18915d681e99Schristos 				up->logname);
1892b8ecfcfeSchristos 		goto no_socket;
1893b8ecfcfeSchristos 	}
1894b8ecfcfeSchristos 
18955d681e99Schristos 	/* Make sure the socket is non-blocking. Connect/reconnect and
18965d681e99Schristos 	 * IO happen in an event-driven environment, and synchronous
18975d681e99Schristos 	 * operations wreak havoc on that.
18985d681e99Schristos 	 */
1899b8ecfcfeSchristos 	rc = fcntl(up->fdt, F_SETFL, O_NONBLOCK, 1);
1900b8ecfcfeSchristos 	if (-1 == rc) {
1901b8ecfcfeSchristos 		if (syslogok(pp, up))
1902b8ecfcfeSchristos 			msyslog(LOG_ERR,
1903b8ecfcfeSchristos 				"%s: cannot set GPSD socket to non-blocking: %m",
19045d681e99Schristos 				up->logname);
1905b8ecfcfeSchristos 		goto no_socket;
1906b8ecfcfeSchristos 	}
19075d681e99Schristos 	/* Disable nagling. The way both GPSD and NTPD handle the
19085d681e99Schristos 	 * protocol makes it record-oriented, and in most cases
19095d681e99Schristos 	 * complete records (JSON serialised objects) will be sent in
19105d681e99Schristos 	 * one sweep. Nagling gives not much advantage but adds another
19115d681e99Schristos 	 * delay, which can worsen the situation for some packets.
19125d681e99Schristos 	 */
1913b8ecfcfeSchristos 	ov = 1;
1914b8ecfcfeSchristos 	rc = setsockopt(up->fdt, IPPROTO_TCP, TCP_NODELAY,
19154eea345dSchristos 			(void *)&ov, sizeof(ov));
1916b8ecfcfeSchristos 	if (-1 == rc) {
1917b8ecfcfeSchristos 		if (syslogok(pp, up))
1918b8ecfcfeSchristos 			msyslog(LOG_INFO,
1919b8ecfcfeSchristos 				"%s: cannot disable TCP nagle: %m",
19205d681e99Schristos 				up->logname);
1921b8ecfcfeSchristos 	}
1922b8ecfcfeSchristos 
19235d681e99Schristos 	/* Start a non-blocking connect. There might be a synchronous
19245d681e99Schristos 	 * connection result we have to handle.
19255d681e99Schristos 	 */
1926b8ecfcfeSchristos 	rc = connect(up->fdt, ai->ai_addr, ai->ai_addrlen);
19275d681e99Schristos 	if (-1 == rc) {
19285d681e99Schristos 		if (errno == EINPROGRESS) {
19295d681e99Schristos 			DPRINTF(1, ("%s: async connect pending, fd=%d\n",
19305d681e99Schristos 				    up->logname, up->fdt));
19315d681e99Schristos 			return;
19325d681e99Schristos 		}
19335d681e99Schristos 
1934b8ecfcfeSchristos 		if (syslogok(pp, up))
1935b8ecfcfeSchristos 			msyslog(LOG_ERR,
1936b8ecfcfeSchristos 				"%s: cannot connect GPSD socket: %m",
19375d681e99Schristos 				up->logname);
19385d681e99Schristos 		goto no_socket;
19395d681e99Schristos 	}
19405d681e99Schristos 
19415d681e99Schristos 	/* We had a successful synchronous connect, so we add the
19425d681e99Schristos 	 * refclock processing ASAP. We still have to wait for the
19435d681e99Schristos 	 * version string and apply the watch command later on, but we
19445d681e99Schristos 	 * might as well get the show on the road now.
19455d681e99Schristos 	 */
19465d681e99Schristos 	DPRINTF(1, ("%s: new socket connection, fd=%d\n",
19475d681e99Schristos 		    up->logname, up->fdt));
19485d681e99Schristos 
19495d681e99Schristos 	pp->io.fd = up->fdt;
19505d681e99Schristos 	up->fdt   = -1;
19515d681e99Schristos 	if (0 == io_addclock(&pp->io)) {
19525d681e99Schristos 		if (syslogok(pp, up))
19535d681e99Schristos 			msyslog(LOG_ERR,
19545d681e99Schristos 				"%s: failed to register with I/O engine",
19555d681e99Schristos 				up->logname);
1956b8ecfcfeSchristos 		goto no_socket;
1957b8ecfcfeSchristos 	}
1958b8ecfcfeSchristos 
1959b8ecfcfeSchristos 	return;
1960b8ecfcfeSchristos 
1961b8ecfcfeSchristos   no_socket:
19625d681e99Schristos 	if (-1 != pp->io.fd)
19635d681e99Schristos 		close(pp->io.fd);
1964b8ecfcfeSchristos 	if (-1 != up->fdt)
1965b8ecfcfeSchristos 		close(up->fdt);
19665d681e99Schristos 	pp->io.fd    = -1;
1967b8ecfcfeSchristos 	up->fdt      = -1;
1968b8ecfcfeSchristos 	up->tickover = up->tickpres;
1969b8ecfcfeSchristos 	up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH);
1970b8ecfcfeSchristos }
1971b8ecfcfeSchristos 
1972b8ecfcfeSchristos /* ------------------------------------------------------------------ */
1973b8ecfcfeSchristos 
1974b8ecfcfeSchristos static void
1975b8ecfcfeSchristos gpsd_test_socket(
1976b8ecfcfeSchristos 	peerT * const peer)
1977b8ecfcfeSchristos {
1978b8ecfcfeSchristos 	clockprocT * const pp = peer->procptr;
1979b8ecfcfeSchristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1980b8ecfcfeSchristos 
1981b8ecfcfeSchristos 	int       ec, rc;
1982b8ecfcfeSchristos 	socklen_t lc;
1983b8ecfcfeSchristos 
1984b8ecfcfeSchristos 	/* Check if the non-blocking connect was finished by testing the
1985b8ecfcfeSchristos 	 * socket for writeability. Use the 'poll()' API if available
1986b8ecfcfeSchristos 	 * and 'select()' otherwise.
1987b8ecfcfeSchristos 	 */
19885d681e99Schristos 	DPRINTF(2, ("%s: check connect, fd=%d\n",
19895d681e99Schristos 		    up->logname, up->fdt));
1990b8ecfcfeSchristos 
1991b8ecfcfeSchristos #if defined(HAVE_SYS_POLL_H)
1992b8ecfcfeSchristos 	{
1993b8ecfcfeSchristos 		struct pollfd pfd;
1994b8ecfcfeSchristos 
1995b8ecfcfeSchristos 		pfd.events = POLLOUT;
1996b8ecfcfeSchristos 		pfd.fd     = up->fdt;
1997b8ecfcfeSchristos 		rc = poll(&pfd, 1, 0);
1998b8ecfcfeSchristos 		if (1 != rc || !(pfd.revents & POLLOUT))
1999b8ecfcfeSchristos 			return;
2000b8ecfcfeSchristos 	}
2001b8ecfcfeSchristos #elif defined(HAVE_SYS_SELECT_H)
2002b8ecfcfeSchristos 	{
2003b8ecfcfeSchristos 		struct timeval tout;
2004b8ecfcfeSchristos 		fd_set         wset;
2005b8ecfcfeSchristos 
2006b8ecfcfeSchristos 		memset(&tout, 0, sizeof(tout));
2007b8ecfcfeSchristos 		FD_ZERO(&wset);
2008b8ecfcfeSchristos 		FD_SET(up->fdt, &wset);
2009b8ecfcfeSchristos 		rc = select(up->fdt+1, NULL, &wset, NULL, &tout);
2010b8ecfcfeSchristos 		if (0 == rc || !(FD_ISSET(up->fdt, &wset)))
2011b8ecfcfeSchristos 			return;
2012b8ecfcfeSchristos 	}
2013b8ecfcfeSchristos #else
2014b8ecfcfeSchristos # error Blooper! That should have been found earlier!
2015b8ecfcfeSchristos #endif
2016b8ecfcfeSchristos 
2017b8ecfcfeSchristos 	/* next timeout is a full one... */
2018b8ecfcfeSchristos 	up->tickover = TICKOVER_LOW;
2019b8ecfcfeSchristos 
2020b8ecfcfeSchristos 	/* check for socket error */
2021b8ecfcfeSchristos 	ec = 0;
2022b8ecfcfeSchristos 	lc = sizeof(ec);
20234eea345dSchristos 	rc = getsockopt(up->fdt, SOL_SOCKET, SO_ERROR, (void *)&ec, &lc);
2024b8ecfcfeSchristos 	if (-1 == rc || 0 != ec) {
20255d681e99Schristos 		const char *errtxt;
20265d681e99Schristos 		if (0 == ec)
20275d681e99Schristos 			ec = errno;
20285d681e99Schristos 		errtxt = strerror(ec);
2029b8ecfcfeSchristos 		if (syslogok(pp, up))
2030b8ecfcfeSchristos 			msyslog(LOG_ERR,
20315d681e99Schristos 				"%s: async connect to GPSD failed,"
20325d681e99Schristos 				" fd=%d, ec=%d(%s)",
20335d681e99Schristos 				up->logname, up->fdt, ec, errtxt);
20345d681e99Schristos 		else
20355d681e99Schristos 			DPRINTF(1, ("%s: async connect to GPSD failed,"
20365d681e99Schristos 				" fd=%d, ec=%d(%s)\n",
20375d681e99Schristos 				    up->logname, up->fdt, ec, errtxt));
2038b8ecfcfeSchristos 		goto no_socket;
20395d681e99Schristos 	} else {
20405d681e99Schristos 		DPRINTF(1, ("%s: async connect to GPSD succeeded, fd=%d\n",
20415d681e99Schristos 			    up->logname, up->fdt));
2042b8ecfcfeSchristos 	}
20435d681e99Schristos 
2044b8ecfcfeSchristos 	/* swap socket FDs, and make sure the clock was added */
2045b8ecfcfeSchristos 	pp->io.fd = up->fdt;
2046b8ecfcfeSchristos 	up->fdt   = -1;
2047b8ecfcfeSchristos 	if (0 == io_addclock(&pp->io)) {
2048b8ecfcfeSchristos 		if (syslogok(pp, up))
2049b8ecfcfeSchristos 			msyslog(LOG_ERR,
2050b8ecfcfeSchristos 				"%s: failed to register with I/O engine",
20515d681e99Schristos 				up->logname);
2052b8ecfcfeSchristos 		goto no_socket;
2053b8ecfcfeSchristos 	}
2054b8ecfcfeSchristos 	return;
2055b8ecfcfeSchristos 
2056b8ecfcfeSchristos   no_socket:
20575d681e99Schristos 	if (-1 != up->fdt) {
20585d681e99Schristos 		DPRINTF(1, ("%s: closing socket, fd=%d\n",
20595d681e99Schristos 			    up->logname, up->fdt));
2060b8ecfcfeSchristos 		close(up->fdt);
20615d681e99Schristos 	}
2062b8ecfcfeSchristos 	up->fdt      = -1;
2063b8ecfcfeSchristos 	up->tickover = up->tickpres;
2064b8ecfcfeSchristos 	up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH);
2065b8ecfcfeSchristos }
2066b8ecfcfeSchristos 
2067b8ecfcfeSchristos /* =====================================================================
2068b8ecfcfeSchristos  * helper stuff
2069b8ecfcfeSchristos  */
2070b8ecfcfeSchristos 
20715d681e99Schristos /* -------------------------------------------------------------------
20725d681e99Schristos  * store a properly clamped precision value
2073b8ecfcfeSchristos  */
20745d681e99Schristos static int16_t
20755d681e99Schristos clamped_precision(
20765d681e99Schristos 	int rawprec)
2077b8ecfcfeSchristos {
20785d681e99Schristos 	if (rawprec > 0)
20795d681e99Schristos 		rawprec = 0;
20805d681e99Schristos 	if (rawprec < -32)
20815d681e99Schristos 		rawprec = -32;
20825d681e99Schristos 	return (int16_t)rawprec;
2083b8ecfcfeSchristos }
2084b8ecfcfeSchristos 
2085b8ecfcfeSchristos /* -------------------------------------------------------------------
20865d681e99Schristos  * Convert a GPSD timestamp (ISO8601 Format) to an l_fp
2087b8ecfcfeSchristos  */
2088b8ecfcfeSchristos static BOOL
2089b8ecfcfeSchristos convert_ascii_time(
2090b8ecfcfeSchristos 	l_fp       * fp      ,
2091b8ecfcfeSchristos 	const char * gps_time)
2092b8ecfcfeSchristos {
2093b8ecfcfeSchristos 	char           *ep;
2094b8ecfcfeSchristos 	struct tm       gd;
2095b8ecfcfeSchristos 	struct timespec ts;
20965d681e99Schristos 	uint32_t        dw;
2097b8ecfcfeSchristos 
2098b8ecfcfeSchristos 	/* Use 'strptime' to take the brunt of the work, then parse
2099b8ecfcfeSchristos 	 * the fractional part manually, starting with a digit weight of
2100b8ecfcfeSchristos 	 * 10^8 nanoseconds.
2101b8ecfcfeSchristos 	 */
2102b8ecfcfeSchristos 	ts.tv_nsec = 0;
2103b8ecfcfeSchristos 	ep = strptime(gps_time, "%Y-%m-%dT%H:%M:%S", &gd);
21045d681e99Schristos 	if (NULL == ep)
21055d681e99Schristos 		return FALSE; /* could not parse the mandatory stuff! */
2106b8ecfcfeSchristos 	if (*ep == '.') {
21075d681e99Schristos 		dw = 100000000u;
2108af12ab5eSchristos 		while (isdigit(*(u_char*)++ep)) {
2109af12ab5eSchristos 			ts.tv_nsec += (*(u_char*)ep - '0') * dw;
21105d681e99Schristos 			dw /= 10u;
2111b8ecfcfeSchristos 		}
2112b8ecfcfeSchristos 	}
2113b8ecfcfeSchristos 	if (ep[0] != 'Z' || ep[1] != '\0')
21145d681e99Schristos 		return FALSE; /* trailing garbage */
2115b8ecfcfeSchristos 
21165d681e99Schristos 	/* Now convert the whole thing into a 'l_fp'. We do not use
21175d681e99Schristos 	 * 'mkgmtime()' since its not standard and going through the
21185d681e99Schristos 	 * calendar routines is not much effort, either.
21195d681e99Schristos 	 */
2120b8ecfcfeSchristos 	ts.tv_sec = (ntpcal_tm_to_rd(&gd) - DAY_NTP_STARTS) * SECSPERDAY
2121b8ecfcfeSchristos 	          + ntpcal_tm_to_daysec(&gd);
2122b8ecfcfeSchristos 	*fp = tspec_intv_to_lfp(ts);
2123b8ecfcfeSchristos 
2124b8ecfcfeSchristos 	return TRUE;
2125b8ecfcfeSchristos }
2126b8ecfcfeSchristos 
2127b8ecfcfeSchristos /* -------------------------------------------------------------------
2128b8ecfcfeSchristos  * Save the last timecode string, making sure it's properly truncated
2129b8ecfcfeSchristos  * if necessary and NUL terminated in any case.
2130b8ecfcfeSchristos  */
2131b8ecfcfeSchristos static void
2132b8ecfcfeSchristos save_ltc(
2133b8ecfcfeSchristos 	clockprocT * const pp,
2134b8ecfcfeSchristos 	const char * const tc)
2135b8ecfcfeSchristos {
2136ccc794f0Schristos 	size_t len = 0;
2137b8ecfcfeSchristos 
2138ccc794f0Schristos 	if (tc) {
2139ccc794f0Schristos 		len = strlen(tc);
2140b8ecfcfeSchristos 		if (len >= sizeof(pp->a_lastcode))
2141b8ecfcfeSchristos 			len = sizeof(pp->a_lastcode) - 1;
2142b8ecfcfeSchristos 		memcpy(pp->a_lastcode, tc, len);
2143ccc794f0Schristos 	}
2144ccc794f0Schristos 	pp->lencode = (u_short)len;
2145b8ecfcfeSchristos 	pp->a_lastcode[len] = '\0';
2146b8ecfcfeSchristos }
2147b8ecfcfeSchristos 
21485d681e99Schristos /* -------------------------------------------------------------------
2149b8ecfcfeSchristos  * asprintf replacement... it's not available everywhere...
2150b8ecfcfeSchristos  */
2151b8ecfcfeSchristos static int
2152b8ecfcfeSchristos myasprintf(
2153b8ecfcfeSchristos 	char      ** spp,
2154b8ecfcfeSchristos 	char const * fmt,
2155b8ecfcfeSchristos 	...             )
2156b8ecfcfeSchristos {
2157b8ecfcfeSchristos 	size_t alen, plen;
2158b8ecfcfeSchristos 
2159b8ecfcfeSchristos 	alen = 32;
2160b8ecfcfeSchristos 	*spp = NULL;
2161b8ecfcfeSchristos 	do {
2162b8ecfcfeSchristos 		va_list va;
2163b8ecfcfeSchristos 
2164b8ecfcfeSchristos 		alen += alen;
2165b8ecfcfeSchristos 		free(*spp);
2166b8ecfcfeSchristos 		*spp = (char*)malloc(alen);
2167b8ecfcfeSchristos 		if (NULL == *spp)
2168b8ecfcfeSchristos 			return -1;
2169b8ecfcfeSchristos 
2170b8ecfcfeSchristos 		va_start(va, fmt);
2171b8ecfcfeSchristos 		plen = (size_t)vsnprintf(*spp, alen, fmt, va);
2172b8ecfcfeSchristos 		va_end(va);
2173b8ecfcfeSchristos 	} while (plen >= alen);
2174b8ecfcfeSchristos 
2175b8ecfcfeSchristos 	return (int)plen;
2176b8ecfcfeSchristos }
2177b8ecfcfeSchristos 
21785d681e99Schristos /* -------------------------------------------------------------------
21795d681e99Schristos  * dump a raw data buffer
21805d681e99Schristos  */
21815d681e99Schristos 
21825d681e99Schristos static char *
21835d681e99Schristos add_string(
21845d681e99Schristos 	char *dp,
21855d681e99Schristos 	char *ep,
21865d681e99Schristos 	const char *sp)
21875d681e99Schristos {
21885d681e99Schristos 	while (dp != ep && *sp)
21895d681e99Schristos 		*dp++ = *sp++;
21905d681e99Schristos 	return dp;
21915d681e99Schristos }
21925d681e99Schristos 
21935d681e99Schristos static void
21945d681e99Schristos log_data(
21955d681e99Schristos 	peerT      *peer,
2196*eabc0478Schristos 	int         level,
21975d681e99Schristos 	const char *what,
21985d681e99Schristos 	const char *buf ,
21995d681e99Schristos 	size_t      len )
22005d681e99Schristos {
22015d681e99Schristos 	/* we're running single threaded with regards to the clocks. */
22025d681e99Schristos 	static char s_lbuf[2048];
22035d681e99Schristos 
22045d681e99Schristos 	clockprocT * const pp = peer->procptr;
22055d681e99Schristos 	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
22065d681e99Schristos 
2207*eabc0478Schristos 	if (debug >= level) {
22085d681e99Schristos 		const char *sptr = buf;
22095d681e99Schristos 		const char *stop = buf + len;
22105d681e99Schristos 		char       *dptr = s_lbuf;
22115d681e99Schristos 		char       *dtop = s_lbuf + sizeof(s_lbuf) - 1; /* for NUL */
22125d681e99Schristos 
22135d681e99Schristos 		while (sptr != stop && dptr != dtop) {
2214af12ab5eSchristos 			u_char uch = (u_char)*sptr++;
2215af12ab5eSchristos 			if (uch == '\\') {
22165d681e99Schristos 				dptr = add_string(dptr, dtop, "\\\\");
2217af12ab5eSchristos 			} else if (isprint(uch)) {
2218af12ab5eSchristos 				*dptr++ = (char)uch;
22195d681e99Schristos 			} else {
22205d681e99Schristos 				char fbuf[6];
2221af12ab5eSchristos 				snprintf(fbuf, sizeof(fbuf), "\\%03o", uch);
22225d681e99Schristos 				dptr = add_string(dptr, dtop, fbuf);
22235d681e99Schristos 			}
22245d681e99Schristos 		}
22255d681e99Schristos 		*dptr = '\0';
22265d681e99Schristos 		mprintf("%s[%s]: '%s'\n", up->logname, what, s_lbuf);
22275d681e99Schristos 	}
22285d681e99Schristos }
22295d681e99Schristos 
2230*eabc0478Schristos 
2231b8ecfcfeSchristos #else
2232b8ecfcfeSchristos NONEMPTY_TRANSLATION_UNIT
2233b8ecfcfeSchristos #endif /* REFCLOCK && CLOCK_GPSDJSON */
2234