piumsgd.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * Copyright (c) 2021 Clementine Computing LLC.
  3. *
  4. * This file is part of PopuFare.
  5. *
  6. * PopuFare is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * PopuFare is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
  18. *
  19. */
  20. /*
  21. * PIU interface server.
  22. * piumsgd is in charge of passing messages from the underlying system
  23. * to the passenger via a websocket connection.
  24. *
  25. * piumsgd also acts as the web server to serve the local passenger
  26. * interface HTML/CSS/JS files.
  27. */
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <errno.h>
  31. #include <getopt.h>
  32. #include <string.h>
  33. #include "mongoose.h"
  34. #define PIUMSGD_VERSION "0.1.0"
  35. #define PIUMSGD_DEFAULT_WEBDIR "/home/bus/config/html"
  36. #define PIUMSGD_DEFAULT_ADDR "0.0.0.0"
  37. #define PIUMSGD_DEFAULT_PORT 8001
  38. static struct option long_opt[] = {
  39. {"webdir", required_argument, 0, 0},
  40. {"host", required_argument, 0, 0},
  41. {"port", required_argument, 0, 0},
  42. {"help", no_argument, 0, 0},
  43. {"verbose", no_argument, 0, 0},
  44. {"version", no_argument, 0, 0},
  45. {0, 0, 0, 0}
  46. };
  47. int g_verbose = 0;
  48. //char s_web_directory[] = "/home/bus/config/html";
  49. char *s_web_directory = NULL;
  50. struct mg_mgr g_mgr;
  51. void _ws_send(struct mg_mgr *mgr, char *msg, size_t msg_n) {
  52. int i;
  53. struct mg_connection *con;
  54. for (con = mgr->conns; con; con = con->next) {
  55. if (con->is_websocket && con->is_accepted) {
  56. mg_ws_send(con, msg, msg_n, WEBSOCKET_OP_TEXT);
  57. }
  58. }
  59. }
  60. static void _cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  61. int i;
  62. size_t n;
  63. struct mg_http_message *hm = NULL;
  64. if (ev == MG_EV_HTTP_MSG) {
  65. hm = (struct mg_http_message *) ev_data;
  66. if (mg_http_match_uri(hm, "/ws")) {
  67. // Upgrade to websocket. From now on, a connection is a full-duplex
  68. // Websocket connection, which will receive MG_EV_WS_MSG events.
  69. //
  70. mg_ws_upgrade(c, hm, NULL);
  71. }
  72. else if (mg_http_match_uri(hm, "/")) {
  73. struct mg_http_serve_opts opts = {.root_dir = s_web_directory};
  74. mg_http_serve_dir(c, hm, &opts);
  75. }
  76. else if (mg_http_match_uri(hm, "/rest")) {
  77. // Serve REST response
  78. //
  79. mg_http_reply(c, 200, "", "{\"result\": %d}\n", 123);
  80. }
  81. else {
  82. // Serve static files
  83. //
  84. struct mg_http_serve_opts opts = {.root_dir = s_web_directory};
  85. mg_http_serve_dir(c, (mg_http_message *)ev_data, &opts);
  86. }
  87. }
  88. else if (ev == MG_EV_WS_MSG) {
  89. // Got websocket frame. Received data is wm->data. Echo it back!
  90. //
  91. struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
  92. n = strlen("relay ");
  93. if (wm->data.len < n) {
  94. n = wm->data.len;
  95. }
  96. if (n < wm->data.len) {
  97. if (strncmp("relay ", (char *)(wm->data.ptr), n)==0) {
  98. _ws_send(&g_mgr, ((char *)(wm->data.ptr)) + n, wm->data.len - n);
  99. }
  100. }
  101. mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_TEXT);
  102. mg_iobuf_delete(&c->recv, c->recv.len);
  103. n = strlen("broadcast");
  104. _ws_send(&g_mgr, (char *)"broadcast", n);
  105. }
  106. (void) fn_data;
  107. }
  108. void show_version(FILE *ofp) {
  109. fprintf(ofp, "piumsgd version %s\n", PIUMSGD_VERSION);
  110. }
  111. void show_help(FILE *ofp) {
  112. show_version(ofp);
  113. fprintf(ofp, "\npiusmgd usage:\n\n");
  114. fprintf(ofp, " piumsgd [-h] [-v] [-p port] [-H host] [-D webdir] [-V]\n");
  115. fprintf(ofp, "\n");
  116. fprintf(ofp, " -D web directory (default %s)\n", PIUMSGD_DEFAULT_WEBDIR);
  117. fprintf(ofp, " -H host (default %s)\n", PIUMSGD_DEFAULT_ADDR);
  118. fprintf(ofp, " -p port (default %i)\n", PIUMSGD_DEFAULT_PORT);
  119. fprintf(ofp, " -V verbose\n");
  120. fprintf(ofp, " -v show version\n");
  121. fprintf(ofp, " -h help (this screen)\n");
  122. fprintf(ofp, "\n");
  123. }
  124. int main(int argc, char **argv) {
  125. int ch, opt_index;
  126. int nfd=0;
  127. int poll_return;
  128. int read_return;
  129. time_t now;
  130. int port = -1;
  131. char *host = NULL, *webdir = NULL;
  132. struct mg_conneciton *nc;
  133. char *listen_host = NULL;
  134. while ((ch = getopt_long(argc, argv, "hvVH:D:p:", long_opt, &opt_index)) >= 0) {
  135. switch (ch) {
  136. case 0:
  137. break;
  138. case 'h':
  139. show_help(stdout);
  140. exit(0);
  141. break;
  142. case 'v':
  143. show_version(stdout);
  144. exit(0);
  145. break;
  146. case 'V':
  147. g_verbose++;
  148. break;
  149. case 'p':
  150. port = atoi(optarg);
  151. break;
  152. case 'H':
  153. host = strdup(optarg);
  154. break;
  155. case 'D':
  156. s_web_directory = strdup(optarg);
  157. break;
  158. default:
  159. fprintf(stderr, "unknown option %c\n", ch);
  160. show_help(stderr);
  161. exit(-1);
  162. break;
  163. }
  164. }
  165. if(!s_web_directory) {
  166. s_web_directory = strdup(PIUMSGD_DEFAULT_WEBDIR);
  167. }
  168. if (port < 0) {
  169. port = PIUMSGD_DEFAULT_PORT;
  170. }
  171. if (!host) {
  172. host = strdup(PIUMSGD_DEFAULT_ADDR);
  173. }
  174. listen_host = (char *)malloc(sizeof(char)*2*strlen(host));
  175. sprintf(listen_host, "http://%s:%i", host, port);
  176. // setup mongoose web server
  177. //
  178. mg_mgr_init(&g_mgr);
  179. //mg_http_listen(&g_mgr, "http://127.0.0.1:8001", _cb, NULL);
  180. //mg_http_listen(&g_mgr, "http://0.0.0.0:8001", _cb, NULL);
  181. mg_http_listen(&g_mgr, listen_host, _cb, NULL);
  182. for (;;) {
  183. mg_mgr_poll(&g_mgr, 200);
  184. }
  185. mg_mgr_free(&g_mgr);
  186. return 0;
  187. }