You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

493 lines
15KB

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