libgps_sock.c 17 KB

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