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