diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2011-06-21 14:50:04 -0400 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2011-06-21 14:50:04 -0400 |
commit | a421d501c7f5e6250b7d12c693fd0ef52b61dcd5 (patch) | |
tree | 46a93612475f5ea0ce632edd9518449f8c4a299e | |
parent | 3e5dae56420c6e888363723b1b0a97cdb33f20cd (diff) | |
download | gpsd-a421d501c7f5e6250b7d12c693fd0ef52b61dcd5.tar.gz |
Path-rewrite for JSON packets works. All regression tests pass.
-rw-r--r-- | drivers.c | 30 | ||||
-rw-r--r-- | gpsd.c | 20 | ||||
-rw-r--r-- | gpsd.h-tail | 1 | ||||
-rw-r--r-- | gpsd.xml | 14 | ||||
-rw-r--r-- | libgpsd_core.c | 27 |
5 files changed, 83 insertions, 9 deletions
@@ -46,11 +46,6 @@ gps_mask_t generic_parse_input(struct gps_device_t *session) session->context->century = year - (year % 100); } return 0; -#ifdef PASSTHROUGH_ENABLE - } else if (session->packet.type == JSON_PACKET) { - gpsd_report(LOG_IO, "<= GPS: %s\n", (char *)session->packet.outbuffer); - return PASSTHROUGH_IS; -#endif /* PASSTHROUGH_ENABLE */ #ifdef NMEA_ENABLE } else if (session->packet.type == NMEA_PACKET) { gps_mask_t st = 0; @@ -1203,6 +1198,31 @@ static const struct gps_type_t aivdm = { static gps_mask_t json_pass_packet(struct gps_device_t *session UNUSED) { + /* + * Hack the packet to reflect its origin. This code is supposed + * to insert the path naming the remote gpsd instance into the + * baginning of the path attribute, followed by a # to separate it + * from the device. + */ +#define PATHPREFIX "\"device\":\"" +#define ORIGINAL session->packet.outbuffer + char *deviceloc=strstr((char *)ORIGINAL, PATHPREFIX); + gpsd_report(LOG_IO, "<= GPS: %s\n", (char *)ORIGINAL); + if (deviceloc != NULL) { + char copy[sizeof(ORIGINAL)]; + (void)strlcpy(copy, (char *)ORIGINAL, sizeof(copy)); + deviceloc += strlen(PATHPREFIX); + (void)strlcpy(deviceloc, + session->gpsdata.dev.path, + sizeof(session->gpsdata.dev.path)); + (void)strlcat((char *)ORIGINAL, "#", sizeof(ORIGINAL)); + (void)strlcat((char *)ORIGINAL, + copy + (deviceloc-(char *)ORIGINAL), + sizeof(ORIGINAL)); + } + gpsd_report (LOG_PROG, "JSON, passing through %s\n", ORIGINAL); +#undef ORIGINAL +#undef PATHPREFIX return PASSTHROUGH_IS; } @@ -1012,6 +1012,7 @@ static void handle_request(struct subscriber_t *sub, json_devicelist_dump(reply, replylen); } else if (strncmp(buf, "WATCH", 5) == 0 && (buf[5] == ';' || buf[5] == '=')) { + const char *start = buf; buf += 5; if (*buf == ';') { ++buf; @@ -1033,8 +1034,13 @@ static void handle_request(struct subscriber_t *sub, if (sub->policy.devpath[0] == '\0') { /* awaken all devices */ for (devp = devices; devp < devices + MAXDEVICES; devp++) - if (allocated_device(devp)) + if (allocated_device(devp)) { (void)awaken(devp); + if (devp->sourcetype == source_gpsd) { + (void)gpsd_write(devp, "?", 1); + (void)gpsd_write(devp, start, (size_t)(end-start)); + } + } } else { devp = find_device(sub->policy.devpath); if (devp == NULL) { @@ -1043,7 +1049,12 @@ static void handle_request(struct subscriber_t *sub, sub->policy.devpath); gpsd_report(LOG_ERROR, "response: %s\n", reply); goto bailout; - } else if (!awaken(devp)) { + } else if (awaken(devp)) { + if (devp->sourcetype == source_gpsd) { + (void)gpsd_write(devp, "?", 1); + (void)gpsd_write(devp, start, (size_t)(end-start)); + } + } else { (void)snprintf(reply, replylen, "{\"class\":\"ERROR\",\"message\":\"Can't assign %s\"}\r\n", sub->policy.devpath); @@ -1568,9 +1579,12 @@ static void consume_packets(struct gps_device_t *device) #ifdef PASSTHROUGH_ENABLE /* this is for passing through JSON packets */ if ((changed & PASSTHROUGH_IS) != 0) { + (void)strlcat((char *)device->packet.outbuffer, + "\r\n", + sizeof(device->packet.outbuffer)); (void)throttled_write(sub, (char *)device->packet.outbuffer, - device->packet.outbuflen); + device->packet.outbuflen+2); continue; } #endif /* PASSTHROUGH_ENABLE */ diff --git a/gpsd.h-tail b/gpsd.h-tail index 22de2d5b..89b5c4ff 100644 --- a/gpsd.h-tail +++ b/gpsd.h-tail @@ -322,6 +322,7 @@ typedef enum {source_unknown, source_pty, /* PTY: we don't require exclusive access */ source_tcp, /* TCP/IP stream: case detected but not used */ source_udp, /* UDP stream: case detected but not used */ + source_gpsd, /* Remote gpsd instance over TCP/IP */ } sourcetype_t; /* @@ -282,10 +282,22 @@ colon, and an optional colon-separated port number (defaulting to 2101). The daemon will handshake with the DGPSIP server and read RTCM2 correction data from it. Corrections from the server will be set to each attached GPS with the capability -to accept them.Example: +to accept them. Example: <filename>dgpsip://dgps.wsrcc.com:2101</filename>.</para> </listitem> </varlistentry> +<varlistentry> +<term>Remote gpsd feed</term> +<listitem> +<para>A URI with the prefix "gpsd://", followed by a hostname and +optionally a colony and a port number (if the port is absent the +default <application>gpsd</application> port will be used). The daemon +will open a socket to the indicated address and port and emulate a +<application>gpsd</application> client, collecting JSON reports from +the remote <application>gpsd</application> instance that will be +passed to local clients.</para> +</listitem> +</varlistentry> </variablelist> <para>(The "ais:://" source type supported in some older versions of diff --git a/libgpsd_core.c b/libgpsd_core.c index 26535214..8f1a19a1 100644 --- a/libgpsd_core.c +++ b/libgpsd_core.c @@ -262,6 +262,32 @@ int gpsd_open(struct gps_device_t *session) return session->gpsdata.gps_fd; } #endif /* NETFEED_ENABLE */ +#ifdef PASSTHROUGH_ENABLE + else if (strncmp(session->gpsdata.dev.path, "gpsd://", 7) == 0) { + /*@-branchstate -nullpass@*/ + char server[GPS_PATH_MAX], *port; + socket_t dsock; + (void)strlcpy(server, session->gpsdata.dev.path + 7, sizeof(server)); + session->gpsdata.gps_fd = -1; + if ((port = strchr(server, ':')) == NULL) { + port = DEFAULT_GPSD_PORT; + } else + *port++ = '\0'; + gpsd_report(LOG_INF, "opening remote gpsd feed at %s, port %s.\n", server, + port); + if ((dsock = netlib_connectsock(AF_UNSPEC, server, port, "tcp")) < 0) { + gpsd_report(LOG_ERROR, "remote gpsd device open error %s.\n", + netlib_errstr(dsock)); + return -1; + } else + gpsd_report(LOG_SPIN, "remote gpsd feed opened on fd %d\n", dsock); + /*@+branchstate +nullpass@*/ + /* watch to remote is issued when WATCH is */ + session->gpsdata.gps_fd = dsock; + session->sourcetype = source_gpsd; + return session->gpsdata.gps_fd; + } +#endif /* PASSTHROUGH_ENABLE */ /* fall through to plain serial open */ return gpsd_serial_open(session); @@ -860,6 +886,7 @@ gps_mask_t gpsd_poll(struct gps_device_t *session) session->gpsdata.dev.path, session->packet.type); if (session->packet.type == COMMENT_PACKET) { gpsd_report (LOG_PROG, "comment, sync lock deferred\n"); + /* FALL THROUGH */ } else if (session->packet.type > COMMENT_PACKET) { first_sync = (session->device_type == NULL); for (dp = gpsd_drivers; *dp; dp++) |