summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2011-06-21 14:50:04 -0400
committerEric S. Raymond <esr@thyrsus.com>2011-06-21 14:50:04 -0400
commita421d501c7f5e6250b7d12c693fd0ef52b61dcd5 (patch)
tree46a93612475f5ea0ce632edd9518449f8c4a299e
parent3e5dae56420c6e888363723b1b0a97cdb33f20cd (diff)
downloadgpsd-a421d501c7f5e6250b7d12c693fd0ef52b61dcd5.tar.gz
Path-rewrite for JSON packets works. All regression tests pass.
-rw-r--r--drivers.c30
-rw-r--r--gpsd.c20
-rw-r--r--gpsd.h-tail1
-rw-r--r--gpsd.xml14
-rw-r--r--libgpsd_core.c27
5 files changed, 83 insertions, 9 deletions
diff --git a/drivers.c b/drivers.c
index da467f78..a9596245 100644
--- a/drivers.c
+++ b/drivers.c
@@ -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;
}
diff --git a/gpsd.c b/gpsd.c
index 730008a9..37679ed2 100644
--- a/gpsd.c
+++ b/gpsd.c
@@ -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;
/*
diff --git a/gpsd.xml b/gpsd.xml
index 31d5daa8..ce1573c4 100644
--- a/gpsd.xml
+++ b/gpsd.xml
@@ -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++)