ws_ssl.c
Go to the documentation of this file.
00001 // Copyright (c) 2014 Cesanta Software
00002 // All rights reserved
00003 //
00004 // This example demostrates proxying of WebSocket traffic, regardless of the
00005 // protocol (ws:// or wss://).
00006 // To use this example:
00007 //    1. configure your browser to use a proxy on port 2014
00008 //    2. import certs/ws1_ca.pem and certs/ws2_ca.pem into the trusted
00009 //       certificates list on your browser
00010 //    3. make && ./ws_ssl
00011 //    4. Point your browser to http://ws_ssl.com
00012 //  A page with 4 sections should appear, showing websocket echoes
00013 
00014 #include "net_skeleton.h"
00015 #include "mongoose.h"
00016 #include "ssl_wrapper.h"
00017 
00018 #define S1_PEM  "certs/ws1_server.pem"
00019 #define C1_PEM  "certs/ws1_client.pem"
00020 #define CA1_PEM "certs/ws1_ca.pem"
00021 #define S2_PEM  "certs/ws2_server.pem"
00022 #define C2_PEM  "certs/ws2_client.pem"
00023 #define CA2_PEM "certs/ws2_ca.pem"
00024 
00025 struct config {
00026   const char *uri;
00027   const char *wrapper_server_addr;
00028   const char *wrapper_client_addr;
00029   const char *target_addr;
00030 };
00031 
00032 static struct config s_wrappers[] = {
00033   {
00034     "ws1:80",
00035     "tcp://127.0.0.1:7001",
00036     "tcp://127.0.0.1:7001",
00037     "tcp://127.0.0.1:9001"
00038   },
00039   {
00040     "ws1:443",
00041     "ssl://127.0.0.1:7002:" S1_PEM,
00042     "tcp://127.0.0.1:7002",
00043     "tcp://127.0.0.1:9001"
00044   },
00045   {
00046     "ws2:80",
00047     "tcp://127.0.0.1:7003",
00048     "tcp://127.0.0.1:7003",
00049     "ssl://127.0.0.1:9002:" C2_PEM ":" CA2_PEM
00050   },
00051   {
00052     "ws2:443",
00053     "ssl://127.0.0.1:7004:" S2_PEM,
00054     "tcp://127.0.0.1:7004",
00055     "ssl://127.0.0.1:9002:" C2_PEM ":" CA2_PEM
00056   },
00057 };
00058 
00059 static int s_received_signal = 0;
00060 
00061 static void signal_handler(int sig_num) {
00062   signal(sig_num, signal_handler);
00063   s_received_signal = sig_num;
00064 }
00065 
00066 static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
00067   int i;
00068 
00069   switch (ev) {
00070     case MG_AUTH:
00071       return MG_TRUE;
00072 
00073     case MG_REQUEST:
00074       printf("==> [%s] [%s]\n", conn->request_method, conn->uri);
00075 
00076       if (strcmp(conn->request_method, "CONNECT") == 0) {
00077         // Iterate over configured wrappers, see if we can use one of them
00078         for (i = 0; i < (int) ARRAY_SIZE(s_wrappers); i++) {
00079           if (strcmp(conn->uri, s_wrappers[i].uri) == 0) {
00080             mg_forward(conn, s_wrappers[i].wrapper_client_addr);
00081             return MG_MORE;
00082           }
00083         }
00084 
00085         // No suitable wrappers found. Disallow that CONNECT request.
00086         mg_send_status(conn, 405);
00087         return MG_TRUE;
00088       }
00089 
00090       // Not a CONNECT request, serve HTML file.
00091       mg_send_file(conn, "ws_ssl.html", NULL);
00092       return MG_MORE;
00093 
00094     default:
00095       return MG_FALSE;
00096   }
00097 }
00098 
00099 static int ws_handler(struct mg_connection *conn, enum mg_event ev) {
00100   switch (ev) {
00101     case MG_AUTH:
00102       return MG_TRUE;
00103     case MG_REQUEST:
00104       if (conn->is_websocket) {
00105         // Simple websocket echo server
00106         mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT,
00107                            conn->content, conn->content_len);
00108       } else {
00109         mg_printf_data(conn, "%s", "websocket connection expected");
00110       }
00111       return MG_TRUE;
00112     default:
00113       return MG_FALSE;
00114   }
00115 }
00116 
00117 static void *serve_thread_func(void *param) {
00118   struct mg_server *server = (struct mg_server *) param;
00119   printf("Listening on port %s\n", mg_get_option(server, "listening_port"));
00120   while (s_received_signal == 0) {
00121     mg_poll_server(server, 1000);
00122   }
00123   mg_destroy_server(&server);
00124   return NULL;
00125 }
00126 
00127 static void *wrapper_thread_func(void *param) {
00128   struct config *c = (struct config *) param;
00129   const char *err_msg;
00130   void *wrapper;
00131 
00132   wrapper = ssl_wrapper_init(c->wrapper_server_addr, c->target_addr, &err_msg);
00133   if (wrapper == NULL) {
00134     fprintf(stderr, "Error: %s\n", err_msg);
00135     exit(EXIT_FAILURE);
00136   }
00137   //((struct ns_mgr *) wrapper)->hexdump_file = "/dev/stderr";
00138   ssl_wrapper_serve(wrapper, &s_received_signal);
00139 
00140   return NULL;
00141 }
00142 
00143 int main(void) {
00144   struct mg_server *proxy_server = mg_create_server(NULL, ev_handler);
00145   struct mg_server *ws1_server = mg_create_server(NULL, ws_handler);
00146   struct mg_server *ws2_server = mg_create_server(NULL, ws_handler);
00147   size_t i;
00148 
00149   ((struct ns_mgr *) proxy_server)->hexdump_file = "/dev/stderr";
00150 
00151   // Configure proxy server to listen on port 2014
00152   mg_set_option(proxy_server, "listening_port", "2014");
00153   //mg_set_option(proxy_server, "enable_proxy", "yes");
00154 
00155   // Configure two websocket echo servers:
00156   //    ws1 is WS, listening on 9001
00157   //    ws2 is WSS, listening on 9002
00158   // Note that HTML page thinks that ws1 is WSS, and ws2 is WS,
00159   // where in reality it is vice versa and proxy server makes the decision.
00160   mg_set_option(ws1_server, "listening_port", "tcp://127.0.0.1:9001");
00161   mg_set_option(ws2_server, "listening_port",
00162                 "ssl://127.0.0.1:9002:" S2_PEM ":" CA2_PEM);
00163 
00164   // Setup signal handlers
00165   signal(SIGTERM, signal_handler);
00166   signal(SIGINT, signal_handler);
00167 
00168   // Start SSL wrappers, each in it's own thread
00169   for (i = 0; i < ARRAY_SIZE(s_wrappers); i++) {
00170     ns_start_thread(wrapper_thread_func, &s_wrappers[i]);
00171   }
00172 
00173   // Start websocket servers in separate threads
00174   mg_start_thread(serve_thread_func, ws1_server);
00175   mg_start_thread(serve_thread_func, ws2_server);
00176 
00177   // Finally, start proxy server in this thread: this call blocks
00178   serve_thread_func(proxy_server);
00179 
00180   printf("Existing on signal %d\n", s_received_signal);
00181   return EXIT_SUCCESS;
00182 }


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:07