1 /* libgps_sock.c -- client interface library for the gpsd daemon
2  *
3  * This file is Copyright (c) 2010-2018 by the GPSD project
4  * SPDX-License-Identifier: BSD-2-clause
5  */
6 
7 #include "gpsd_config.h"  /* must be before all includes */
8 
9 #include <assert.h>
10 #include <ctype.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <locale.h>
14 #include <math.h>
15 #include <stdbool.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/select.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 #ifndef USE_QT
25 #ifdef HAVE_SYS_SOCKET_H
26 #include <sys/socket.h>
27 #endif /* HAVE_SYS_SOCKET_H */
28 #ifdef HAVE_WINSOCK2_H
29 #include <winsock2.h>
30 #endif /* HAVE_WINSOCK2_H */
31 #else
32 #include <QTcpSocket>
33 #endif /* USE_QT */
34 
35 #include "gps.h"
36 #include "gpsd.h"
37 #include "libgps.h"
38 #include "strfuncs.h"
39 #include "timespec.h"      /* for NS_IN_SEC */
40 #ifdef SOCKET_EXPORT_ENABLE
41 #include "gps_json.h"
42 
43 struct privdata_t
44 {
45     bool newstyle;
46     /* data buffered from the last read */
47     ssize_t waiting;
48     char buffer[GPS_JSON_RESPONSE_MAX * 2];
49 #ifdef LIBGPS_DEBUG
50     int waitcount;
51 #endif /* LIBGPS_DEBUG */
52 };
53 
54 #ifdef HAVE_WINSOCK2_H
55 static bool need_init = TRUE;
56 static bool need_finish = TRUE;
57 
windows_init(void)58 static bool windows_init(void)
59 /* Ensure socket networking is initialized for Windows. */
60 {
61     WSADATA wsadata;
62     /* request access to Windows Sockets API version 2.2 */
63     int res = WSAStartup(MAKEWORD(2, 2), &wsadata);
64     if (res != 0) {
65       libgps_debug_trace((DEBUG_CALLS, "WSAStartup returns error %d\n", res));
66     }
67     return (res == 0);
68 }
69 
windows_finish(void)70 static bool windows_finish(void)
71 /* Shutdown Windows Sockets. */
72 {
73     int res = WSACleanup();
74     if (res != 0) {
75         libgps_debug_trace((DEBUG_CALLS, "WSACleanup returns error %d\n", res));
76     }
77     return (res == 0);
78 }
79 #endif /* HAVE_WINSOCK2_H */
80 
gps_sock_open(const char * host,const char * port,struct gps_data_t * gpsdata)81 int gps_sock_open(const char *host, const char *port,
82 		  struct gps_data_t *gpsdata)
83 {
84     if (!host)
85 	host = "localhost";
86     if (!port)
87 	port = DEFAULT_GPSD_PORT;
88 
89     libgps_debug_trace((DEBUG_CALLS, "gps_sock_open(%s, %s)\n", host, port));
90 
91 #ifndef USE_QT
92 #ifdef HAVE_WINSOCK2_H
93 	if (need_init) {
94 	  need_init != windows_init();
95 	}
96 #endif
97 	if ((gpsdata->gps_fd =
98 	    netlib_connectsock(AF_UNSPEC, host, port, "tcp")) < 0) {
99 	    errno = gpsdata->gps_fd;
100 	    libgps_debug_trace((DEBUG_CALLS,
101                                "netlib_connectsock() returns error %d\n",
102                                errno));
103 	    return -1;
104         } else
105 	    libgps_debug_trace((DEBUG_CALLS,
106                 "netlib_connectsock() returns socket on fd %d\n",
107                 gpsdata->gps_fd));
108 #else /* HAVE_WINSOCK2_H */
109 	QTcpSocket *sock = new QTcpSocket();
110 	gpsdata->gps_fd = sock;
111 	sock->connectToHost(host, QString(port).toInt());
112 	if (!sock->waitForConnected())
113 	    qDebug() << "libgps::connect error: " << sock->errorString();
114 	else
115 	    qDebug() << "libgps::connected!";
116 #endif /* USE_QT */
117 
118     /* set up for line-buffered I/O over the daemon socket */
119     gpsdata->privdata = (void *)malloc(sizeof(struct privdata_t));
120     if (gpsdata->privdata == NULL)
121 	return -1;
122     PRIVATE(gpsdata)->newstyle = false;
123     PRIVATE(gpsdata)->waiting = 0;
124     PRIVATE(gpsdata)->buffer[0] = 0;
125 
126 #ifdef LIBGPS_DEBUG
127     PRIVATE(gpsdata)->waitcount = 0;
128 #endif /* LIBGPS_DEBUG */
129     return 0;
130 }
131 
gps_sock_waiting(const struct gps_data_t * gpsdata,int timeout)132 bool gps_sock_waiting(const struct gps_data_t *gpsdata, int timeout)
133 /* is there input waiting from the GPS? */
134 /* timeout is in uSec */
135 {
136 #ifndef USE_QT
137     libgps_debug_trace((DEBUG_CALLS, "gps_waiting(%d): %d\n",
138                        timeout, PRIVATE(gpsdata)->waitcount++));
139     if (PRIVATE(gpsdata)->waiting > 0)
140 	return true;
141 
142     /* all error conditions return "not waiting" -- crude but effective */
143     return nanowait(gpsdata->gps_fd, timeout * 1000);
144 #else
145     return ((QTcpSocket *) (gpsdata->gps_fd))->waitForReadyRead(timeout / 1000);
146 #endif
147 }
148 
gps_sock_close(struct gps_data_t * gpsdata)149 int gps_sock_close(struct gps_data_t *gpsdata)
150 /* close a gpsd connection */
151 {
152     free(PRIVATE(gpsdata));
153     gpsdata->privdata = NULL;
154 #ifndef USE_QT
155     int status;
156 #ifdef HAVE_WINSOCK2_H
157     status = closesocket(gpsdata->gps_fd);
158     if (need_finish) {
159       need_finish != windows_finish();
160     }
161 #else
162     status = close(gpsdata->gps_fd);
163 #endif /* HAVE_WINSOCK2_H */
164     gpsdata->gps_fd = -1;
165     return status;
166 #else
167     QTcpSocket *sock = (QTcpSocket *) gpsdata->gps_fd;
168     sock->disconnectFromHost();
169     delete sock;
170     gpsdata->gps_fd = NULL;
171     return 0;
172 #endif
173 }
174 
gps_sock_read(struct gps_data_t * gpsdata,char * message,int message_len)175 int gps_sock_read(struct gps_data_t *gpsdata, char *message, int message_len)
176 /* wait for and read data being streamed from the daemon */
177 {
178     char *eol;
179     ssize_t response_length;
180     int status = -1;
181 
182     errno = 0;
183     gpsdata->set &= ~PACKET_SET;
184 
185     /* scan to find end of message (\n), or end of buffer */
186     for (eol = PRIVATE(gpsdata)->buffer;
187 	 eol < (PRIVATE(gpsdata)->buffer + PRIVATE(gpsdata)->waiting);
188          eol++) {
189         if ('\n' == *eol)
190             break;
191     }
192 
193     if (*eol != '\n') {
194 	/* no full message found, try to fill buffer */
195 
196 #ifndef USE_QT
197 	/* read data: return -1 if no data waiting or buffered, 0 otherwise */
198 	status = (int)recv(gpsdata->gps_fd,
199                PRIVATE(gpsdata)->buffer + PRIVATE(gpsdata)->waiting,
200                sizeof(PRIVATE(gpsdata)->buffer) - PRIVATE(gpsdata)->waiting, 0);
201 #else
202 	status =
203 	    ((QTcpSocket *) (gpsdata->gps_fd))->read(PRIVATE(gpsdata)->buffer +
204                  PRIVATE(gpsdata)->waiting,
205                  sizeof(PRIVATE(gpsdata)->buffer) - PRIVATE(gpsdata)->waiting);
206 #endif
207 #ifdef HAVE_WINSOCK2_H
208 	int wserr = WSAGetLastError();
209 #endif /* HAVE_WINSOCK2_H */
210 
211 #ifdef USE_QT
212 	if (status < 0) {
213             /* All negative statuses are error for QT
214              *
215              * read: https://doc.qt.io/qt-5/qiodevice.html#read
216              *
217              * Reads at most maxSize bytes from the device into data,
218              * and returns the number of bytes read.
219              * If an error occurs, such as when attempting to read from
220              * a device opened in WriteOnly mode, this function returns -1.
221              *
222              * 0 is returned when no more data is available for reading.
223              * However, reading past the end of the stream is considered
224              * an error, so this function returns -1 in those cases
225              * (that is, reading on a closed socket or after a process
226              * has died).
227              */
228             return -1;
229 	}
230 
231 #else  /* not USE_QT */
232 	if (status <= 0) {
233             /* 0 or negative
234              *
235              * read:
236              *  https://pubs.opengroup.org/onlinepubs/007908775/xsh/read.html
237              *
238              * If nbyte is 0, read() will return 0 and have no other results.
239              * ...
240              * When attempting to read a file (other than a pipe or FIFO)
241              * that supports non-blocking reads and has no data currently
242              * available:
243              *    - If O_NONBLOCK is set,
244              *            read() will return a -1 and set errno to [EAGAIN].
245              *    - If O_NONBLOCK is clear,
246              *            read() will block the calling thread until some
247              *            data becomes available.
248              *    - The use of the O_NONBLOCK flag has no effect if there
249              *       is some data available.
250              * ...
251              * If a read() is interrupted by a signal before it reads any
252              * data, it will return -1 with errno set to [EINTR].
253              * If a read() is interrupted by a signal after it has
254              * successfully read some data, it will return the number of
255              * bytes read.
256              *
257              * recv:
258              *   https://pubs.opengroup.org/onlinepubs/007908775/xns/recv.html
259              *
260              * If no messages are available at the socket and O_NONBLOCK
261              * is not set on the socket's file descriptor, recv() blocks
262              * until a message arrives.
263              * If no messages are available at the socket and O_NONBLOCK
264              * is set on the socket's file descriptor, recv() fails and
265              * sets errno to [EAGAIN] or [EWOULDBLOCK].
266              * ...
267              * Upon successful completion, recv() returns the length of
268              * the message in bytes. If no messages are available to be
269              * received and the peer has performed an orderly shutdown,
270              * recv() returns 0. Otherwise, -1 is returned and errno is
271              * set to indicate the error.
272              *
273              * Summary:
274              * if nbytes 0 and read return 0 -> out of the free buffer
275              * space but still didn't get correct json -> report an error
276              * -> return -1
277              * if read return 0 but requested some bytes to read -> other
278              *side disconnected -> report an error -> return -1
279              * if read return -1 and errno is in [EAGAIN, EINTR, EWOULDBLOCK]
280              * -> not an error, we'll retry later -> return 0
281              * if read return -1 and errno is not in [EAGAIN, EINTR,
282              * EWOULDBLOCK] -> error -> return -1
283              *
284              */
285 
286             /*
287              * check for not error cases first: EAGAIN, EINTR, etc
288              */
289              if (status < 0) {
290 #ifdef HAVE_WINSOCK2_H
291                 if (wserr == WSAEINTR || wserr == WSAEWOULDBLOCK)
292                     return 0;
293 #else
294                 if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
295                     return 0;
296 #endif /* HAVE_WINSOCK2_H */
297              }
298 
299              /* disconnect or error */
300              return -1;
301 	}
302 #endif /* USE_QT */
303 
304 	/* if we just received data from the socket, it's in the buffer */
305 	PRIVATE(gpsdata)->waiting += status;
306 
307 	/* there's new buffered data waiting, check for full message */
308 	for (eol = PRIVATE(gpsdata)->buffer;
309 	     eol < (PRIVATE(gpsdata)->buffer + PRIVATE(gpsdata)->waiting);
310              eol++) {
311 	    if ('\n' == *eol)
312 		break;
313 	}
314 	if (*eol != '\n')
315             /* still no full message, give up for now */
316 	    return 0;
317     }
318 
319     /* eol now points to trailing \n in a full message */
320     *eol = '\0';
321     if (NULL != message) {
322         strlcpy(message, PRIVATE(gpsdata)->buffer, message_len);
323     }
324     (void)clock_gettime(CLOCK_REALTIME, &gpsdata->online);
325     /* unpack the JSON message */
326     status = gps_unpack(PRIVATE(gpsdata)->buffer, gpsdata);
327 
328     /* why the 1? */
329     response_length = eol - PRIVATE(gpsdata)->buffer + 1;
330 
331     /* calculate length of good data still in buffer */
332     PRIVATE(gpsdata)->waiting -= response_length;
333 
334     if (1 > PRIVATE(gpsdata)->waiting) {
335         /* no waiting data, or overflow, clear the buffer, just in case */
336         *PRIVATE(gpsdata)->buffer = '\0';
337         PRIVATE(gpsdata)->waiting = 0;
338     } else {
339 	memmove(PRIVATE(gpsdata)->buffer,
340 		PRIVATE(gpsdata)->buffer + response_length,
341 		PRIVATE(gpsdata)->waiting);
342     }
343     gpsdata->set |= PACKET_SET;
344 
345     return (status == 0) ? (int)response_length : status;
346 }
347 
gps_unpack(char * buf,struct gps_data_t * gpsdata)348 int gps_unpack(char *buf, struct gps_data_t *gpsdata)
349 /* unpack a gpsd response into a status structure, buf must be writeable.
350  * gps_unpack() currently returns 0 in all cases, but should it ever need to
351  * return an error status, it must be < 0.
352  */
353 {
354     libgps_debug_trace((DEBUG_CALLS, "gps_unpack(%s)\n", buf));
355 
356     /* detect and process a JSON response */
357     if (buf[0] == '{') {
358 	const char *jp = buf, **next = &jp;
359 	while (next != NULL && *next != NULL && next[0][0] != '\0') {
360 	    libgps_debug_trace((DEBUG_CALLS,
361                                "gps_unpack() segment parse '%s'\n",
362                                *next));
363 	    if (libgps_json_unpack(*next, gpsdata, next) == -1)
364 		break;
365 #ifdef LIBGPS_DEBUG
366 	    if (libgps_debuglevel >= 1)
367 		libgps_dump_state(gpsdata);
368 #endif /* LIBGPS_DEBUG */
369 
370 	}
371     }
372 
373 #ifndef USE_QT
374     libgps_debug_trace((DEBUG_CALLS,
375                         "final flags: (0x%04x) %s\n",
376                         gpsdata->set,gps_maskdump(gpsdata->set)));
377 #endif
378     return 0;
379 }
380 
gps_sock_data(const struct gps_data_t * gpsdata)381 const char *gps_sock_data(const struct gps_data_t *gpsdata)
382 /* return the contents of the client data buffer */
383 {
384     /* no length data, so pretty useless... */
385     return PRIVATE(gpsdata)->buffer;
386 }
387 
gps_sock_send(struct gps_data_t * gpsdata,const char * buf)388 int gps_sock_send(struct gps_data_t *gpsdata, const char *buf)
389 /* send a command to the gpsd instance */
390 {
391 #ifndef USE_QT
392 #ifdef HAVE_WINSOCK2_H
393     if (send(gpsdata->gps_fd, buf, strlen(buf), 0) == (ssize_t) strlen(buf))
394 #else
395     if (write(gpsdata->gps_fd, buf, strlen(buf)) == (ssize_t) strlen(buf))
396 #endif /* HAVE_WINSOCK2_H */
397 	return 0;
398     else
399 	return -1;
400 #else
401     QTcpSocket *sock = (QTcpSocket *) gpsdata->gps_fd;
402     sock->write(buf, strlen(buf));
403     if (sock->waitForBytesWritten())
404 	return 0;
405     else {
406 	qDebug() << "libgps::send error: " << sock->errorString();
407 	return -1;
408     }
409 #endif
410 }
411 
gps_sock_stream(struct gps_data_t * gpsdata,unsigned int flags,void * d)412 int gps_sock_stream(struct gps_data_t *gpsdata, unsigned int flags, void *d)
413 /* ask gpsd to stream reports at you, hiding the command details */
414 {
415     char buf[GPS_JSON_COMMAND_MAX];
416 
417     if ((flags & (WATCH_JSON | WATCH_NMEA | WATCH_RAW)) == 0) {
418 	flags |= WATCH_JSON;
419     }
420     if ((flags & WATCH_DISABLE) != 0) {
421 	(void)strlcpy(buf, "?WATCH={\"enable\":false,", sizeof(buf));
422 	if (flags & WATCH_JSON)
423 	    (void)strlcat(buf, "\"json\":false,", sizeof(buf));
424 	if (flags & WATCH_NMEA)
425 	    (void)strlcat(buf, "\"nmea\":false,", sizeof(buf));
426 	if (flags & WATCH_RAW)
427 	    (void)strlcat(buf, "\"raw\":1,", sizeof(buf));
428 	if (flags & WATCH_RARE)
429 	    (void)strlcat(buf, "\"raw\":0,", sizeof(buf));
430 	if (flags & WATCH_SCALED)
431 	    (void)strlcat(buf, "\"scaled\":false,", sizeof(buf));
432 	if (flags & WATCH_TIMING)
433 	    (void)strlcat(buf, "\"timing\":false,", sizeof(buf));
434 	if (flags & WATCH_SPLIT24)
435 	    (void)strlcat(buf, "\"split24\":false,", sizeof(buf));
436 	if (flags & WATCH_PPS)
437 	    (void)strlcat(buf, "\"pps\":false,", sizeof(buf));
438 	str_rstrip_char(buf, ',');
439 	(void)strlcat(buf, "};", sizeof(buf));
440 	libgps_debug_trace((DEBUG_CALLS,
441                            "gps_stream() disable command: %s\n", buf));
442 	return gps_send(gpsdata, buf);
443     } else {			/* if ((flags & WATCH_ENABLE) != 0) */
444 	(void)strlcpy(buf, "?WATCH={\"enable\":true,", sizeof(buf));
445 	if (flags & WATCH_JSON)
446 	    (void)strlcat(buf, "\"json\":true,", sizeof(buf));
447 	if (flags & WATCH_NMEA)
448 	    (void)strlcat(buf, "\"nmea\":true,", sizeof(buf));
449 	if (flags & WATCH_RARE)
450 	    (void)strlcat(buf, "\"raw\":1,", sizeof(buf));
451 	if (flags & WATCH_RAW)
452 	    (void)strlcat(buf, "\"raw\":2,", sizeof(buf));
453 	if (flags & WATCH_SCALED)
454 	    (void)strlcat(buf, "\"scaled\":true,", sizeof(buf));
455 	if (flags & WATCH_TIMING)
456 	    (void)strlcat(buf, "\"timing\":true,", sizeof(buf));
457 	if (flags & WATCH_SPLIT24)
458 	    (void)strlcat(buf, "\"split24\":true,", sizeof(buf));
459 	if (flags & WATCH_PPS)
460 	    (void)strlcat(buf, "\"pps\":true,", sizeof(buf));
461 	if (flags & WATCH_DEVICE)
462 	    str_appendf(buf, sizeof(buf), "\"device\":\"%s\",", (char *)d);
463 	str_rstrip_char(buf, ',');
464 	(void)strlcat(buf, "};", sizeof(buf));
465 	libgps_debug_trace((DEBUG_CALLS,
466                            "gps_stream() enable command: %s\n", buf));
467 	return gps_send(gpsdata, buf);
468     }
469 }
470 
gps_sock_mainloop(struct gps_data_t * gpsdata,int timeout,void (* hook)(struct gps_data_t * gpsdata))471 int gps_sock_mainloop(struct gps_data_t *gpsdata, int timeout,
472 			 void (*hook)(struct gps_data_t *gpsdata))
473 /* run a socket main loop with a specified handler */
474 {
475     for (;;) {
476 	if (!gps_waiting(gpsdata, timeout)) {
477 	    return -1;
478 	} else {
479 	    int status = gps_read(gpsdata, NULL, 0);
480 
481 	    if (status == -1)
482 		return -1;
483 	    if (status > 0)
484 		(*hook)(gpsdata);
485 	}
486     }
487     //return 0;
488 }
489 
490 #endif /* SOCKET_EXPORT_ENABLE */
491 
492 /* end */
493