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