2 * refclock_gpsdjson.c - clock driver as GPSD JSON client
3 * Juergen Perlinger (perlinger@ntp.org)
4 * Feb 11, 2014 for the NTP project.
5 * The contents of 'html/copyright.html' apply.
7 * Heavily inspired by refclock_nmea.c
9 * Note: This will currently NOT work with Windows due to some
12 * - There is no GPSD for Windows. (There is an unofficial port to
13 * cygwin, but Windows is not officially supported.)
15 * - To work properly, this driver needs PPS and TPV sentences from
16 * GPSD. I don't see how the cygwin port should deal with that.
18 * - The device name matching must be done in a different way for
19 * Windows. (Can be done with COMxx matching, as done for NMEA.)
21 * Apart from those minor hickups, once GPSD has been fully ported to
22 * Windows, there's no reason why this should not work there ;-)
29 #include "ntp_types.h"
31 #if defined(REFCLOCK) && defined(CLOCK_GPSDJSON) && !defined(SYS_WINNT)
33 /* =====================================================================
34 * get the little JSMN library directly into our guts
36 #include "../libjsmn/jsmn.c"
38 /* =====================================================================
39 * header stuff we need
48 #include <sys/types.h>
49 #include <sys/socket.h>
51 #include <netinet/tcp.h>
53 #if defined(HAVE_SYS_POLL_H)
54 # include <sys/poll.h>
55 #elif defined(HAVE_SYS_SELECT_H)
56 # include <sys/select.h>
58 # error need poll() or select()
63 #include "ntp_unixtime.h"
64 #include "ntp_refclock.h"
65 #include "ntp_stdlib.h"
66 #include "ntp_calendar.h"
67 #include "timespecops.h"
69 #define PRECISION (-9) /* precision assumed (about 2 ms) */
70 #define PPS_PRECISION (-20) /* precision assumed (about 1 us) */
71 #define REFID "GPSD" /* reference id */
72 #define DESCRIPTION "GPSD JSON client clock" /* who we are */
74 #define MAX_PDU_LEN 1600
75 #define TICKOVER_LOW 10
76 #define TICKOVER_HIGH 120
77 #define LOGTHROTTLE 3600
79 #define PPS_MAXCOUNT 30
93 /* some local typedefs : The NTPD formatting style cries for short type
94 * names, and we provide them locally. Note:the suffix '_t' is reserved
95 * for the standard; I use a capital T instead.
97 typedef struct peer peerT;
98 typedef struct refclockproc clockprocT;
99 typedef struct addrinfo addrinfoT;
101 /* =====================================================================
102 * We use the same device name scheme as does the NMEA driver; since
103 * GPSD supports the same links, we can select devices by a fixed name.
105 static const char * s_dev_stem = "/dev/gps";
107 /* =====================================================================
108 * forward declarations for transfer vector and the vector itself
111 static void gpsd_init (void);
112 static int gpsd_start (int, peerT *);
113 static void gpsd_shutdown (int, peerT *);
114 static void gpsd_receive (struct recvbuf *);
115 static void gpsd_poll (int, peerT *);
116 static void gpsd_control (int, const struct refclockstat *,
117 struct refclockstat *, peerT *);
118 static void gpsd_timer (int, peerT *);
119 static void gpsd_clockstats (int, peerT *);
121 static int myasprintf(char**, char const*, ...);
123 struct refclock refclock_gpsdjson = {
124 gpsd_start, /* start up driver */
125 gpsd_shutdown, /* shut down driver */
126 gpsd_poll, /* transmit poll message */
127 gpsd_control, /* fudge control */
128 gpsd_init, /* initialize driver */
129 noentry, /* buginfo */
130 gpsd_timer /* called once per second */
133 /* =====================================================================
134 * our local clock unit and data
136 typedef struct gpsd_unit {
138 /* current line protocol version */
139 uint16_t proto_major;
140 uint16_t proto_minor;
142 /* PPS time stamps */
143 l_fp pps_local; /* when we received the PPS message */
144 l_fp pps_stamp; /* related reference time */
145 l_fp pps_recvt; /* when GPSD detected the pulse */
147 /* TPV (GPS data) time stamps */
148 l_fp tpv_local; /* when we received the TPV message */
149 l_fp tpv_stamp; /* effective GPS time stamp */
150 l_fp tpv_recvt; /* when GPSD got the fix */
152 /* fudge values for correction, mirrored as 'l_fp' */
156 /* Flags to indicate available data */
157 int fl_tpv : 1; /* valid TPV seen (have time) */
158 int fl_pps : 1; /* valid pulse seen */
159 int fl_vers : 1; /* have protocol version */
160 int fl_watch : 1; /* watch reply seen */
161 int fl_nsec : 1; /* have nanosec PPS info */
163 /* admin stuff for sockets and device selection */
164 int fdt; /* current connecting socket */
165 addrinfoT * addr; /* next address to try */
166 u_int tickover; /* timeout countdown */
167 u_int tickpres; /* timeout preset */
168 u_int ppscount; /* PPS mode up/down count */
169 char * device; /* device name of unit */
171 /* tallies for the various events */
172 u_int tc_good; /* good samples received */
173 u_int tc_btime; /* bad time stamps */
174 u_int tc_bdate; /* bad date strings */
175 u_int tc_breply; /* bad replies */
176 u_int tc_recv; /* received known records */
178 /* log bloat throttle */
179 u_int logthrottle;/* seconds to next log slot */
181 /* record assemby buffer and saved length */
183 char buffer[MAX_PDU_LEN];
186 /* =====================================================================
187 * static local helpers forward decls
189 static void gpsd_init_socket(peerT * const peer);
190 static void gpsd_test_socket(peerT * const peer);
191 static void gpsd_stop_socket(peerT * const peer);
193 static void gpsd_parse(peerT * const peer,
194 const l_fp * const rtime);
195 static BOOL convert_ascii_time(l_fp * fp, const char * gps_time);
196 static void save_ltc(clockprocT * const pp, const char * const tc);
197 static int syslogok(clockprocT * const pp, gpsd_unitT * const up);
199 /* =====================================================================
200 * local / static stuff
203 /* The logon string is actually the ?WATCH command of GPSD, using JSON
204 * data and selecting the GPS device name we created from our unit
205 * number. [Note: This is a format string!]
208 "?WATCH={\"enable\":true,\"json\":true,\"device\":\"%s\"};\r\n"
210 /* We keep a static list of network addresses for 'localhost:gpsd', and
211 * we try to connect to them in round-robin fashion.
213 static addrinfoT * s_gpsd_addr;
215 /* =====================================================================
220 clockprocT * const pp,
221 gpsd_unitT * const up)
223 int res = (0 != (pp->sloppyclockflag & CLK_FLAG3))
224 || (0 == up->logthrottle )
225 || (LOGTHROTTLE == up->logthrottle );
227 up->logthrottle = LOGTHROTTLE;
231 /* =====================================================================
232 * the clock functions
235 /* ---------------------------------------------------------------------
236 * Init: This currently just gets the socket address for the GPS daemon
243 memset(&hints, 0, sizeof(hints));
244 hints.ai_family = AF_UNSPEC;
245 hints.ai_protocol = IPPROTO_TCP;
246 hints.ai_socktype = SOCK_STREAM;
248 /* just take the first configured address of localhost... */
249 if (getaddrinfo("localhost", "gpsd", &hints, &s_gpsd_addr))
253 /* ---------------------------------------------------------------------
254 * Start: allocate a unit pointer and set up the runtime data
262 clockprocT * const pp = peer->procptr;
263 gpsd_unitT * const up = emalloc_zero(sizeof(*up));
267 /* initialize the unit structure */
269 up->addr = s_gpsd_addr;
270 up->tickpres = TICKOVER_LOW;
272 /* setup refclock processing */
274 pp->unitptr = (caddr_t)up;
276 pp->io.clock_recv = gpsd_receive;
277 pp->io.srcclock = peer;
279 pp->a_lastcode[0] = '\0';
281 pp->clockdesc = DESCRIPTION;
282 memcpy(&pp->refid, REFID, 4);
284 /* Initialize miscellaneous variables */
285 peer->precision = PRECISION;
287 /* Create the device name and check for a Character Device. It's
288 * assumed that GPSD was started with the same link, so the
289 * names match. (If this is not practicable, we will have to
290 * read the symlink, if any, so we can get the true device
293 if (-1 == myasprintf(&up->device, "%s%u", s_dev_stem, unit)) {
294 msyslog(LOG_ERR, "%s clock device name too long",
295 refnumtoa(&peer->srcadr));
298 if (-1 == stat(up->device, &sb) || !S_ISCHR(sb.st_mode)) {
299 msyslog(LOG_ERR, "%s: '%s' is not a character device",
300 refnumtoa(&peer->srcadr), up->device);
304 (LOG_NOTICE, "%s: startup, device is '%s'",
305 refnumtoa(&peer->srcadr), up->device));
309 /* On failure, remove all UNIT ressources and declare defeat. */
315 pp->unitptr = (caddr_t)NULL;
319 /* ------------------------------------------------------------------ */
326 clockprocT * const pp = peer->procptr;
327 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
335 pp->unitptr = (caddr_t)NULL;
337 io_closeclock(&pp->io);
340 (LOG_NOTICE, "%s: shutdown", refnumtoa(&peer->srcadr)));
343 /* ------------------------------------------------------------------ */
347 struct recvbuf * rbufp)
349 /* declare & init control structure ptrs */
350 peerT * const peer = rbufp->recv_peer;
351 clockprocT * const pp = peer->procptr;
352 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
354 const char *psrc, *esrc;
355 char *pdst, *edst, ch;
357 /* Since we're getting a raw stream data, we must assemble lines
358 * in our receive buffer. We can't use neither 'refclock_gtraw'
359 * not 'refclock_gtlin' here... We process chars until we reach
360 * an EoL (that is, line feed) but we truncate the message if it
361 * does not fit the buffer. GPSD might truncate messages, too,
362 * so dealing with truncated buffers is necessary anyway.
364 psrc = (const char*)rbufp->recv_buffer;
365 esrc = psrc + rbufp->recv_length;
367 pdst = up->buffer + up->buflen;
368 edst = pdst + sizeof(up->buffer) - 1; /* for trailing NUL */
370 while (psrc != esrc) {
373 /* trim trailing whitespace & terminate buffer */
374 while (pdst != up->buffer && pdst[-1] <= ' ')
377 /* process data and reset buffer */
378 gpsd_parse(peer, &rbufp->recv_time);
380 } else if (pdst != edst) {
381 /* add next char, ignoring leading whitespace */
382 if (ch > ' ' || pdst != up->buffer)
386 up->buflen = pdst - up->buffer;
387 up->tickover = TICKOVER_LOW;
390 /* ------------------------------------------------------------------ */
397 clockprocT * const pp = peer->procptr;
398 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
403 /* find the dominant error */
404 tc_max = max(up->tc_btime, up->tc_bdate);
405 tc_max = max(tc_max, up->tc_breply);
407 if (pp->coderecv != pp->codeproc) {
409 pp->lastref = pp->lastrec;
410 refclock_receive(peer);
412 /* not working properly, admit to it */
413 peer->flags &= ~FLAG_PPS;
414 peer->precision = PRECISION;
416 if (-1 == pp->io.fd) {
417 /* not connected to GPSD: clearly not working! */
418 refclock_report(peer, CEVNT_FAULT);
419 } else if (tc_max == up->tc_breply) {
420 refclock_report(peer, CEVNT_BADREPLY);
421 } else if (tc_max == up->tc_btime) {
422 refclock_report(peer, CEVNT_BADTIME);
423 } else if (tc_max == up->tc_bdate) {
424 refclock_report(peer, CEVNT_BADDATE);
426 refclock_report(peer, CEVNT_TIMEOUT);
430 if (pp->sloppyclockflag & CLK_FLAG4)
431 gpsd_clockstats(unit, peer);
433 /* clear tallies for next round */
434 up->tc_good = up->tc_btime = up->tc_bdate =
435 up->tc_breply = up->tc_recv = 0;
438 /* ------------------------------------------------------------------ */
443 const struct refclockstat * in_st,
444 struct refclockstat * out_st,
447 clockprocT * const pp = peer->procptr;
448 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
450 /* save preprocessed fudge times */
451 DTOLFP(pp->fudgetime1, &up->pps_fudge);
452 DTOLFP(pp->fudgetime2, &up->tpv_fudge);
455 /* ------------------------------------------------------------------ */
462 static const char query[] = "?VERSION;";
464 clockprocT * const pp = peer->procptr;
465 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
468 /* This is used for timeout handling. Nothing that needs
469 * sub-second precison happens here, so receive/connect/retry
470 * timeouts are simply handled by a count down, and then we
471 * decide what to do by the socket values.
473 * Note that the timer stays at zero here, unless some of the
474 * functions set it to another value.
480 switch (up->tickover) {
482 /* try to get a live signal
483 * If the device is not yet present, we will most likely
484 * get an error. We put out a new version request,
485 * because the reply will initiate a new watch request
488 if (-1 != pp->io.fd) {
489 if ( ! up->fl_watch) {
490 DPRINTF(2, ("GPSD_JSON(%d): timer livecheck: '%s'\n",
492 rc = write(pp->io.fd,
493 query, sizeof(query));
496 } else if (-1 != up->fdt) {
497 gpsd_test_socket(peer);
503 gpsd_stop_socket(peer);
504 else if (-1 != up->fdt)
505 gpsd_test_socket(peer);
506 else if (NULL != s_gpsd_addr)
507 gpsd_init_socket(peer);
511 if (-1 == pp->io.fd && -1 != up->fdt)
512 gpsd_test_socket(peer);
515 if (up->ppscount > PPS_HIWAT && !(peer->flags & FLAG_PPS))
516 peer->flags |= FLAG_PPS;
517 if (up->ppscount < PPS_LOWAT && (peer->flags & FLAG_PPS))
518 peer->flags &= ~FLAG_PPS;
521 /* =====================================================================
525 #define JSMN_MAXTOK 100
526 #define INVALID_TOKEN (-1)
528 typedef struct json_ctx {
531 jsmntok_t tok[JSMN_MAXTOK];
536 #ifdef HAVE_LONG_LONG
537 typedef long long json_int;
538 #define JSON_STRING_TO_INT strtoll
540 typedef long json_int;
541 #define JSON_STRING_TO_INT strtol
544 /* ------------------------------------------------------------------ */
548 const json_ctx * ctx,
552 len = ctx->tok[tid].size;
553 for (++tid; len; --len)
555 tid = json_token_skip(ctx, tid);
563 /* ------------------------------------------------------------------ */
567 const json_ctx * ctx,
573 if (tid >= ctx->ntok || ctx->tok[tid].type != JSMN_OBJECT)
574 return INVALID_TOKEN;
575 len = ctx->ntok - tid - 1;
576 if (len > ctx->tok[tid].size)
577 len = ctx->tok[tid].size;
578 for (tid += 1; len > 1; len-=2) {
579 if (ctx->tok[tid].type != JSMN_STRING)
580 continue; /* hmmm... that's an error, strictly speaking */
581 if (!strcmp(key, ctx->buf + ctx->tok[tid].start))
583 tid = json_token_skip(ctx, tid + 1);
585 return INVALID_TOKEN;
588 /* ------------------------------------------------------------------ */
590 #if 0 /* currently unused */
592 json_object_lookup_string(
593 const json_ctx * ctx,
598 val_ref = json_object_lookup(ctx, tid, key);
599 if (INVALID_TOKEN == val_ref ||
600 JSMN_STRING != ctx->tok[val_ref].type )
602 return ctx->buf + ctx->tok[val_ref].start;
611 json_object_lookup_string_default(
612 const json_ctx * ctx,
618 val_ref = json_object_lookup(ctx, tid, key);
619 if (INVALID_TOKEN == val_ref ||
620 JSMN_STRING != ctx->tok[val_ref].type )
622 return ctx->buf + ctx->tok[val_ref].start;
625 /* ------------------------------------------------------------------ */
628 json_object_lookup_int(
629 const json_ctx * ctx,
637 val_ref = json_object_lookup(ctx, tid, key);
638 if (INVALID_TOKEN == val_ref ||
639 JSMN_PRIMITIVE != ctx->tok[val_ref].type )
641 ret = JSON_STRING_TO_INT(
642 ctx->buf + ctx->tok[val_ref].start, &ep, 10);
653 json_object_lookup_int_default(
654 const json_ctx * ctx,
664 retv = json_object_lookup_int(ctx, tid, key);
671 /* ------------------------------------------------------------------ */
674 json_object_lookup_float(
675 const json_ctx * ctx,
683 val_ref = json_object_lookup(ctx, tid, key);
684 if (INVALID_TOKEN == val_ref ||
685 JSMN_PRIMITIVE != ctx->tok[val_ref].type )
687 ret = strtod(ctx->buf + ctx->tok[val_ref].start, &ep);
698 json_object_lookup_float_default(
699 const json_ctx * ctx,
709 retv = json_object_lookup_float(ctx, tid, key);
716 /* ------------------------------------------------------------------ */
727 rc = jsmn_parse(&jsm, buf, ctx->tok, JSMN_MAXTOK);
729 ctx->ntok = jsm.toknext;
731 /* Make all tokens NUL terminated by overwriting the
734 for (idx = 0; idx < jsm.toknext; ++idx)
735 if (ctx->tok[idx].end > ctx->tok[idx].start)
736 ctx->buf[ctx->tok[idx].end] = '\0';
738 if (JSMN_ERROR_PART != rc &&
739 JSMN_ERROR_NOMEM != rc &&
741 return FALSE; /* not parseable - bail out */
743 if (0 >= jsm.toknext || JSMN_OBJECT != ctx->tok[0].type)
744 return FALSE; /* not object or no data!?! */
750 /* =====================================================================
751 * static local helpers
754 /* ------------------------------------------------------------------ */
755 /* Process a WATCH record
757 * Currently this is only used to recognise that the device is present
758 * and that we're listed subscribers.
763 json_ctx * const jctx ,
764 const l_fp * const rtime)
766 clockprocT * const pp = peer->procptr;
767 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
772 /* ------------------------------------------------------------------ */
777 json_ctx * const jctx ,
778 const l_fp * const rtime)
780 clockprocT * const pp = peer->procptr;
781 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
785 const char *revision;
788 /* get protocol version number */
789 revision = json_object_lookup_string_default(
790 jctx, 0, "rev", "(unknown)");
791 release = json_object_lookup_string_default(
792 jctx, 0, "release", "(unknown)");
794 up->proto_major = (uint16_t)json_object_lookup_int(
795 jctx, 0, "proto_major");
796 up->proto_minor = (uint16_t)json_object_lookup_int(
797 jctx, 0, "proto_minor");
800 if (syslogok(pp, up))
802 "%s: GPSD revision=%s release=%s protocol=%u.%u",
803 refnumtoa(&peer->srcadr),
805 up->proto_major, up->proto_minor);
808 /* With the 3.9 GPSD protocol, '*_musec' vanished and was
809 * replace by '*_nsec'. Dispatch properly.
811 if ( up->proto_major > 3 ||
812 (up->proto_major == 3 && up->proto_minor >= 9))
817 /*TODO: validate protocol version! */
819 /* request watch for our GPS device
820 * Reuse the input buffer, which is no longer needed in the
821 * current cycle. Also assume that we can write the watch
822 * request in one sweep into the socket; since we do not do
823 * output otherwise, this should always work. (Unless the
824 * TCP/IP window size gets lower than the length of the
825 * request. We handle that when it happens.)
827 snprintf(up->buffer, sizeof(up->buffer),
828 s_logon, up->device);
831 if (len != write(pp->io.fd, buf, len)) {
832 /*Note: if the server fails to read our request, the
833 * resulting data timeout will take care of the
836 if (syslogok(pp, up))
838 "%s: failed to write watch request (%m)",
839 refnumtoa(&peer->srcadr));
843 /* ------------------------------------------------------------------ */
848 json_ctx * const jctx ,
849 const l_fp * const rtime)
851 clockprocT * const pp = peer->procptr;
852 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
854 const char * gps_time;
856 double ept, epp, epx, epy, epv;
859 gps_mode = (int)json_object_lookup_int_default(
862 gps_time = json_object_lookup_string_default(
863 jctx, 0, "time", NULL);
865 if (gps_mode < 1 || NULL == gps_time) {
866 /* receiver has no fix; tell about and avoid stale data */
873 /* save last time code to clock data */
874 save_ltc(pp, gps_time);
876 /* convert clock and set resulting ref time */
877 if (convert_ascii_time(&up->tpv_stamp, gps_time)) {
878 DPRINTF(2, ("GPSD_JSON(%d): process_tpv, stamp='%s', recvt='%s' mode=%u\n",
880 gmprettydate(&up->tpv_stamp),
881 gmprettydate(&up->tpv_recvt),
884 up->tpv_local = *rtime;
885 up->tpv_recvt = *rtime;/*TODO: hack until we get it remote from GPSD */
886 L_SUB(&up->tpv_recvt, &up->tpv_fudge);
893 /* Set the precision from the GPSD data
895 * Since EPT has some issues, we use EPT and a home-brewed error
896 * estimation base on a sphere derived from EPX/Y/V and the
897 * speed of light. Use the better one of those two.
899 ept = json_object_lookup_float_default(jctx, 0, "ept", 1.0);
900 epx = json_object_lookup_float_default(jctx, 0, "epx", 1000.0);
901 epy = json_object_lookup_float_default(jctx, 0, "epy", 1000.0);
903 /* 2d-fix: extend bounding rectangle to cuboid */
906 /* 3d-fix: get bounding cuboid */
907 epv = json_object_lookup_float_default(
908 jctx, 0, "epv", 1000.0);
911 /* get diameter of enclosing sphere of bounding cuboid as spatial
912 * error, then divide spatial error by speed of light to get
913 * another time error estimate. Add extra 100 meters as
914 * optimistic lower bound. Then use the better one of the two
917 epp = 2.0 * sqrt(epx*epx + epy*epy + epv*epv);
918 epp = (epp + 100.0) / 299792458.0;
920 ept = min(ept, epp );
921 ept = min(ept, 0.5 );
922 ept = max(ept, 1.0-9);
923 ept = frexp(ept, &xlog2);
925 peer->precision = xlog2;
928 /* ------------------------------------------------------------------ */
933 json_ctx * const jctx ,
934 const l_fp * const rtime)
936 clockprocT * const pp = peer->procptr;
937 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
942 ts.tv_sec = (time_t)json_object_lookup_int(
943 jctx, 0, "clock_sec");
945 ts.tv_nsec = json_object_lookup_int(
946 jctx, 0, "clock_nsec");
948 ts.tv_nsec = json_object_lookup_int(
949 jctx, 0, "clock_musec") * 1000;
954 up->pps_local = *rtime;
955 /* get fudged receive time */
956 up->pps_recvt = tspec_stamp_to_lfp(ts);
957 L_SUB(&up->pps_recvt, &up->pps_fudge);
959 /* map to next full second as reference time stamp */
960 up->pps_stamp = up->pps_recvt;
961 L_ADDUF(&up->pps_stamp, 0x80000000u);
962 up->pps_stamp.l_uf = 0;
964 pp->lastrec = up->pps_stamp;
966 DPRINTF(2, ("GPSD_JSON(%d): process_pps, stamp='%s', recvt='%s'\n",
968 gmprettydate(&up->pps_stamp),
969 gmprettydate(&up->pps_recvt)));
971 /* When we have a time pulse, clear the TPV flag: the
972 * PPS is only valid for the >NEXT< TPV value!
979 DPRINTF(2, ("GPSD_JSON(%d): process_pps FAILED, nsec=%d stamp='%s', recvt='%s'\n",
980 up->unit, up->fl_nsec,
981 gmprettydate(&up->pps_stamp),
982 gmprettydate(&up->pps_recvt)));
986 /* ------------------------------------------------------------------ */
991 const l_fp * const rtime)
993 clockprocT * const pp = peer->procptr;
994 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1000 DPRINTF(2, ("GPSD_JSON(%d): gpsd_parse: time %s '%s'\n",
1001 up->unit, ulfptoa(rtime, 6), up->buffer));
1003 /* See if we can grab anything potentially useful */
1004 if (!json_parse_record(&jctx, up->buffer))
1007 /* Now dispatch over the objects we know */
1008 clsid = json_object_lookup_string_default(
1009 &jctx, 0, "class", "-bad-repy-");
1012 if (!strcmp("VERSION", clsid))
1013 process_version(peer, &jctx, rtime);
1014 else if (!strcmp("TPV", clsid))
1015 process_tpv(peer, &jctx, rtime);
1016 else if (!strcmp("PPS", clsid))
1017 process_pps(peer, &jctx, rtime);
1018 else if (!strcmp("WATCH", clsid))
1019 process_watch(peer, &jctx, rtime);
1021 return; /* nothing we know about... */
1023 /* now aggregate TPV and PPS -- no PPS? just use TPV...*/
1025 /* TODO: also check remote receive time stamps */
1026 tmpfp = up->tpv_local;
1027 L_SUB(&tmpfp, &up->pps_local);
1029 if (up->fl_pps && 0 == tmpfp.l_ui) {
1030 refclock_process_offset(
1031 pp, up->tpv_stamp, up->pps_recvt, 0.0);
1032 if (up->ppscount < PPS_MAXCOUNT)
1035 refclock_process_offset(
1036 pp, up->tpv_stamp, up->tpv_recvt, 0.0);
1037 if (up->ppscount > 0)
1046 /* ------------------------------------------------------------------ */
1052 clockprocT * const pp = peer->procptr;
1053 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1055 if (-1 != pp->io.fd)
1056 io_closeclock(&pp->io);
1058 if (syslogok(pp, up))
1060 "%s: closing socket to GPSD",
1061 refnumtoa(&peer->srcadr));
1062 up->tickover = up->tickpres;
1063 up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH);
1070 /* ------------------------------------------------------------------ */
1076 clockprocT * const pp = peer->procptr;
1077 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1082 /* draw next address to try */
1083 if (NULL == up->addr)
1084 up->addr = s_gpsd_addr;
1086 up->addr = ai->ai_next;
1088 /* try to create a matching socket */
1090 ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1091 if (-1 == up->fdt) {
1092 if (syslogok(pp, up))
1094 "%s: cannot create GPSD socket: %m",
1095 refnumtoa(&peer->srcadr));
1099 /* make sure the socket is non-blocking */
1100 rc = fcntl(up->fdt, F_SETFL, O_NONBLOCK, 1);
1102 if (syslogok(pp, up))
1104 "%s: cannot set GPSD socket to non-blocking: %m",
1105 refnumtoa(&peer->srcadr));
1108 /* disable nagling */
1110 rc = setsockopt(up->fdt, IPPROTO_TCP, TCP_NODELAY,
1111 (char*)&ov, sizeof(ov));
1113 if (syslogok(pp, up))
1115 "%s: cannot disable TCP nagle: %m",
1116 refnumtoa(&peer->srcadr));
1119 /* start a non-blocking connect */
1120 rc = connect(up->fdt, ai->ai_addr, ai->ai_addrlen);
1121 if (-1 == rc && errno != EINPROGRESS) {
1122 if (syslogok(pp, up))
1124 "%s: cannot connect GPSD socket: %m",
1125 refnumtoa(&peer->srcadr));
1135 up->tickover = up->tickpres;
1136 up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH);
1139 /* ------------------------------------------------------------------ */
1145 clockprocT * const pp = peer->procptr;
1146 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1151 /* Check if the non-blocking connect was finished by testing the
1152 * socket for writeability. Use the 'poll()' API if available
1153 * and 'select()' otherwise.
1155 DPRINTF(2, ("GPSD_JSON(%d): check connect, fd=%d\n",
1156 up->unit, up->fdt));
1158 #if defined(HAVE_SYS_POLL_H)
1162 pfd.events = POLLOUT;
1164 rc = poll(&pfd, 1, 0);
1165 if (1 != rc || !(pfd.revents & POLLOUT))
1168 #elif defined(HAVE_SYS_SELECT_H)
1170 struct timeval tout;
1173 memset(&tout, 0, sizeof(tout));
1175 FD_SET(up->fdt, &wset);
1176 rc = select(up->fdt+1, NULL, &wset, NULL, &tout);
1177 if (0 == rc || !(FD_ISSET(up->fdt, &wset)))
1181 # error Blooper! That should have been found earlier!
1184 /* next timeout is a full one... */
1185 up->tickover = TICKOVER_LOW;
1187 /* check for socket error */
1190 rc = getsockopt(up->fdt, SOL_SOCKET, SO_ERROR, &ec, &lc);
1191 DPRINTF(1, ("GPSD_JSON(%d): connect finshed, fd=%d, ec=%d(%s)\n",
1192 up->unit, up->fdt, ec, strerror(ec)));
1193 if (-1 == rc || 0 != ec) {
1195 if (syslogok(pp, up))
1197 "%s: (async)cannot connect GPSD socket: %m",
1198 refnumtoa(&peer->srcadr));
1201 /* swap socket FDs, and make sure the clock was added */
1202 pp->io.fd = up->fdt;
1204 if (0 == io_addclock(&pp->io)) {
1205 if (syslogok(pp, up))
1207 "%s: failed to register with I/O engine",
1208 refnumtoa(&peer->srcadr));
1217 up->tickover = up->tickpres;
1218 up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH);
1221 /* =====================================================================
1226 * shm_clockstats - dump and reset counters
1234 clockprocT * const pp = peer->procptr;
1235 gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;
1240 /* if snprintf() returns a negative values on errors (some older
1241 * ones do) make sure we are NUL terminated. Using an unsigned
1242 * result does the trick.
1244 llen = snprintf(logbuf, sizeof(logbuf),
1245 "good=%-3u badtime=%-3u baddate=%-3u badreply=%-3u recv=%-3u",
1246 up->tc_good, up->tc_btime, up->tc_bdate,
1247 up->tc_breply, up->tc_recv);
1248 logbuf[min(llen, sizeof(logbuf)-1)] = '\0';
1249 record_clock_stats(&peer->srcadr, logbuf);
1252 /* -------------------------------------------------------------------
1253 * Convert a GPSD timestam (ISO8601 Format) to an l_fp
1258 const char * gps_time)
1265 /* Use 'strptime' to take the brunt of the work, then parse
1266 * the fractional part manually, starting with a digit weight of
1270 ep = strptime(gps_time, "%Y-%m-%dT%H:%M:%S", &gd);
1273 while (isdigit((unsigned char)*++ep)) {
1274 ts.tv_nsec += (*ep - '0') * dw;
1278 if (ep[0] != 'Z' || ep[1] != '\0')
1281 /* now convert the whole thing into a 'l_fp' */
1282 ts.tv_sec = (ntpcal_tm_to_rd(&gd) - DAY_NTP_STARTS) * SECSPERDAY
1283 + ntpcal_tm_to_daysec(&gd);
1284 *fp = tspec_intv_to_lfp(ts);
1289 /* -------------------------------------------------------------------
1290 * Save the last timecode string, making sure it's properly truncated
1291 * if necessary and NUL terminated in any case.
1295 clockprocT * const pp,
1296 const char * const tc)
1300 len = (tc) ? strlen(tc) : 0;
1301 if (len >= sizeof(pp->a_lastcode))
1302 len = sizeof(pp->a_lastcode) - 1;
1303 pp->lencode = (u_short)len;
1304 memcpy(pp->a_lastcode, tc, len);
1305 pp->a_lastcode[len] = '\0';
1309 * -------------------------------------------------------------------
1310 * asprintf replacement... it's not available everywhere...
1327 *spp = (char*)malloc(alen);
1332 plen = (size_t)vsnprintf(*spp, alen, fmt, va);
1334 } while (plen >= alen);
1340 NONEMPTY_TRANSLATION_UNIT
1341 #endif /* REFCLOCK && CLOCK_GPSDJSON */