libgps_sock.c 16 KB

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