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.

352 lines
8.5 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
3 years ago
3 years ago
3 years ago
  1. /*
  2. Copyright Jeroen Vreeken (jeroen@vreeken.net), 2016
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <dml/dml_client.h>
  15. #include <dml/dml_connection.h>
  16. #include <dml/dml_poll.h>
  17. #include <dml/dml_packet.h>
  18. #include <dml/dml.h>
  19. #include <dml/dml_id.h>
  20. #include <dml/dml_crypto.h>
  21. #include <dml/dml_stream.h>
  22. #include <dml_config.h>
  23. #include <dml_stream_client_simple.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #define DML_STREAM_CLIENT_SIMPLE_KEEPALIVE 120
  29. struct dml_stream_client_simple {
  30. bool header_written;
  31. struct dml_client *client;
  32. struct dml_connection *dc;
  33. bool found_req_id;
  34. uint8_t req_id[DML_ID_SIZE];
  35. bool verify;
  36. void *arg;
  37. int (*data_cb)(void *arg, void *data, size_t datasize);
  38. char *name;
  39. char *alias;
  40. char *mime;
  41. };
  42. static int keepalive_cb(void *arg)
  43. {
  44. struct dml_stream_client_simple *dss = arg;
  45. if (!dss->dc) {
  46. return 0;
  47. }
  48. if (dss->found_req_id) {
  49. fprintf(stderr, "No data for %d seconds, send keepalive connect\n", DML_STREAM_CLIENT_SIMPLE_KEEPALIVE);
  50. dml_packet_send_connect(dss->dc, dss->req_id, DML_PACKET_DATA);
  51. } else {
  52. //TODO What is the best way to trigger discovery?
  53. }
  54. dml_poll_timeout(dss,
  55. &(struct timespec){ DML_STREAM_CLIENT_SIMPLE_KEEPALIVE, 0});
  56. return 0;
  57. }
  58. static void rx_packet(struct dml_connection *dc, void *arg,
  59. uint16_t id, uint16_t len, uint8_t *data)
  60. {
  61. struct dml_stream_client_simple *dss = arg;
  62. // fprintf(stderr, "got id: %d\n", id);
  63. switch(id) {
  64. case DML_PACKET_ROUTE: {
  65. if (dss->found_req_id)
  66. break;
  67. uint8_t id[DML_ID_SIZE];
  68. uint8_t hops;
  69. dml_packet_parse_route(data, len, id, &hops);
  70. if (hops < 255) {
  71. dml_packet_send_req_description(dc, id);
  72. }
  73. }
  74. case DML_PACKET_DESCRIPTION: {
  75. if (!dss->found_req_id) {
  76. uint8_t desc_id[DML_ID_SIZE];
  77. uint8_t version;
  78. uint32_t bps;
  79. char *mime, *name, *alias, *description;
  80. dml_packet_parse_description(data, len, desc_id, &version,
  81. &bps, &mime, &name, &alias, &description);
  82. bool found = true;
  83. if (dss->name && strcmp(name, dss->name))
  84. found = false;
  85. if (dss->alias && strcmp(alias, dss->alias))
  86. found = false;
  87. if (dss->mime && strcmp(mime, dss->mime))
  88. found = false;
  89. if (found) {
  90. dss->found_req_id = true;
  91. memcpy(dss->req_id, desc_id, DML_ID_SIZE);
  92. }
  93. }
  94. if (dss->found_req_id) {
  95. if (!dml_stream_update_description(data, len, NULL))
  96. break;
  97. fprintf(stderr, "Request certificate\n");
  98. dml_packet_send_req_certificate(dc, dss->req_id);
  99. }
  100. break;
  101. }
  102. case DML_PACKET_CERTIFICATE: {
  103. uint8_t cid[DML_ID_SIZE];
  104. void *cert;
  105. size_t size;
  106. fprintf(stderr, "Parse certificate\n");
  107. if (dml_packet_parse_certificate(data, len, cid, &cert, &size)) {
  108. fprintf(stderr, "Failed to parse certificate\n");
  109. break;
  110. }
  111. fprintf(stderr, "verify %d\n", dss->verify);
  112. if (!dss->verify || !dml_crypto_cert_add_verify(cert, size, cid)) {
  113. fprintf(stderr, "Request header\n");
  114. dml_packet_send_req_header(dc, dss->req_id);
  115. }
  116. free(cert);
  117. break;
  118. }
  119. case DML_PACKET_HEADER: {
  120. uint8_t hid[DML_ID_SIZE];
  121. uint8_t sig[DML_SIG_SIZE];
  122. void *header;
  123. size_t header_size;
  124. struct dml_stream *ds;
  125. struct dml_crypto_key *dk;
  126. bool send_connect = false;
  127. if (dml_packet_parse_header(data, len, hid, sig, &header, &header_size))
  128. break;
  129. if ((ds = dml_stream_by_id(hid))) {
  130. if (!dss->verify) {
  131. send_connect = true;
  132. } else if ((dk = dml_stream_crypto_get(ds))) {
  133. bool verified = dml_crypto_verify(header, header_size, sig, dk);
  134. if (verified) {
  135. send_connect = true;
  136. } else {
  137. fprintf(stderr, "Failed to verify header signature (%zd bytes)\n", header_size);
  138. }
  139. }
  140. }
  141. if (send_connect) {
  142. dss->data_cb(dss->arg, header, header_size);
  143. dss->header_written = true;
  144. dml_stream_data_id_set(ds, DML_PACKET_DATA);
  145. dml_packet_send_connect(dc, dss->req_id, DML_PACKET_DATA);
  146. fprintf(stderr, "Send connect\n");
  147. }
  148. free(header);
  149. break;
  150. }
  151. default: {
  152. if (id < DML_PACKET_DATA)
  153. break;
  154. if (len < DML_SIG_SIZE + sizeof(uint64_t))
  155. break;
  156. uint64_t timestamp;
  157. size_t payload_len;
  158. void *payload_data;
  159. struct dml_crypto_key *dk;
  160. struct dml_stream *ds;
  161. ds = dml_stream_by_data_id(id);
  162. if (!ds) {
  163. fprintf(stderr, "Could not find dml stream\n");
  164. break;
  165. }
  166. bool parsed = false;
  167. if (dss->verify) {
  168. dk = dml_stream_crypto_get(ds);
  169. if (dml_packet_parse_data(data, len,
  170. &payload_data, &payload_len, &timestamp, dk)) {
  171. fprintf(stderr, "Decoding failed\n");
  172. } else {
  173. parsed = true;
  174. }
  175. } else {
  176. if (dml_packet_parse_data_unverified(data, len,
  177. &payload_data, &payload_len, &timestamp)) {
  178. } else {
  179. parsed = true;
  180. }
  181. }
  182. if (parsed) {
  183. if (timestamp <= dml_stream_timestamp_get(ds)) {
  184. fprintf(stderr, "Timestamp mismatch %"PRIx64" <= %"PRIx64"\n",
  185. timestamp, dml_stream_timestamp_get(ds));
  186. } else {
  187. dml_stream_timestamp_set(ds, timestamp);
  188. // fprintf(stderr, "Received %zd ok\n", payload_len);
  189. dss->data_cb(dss->arg, payload_data, payload_len);
  190. dml_poll_timeout(dss,
  191. &(struct timespec){ DML_STREAM_CLIENT_SIMPLE_KEEPALIVE, 0});
  192. }
  193. }
  194. break;
  195. }
  196. }
  197. return;
  198. }
  199. static int client_reconnect(void *arg)
  200. {
  201. struct dml_stream_client_simple *dss = arg;
  202. if (dml_client_connect(dss->client)) {
  203. printf("Reconnect to DML server failed\n");
  204. dml_poll_timeout(dss, &(struct timespec){ 2, 0 });
  205. } else {
  206. printf("Reconnect to DML server successfull\n");
  207. dml_poll_add(dss, NULL, NULL, keepalive_cb);
  208. }
  209. return 0;
  210. }
  211. static int client_connection_close(struct dml_connection *dc, void *arg)
  212. {
  213. struct dml_stream_client_simple *dss = arg;
  214. dml_poll_add(dss, NULL, NULL, client_reconnect);
  215. dml_poll_timeout(dss, &(struct timespec){ 1, 0 });
  216. if (dc)
  217. dml_connection_destroy(dc);
  218. dss->dc = NULL;
  219. return 0;
  220. }
  221. static void client_connect(struct dml_client *client, void *arg)
  222. {
  223. struct dml_stream_client_simple *dss = arg;
  224. struct dml_connection *dc;
  225. int fd;
  226. fd = dml_client_fd_get(client);
  227. dc = dml_connection_create(fd, arg, rx_packet, client_connection_close);
  228. if (dss->found_req_id) {
  229. dml_packet_send_hello(dc, DML_PACKET_HELLO_LEAF, "dml_stream_client " DML_VERSION);
  230. dml_packet_send_req_description(dc, dss->req_id);
  231. } else {
  232. dml_packet_send_hello(dc, DML_PACKET_HELLO_UPDATES, "dml_stream_client " DML_VERSION);
  233. }
  234. dss->dc = dc;
  235. }
  236. struct dml_stream_client_simple *dml_stream_client_simple_create(
  237. char *server, uint8_t req_id[DML_ID_SIZE],
  238. void *arg,
  239. int (*data_cb)(void *arg, void *, size_t),
  240. bool verify)
  241. {
  242. return dml_stream_client_simple_search_create(
  243. server, req_id, NULL, NULL, NULL, arg, data_cb, verify);
  244. }
  245. struct dml_stream_client_simple *dml_stream_client_simple_search_create(
  246. char *server, uint8_t req_id[DML_ID_SIZE], char *name, char *alias, char *mime,
  247. void *arg,
  248. int (*data_cb)(void *arg, void *, size_t),
  249. bool verify)
  250. {
  251. struct dml_stream_client_simple *dss;
  252. struct dml_client *client;
  253. dss = calloc(1, sizeof(struct dml_stream_client_simple));
  254. if (!dss)
  255. goto err_calloc;
  256. if (req_id) {
  257. memcpy(dss->req_id, req_id, DML_ID_SIZE);
  258. dss->found_req_id = true;
  259. } else {
  260. if (name)
  261. dss->name = strdup(name);
  262. if (alias)
  263. dss->alias = strdup(alias);
  264. if (mime)
  265. dss->mime = strdup(mime);
  266. }
  267. dss->data_cb = data_cb;
  268. dss->verify = verify;
  269. dss->arg = arg;
  270. client = dml_client_create(server, 0, client_connect, dss);
  271. if (!client)
  272. goto err_create;
  273. dss->client = client;
  274. if (dml_client_connect(client))
  275. goto err_connect;
  276. dml_poll_add(dss, NULL, NULL, keepalive_cb);
  277. return dss;
  278. err_connect:
  279. dml_client_destroy(client);
  280. err_create:
  281. free(dss);
  282. err_calloc:
  283. return NULL;
  284. }
  285. int dml_stream_client_simple_destroy(struct dml_stream_client_simple *dss)
  286. {
  287. dml_connection_destroy(dss->dc);
  288. free(dss);
  289. return 0;
  290. }