1 /*
2  *   Copyright (c) 2014 - 2016 Kulykov Oleh <info@resident.name>
3  *
4  *   Permission is hereby granted, free of charge, to any person obtaining a copy
5  *   of this software and associated documentation files (the "Software"), to deal
6  *   in the Software without restriction, including without limitation the rights
7  *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  *   copies of the Software, and to permit persons to whom the Software is
9  *   furnished to do so, subject to the following conditions:
10  *
11  *   The above copyright notice and this permission notice shall be included in
12  *   all copies or substantial portions of the Software.
13  *
14  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  *   THE SOFTWARE.
21  */
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include <aos/kernel.h>
26 #include <librws.h>
27 
28 #if AOS_COMP_CLI
29 #include <aos/cli.h>
30 #endif
31 
32 #define WEBSOCKET_CONNECTED (0x01)
33 #define WEBSOCKET_DISCONNECTED (0x02)
34 #define WEBSOCKET_DATA_NOT_RECVED (0x04)
35 
36 #define WEBSOCKET_SSL_TEST 0
37 #define WEBSOCKET_BIN_DATA_TEST 0
38 
39 #if WEBSOCKET_SSL_TEST
40 
41 const char *ECHO_WEBSOCKET_CER = {
42    "-----BEGIN CERTIFICATE-----\r\n"
43     "MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\r\n"
44     "MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\r\n"
45     "DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\r\n"
46     "SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\r\n"
47     "GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\r\n"
48     "AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\r\n"
49     "q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\r\n"
50     "SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\r\n"
51     "Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\r\n"
52     "a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\r\n"
53     "/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\r\n"
54     "AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\r\n"
55     "CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\r\n"
56     "bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\r\n"
57     "c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\r\n"
58     "VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\r\n"
59     "ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\r\n"
60     "MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\r\n"
61     "Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\r\n"
62     "AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\r\n"
63     "uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\r\n"
64     "wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\r\n"
65     "X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\r\n"
66     "PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\r\n"
67     "KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\r\n"
68     "-----END CERTIFICATE-----\r\n"
69 };
70 #endif
71 
72 static rws_socket _socket = NULL;
73 static int state_flags = 0;
74 
on_socket_received_text(rws_socket socket,const char * text,const unsigned int length,bool is_finish)75 static void on_socket_received_text(rws_socket socket, const char *text, const unsigned int length, bool is_finish)
76 {
77     char *buff = NULL;
78 
79     if (!socket || !text || !length) {
80         DBG("%s: Invalid parameter(s).", __FUNCTION__);
81         return;
82     }
83 
84     buff = (char *)aos_malloc(length + 1);
85     if (!buff) {
86         DBG("%s: Not enough memory. len:%d", __FUNCTION__, length + 1);
87         return;
88     }
89 
90     state_flags &= (~WEBSOCKET_DATA_NOT_RECVED);
91 
92     memcpy(buff, text, length);
93     buff[length] = 0;
94 
95     DBG("%s: Socket text: %s", __FUNCTION__, buff);
96     aos_free(buff);
97     buff = NULL;
98 }
99 
on_socket_received_bin(rws_socket socket,const void * data,const unsigned int length,bool is_finish)100 static void on_socket_received_bin(rws_socket socket, const void * data, const unsigned int length, bool is_finish)
101 {
102     char *buff = NULL;
103 
104     if (!socket || !data || !length) {
105         DBG("%s: Invalid parameter(s).", __FUNCTION__);
106         return;
107     }
108 
109     buff = (char *)aos_malloc(length + 1);
110     if (!buff) {
111         DBG("%s: Not enough memory. len:%d", __FUNCTION__, length + 1);
112         return;
113     }
114 
115     state_flags &= ~WEBSOCKET_DATA_NOT_RECVED;
116 
117     memcpy(buff, data, length);
118     buff[length] = 0;
119 
120     DBG("%s: Socket bin: \n%s", __FUNCTION__, buff);
121     aos_free(buff);
122     buff = NULL;
123 }
124 
on_socket_received_pong(rws_socket socket)125 static void on_socket_received_pong(rws_socket socket)
126 {
127     if (!socket) {
128         DBG("%s: Invalid parameter(s).", __FUNCTION__);
129         return;
130     }
131     DBG("received pong!!!!!!!!!!!");
132 }
133 
on_socket_connected(rws_socket socket)134 static void on_socket_connected(rws_socket socket)
135 {
136     const char * test_send_text =
137         "{\"version\":\"1.0\",\"supportedConnectionTypes\":[\"websocket\"],\"minimumVersion\":\"1.0\",\"channel\":\"/meta/handshake\"}";
138 
139     DBG("%s: Socket connected", __FUNCTION__);
140 
141     state_flags |= WEBSOCKET_CONNECTED;
142     state_flags &= ~WEBSOCKET_DISCONNECTED;
143     rws_socket_send_text(socket, test_send_text);
144 }
145 
on_socket_disconnected(rws_socket socket)146 static void on_socket_disconnected(rws_socket socket)
147 {
148     rws_error error = rws_socket_get_error(socket);
149     if (error) {
150         DBG("%s: Socket disconnect with code, error: %i, %s",
151             __FUNCTION__,
152             rws_error_get_code(error),
153             rws_error_get_description(error));
154     }
155 
156     state_flags &= ~WEBSOCKET_CONNECTED;
157     state_flags |= WEBSOCKET_DISCONNECTED;
158     _socket = NULL;
159 }
160 
161 
websoc_cli_test_int(const char * scheme,const char * host,const char * path,const int port,const char * cert)162 int websoc_cli_test_int(const char *scheme, const char *host,
163                         const char *path, const int port,
164                         const char *cert)
165 {
166     int sleep_count = 0;
167     int ret = 0;
168 
169     if (!scheme || !host || !path) {
170         DBG("%s: Invalid parameter(s).", __FUNCTION__);
171         return -1;
172     }
173 
174     if (_socket) {
175         DBG("%s: Socket is not closed.", __FUNCTION__);
176         return -2;
177     }
178 
179     _socket = rws_socket_create(); // create and store socket handle
180 
181     state_flags = 0;
182     state_flags |= WEBSOCKET_DATA_NOT_RECVED;
183 
184     rws_socket_set_scheme(_socket, scheme);
185     rws_socket_set_host(_socket, host);
186     rws_socket_set_path(_socket, path);
187     rws_socket_set_port(_socket, port);
188 
189 #ifdef WEBSOCKET_SSL_ENABLE
190     if (cert) {
191         rws_socket_set_server_cert(_socket, cert, strlen(cert) + 1);
192     }
193 #endif
194 
195     rws_socket_set_on_disconnected(_socket, &on_socket_disconnected);
196     rws_socket_set_on_connected(_socket, &on_socket_connected);
197     rws_socket_set_on_received_text(_socket, &on_socket_received_text);
198     rws_socket_set_on_received_bin(_socket, &on_socket_received_bin);
199     rws_socket_set_on_received_pong(_socket, &on_socket_received_pong);
200 
201     rws_socket_connect(_socket);
202 
203     /* Connecting */
204     while ((!(state_flags & WEBSOCKET_CONNECTED)) &&
205            (!(state_flags & WEBSOCKET_DISCONNECTED))) {
206         rws_thread_sleep(1000);
207         DBG("Wait for websocket connection\n");
208         sleep_count++;
209         if (30 == sleep_count) {
210             if (!(state_flags & WEBSOCKET_CONNECTED)) {
211                 ERR("Connect timeout\n");
212                 ret = -1;
213             }
214             break;
215         }
216     }
217 
218 
219     /* Receiving data */
220     sleep_count = 0;
221     if (state_flags & WEBSOCKET_CONNECTED) {
222         while ((state_flags & WEBSOCKET_DATA_NOT_RECVED) && _socket &&
223                (rws_true == rws_socket_is_connected(_socket))) {
224             rws_thread_sleep(1000);
225             sleep_count++;
226             if (20 == sleep_count) {
227                 if (state_flags & WEBSOCKET_DATA_NOT_RECVED) {
228                     ERR("recv timeout\n");
229                     ret = -1;
230                 }
231                 break;
232             }
233         }
234     }
235 
236 #if WEBSOCKET_BIN_DATA_TEST
237    static const char *text_arr[] = {
238         "-----BEGIN CERTIFICATE-----"
239         "MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN"
240         "MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu"
241         "VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN"
242         "MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0"
243         "MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi"
244         "MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7"
245         "ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy"
246         "RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS"
247         "bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF"
248         "/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R"
249         "3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw"
250         "EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy"
251         "9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V"
252         "GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ"
253         "2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV"
254         "WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD"
255         "W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/"
256         "BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN"
257         "AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj"
258         "t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV"
259         "DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9"
260         "TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G"
261         "lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW"
262         "mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df"
263         "WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5"
264         "+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ"
265         "tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA"
266         "GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv"
267         "8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c"
268         "-----END CERTIFICATE-----",
269         "AABBsdfasdfasdfasdfasdfasdfasdfadfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadfasdfasdfasdfasdfasdf",
270         "09840523490582034850-2385023845023845023840523orjoewjrt0932u4ojt[iq3w04tu32094503u4t32u4059",
271         ";';,,'s'd,fdg;sm;lsdf;g,s;d  ;s,g ;,df;gl s;dg, ;sd,;gf,sd; g,",
272         "46s4f64s6df4a6sd4f64sdgf654segf654df66dsfg4e4rt65w4t6w4et64ewr6g4sd64fg65ds4fg",
273         "sdfasdg4sag64a6g45sd4 64365 46 4d6f4asd64 f6as4 f6as74f987s6543654165JJKK",
274         NULL
275     };
276 
277     rws_socket_send_bin_start(_socket, "start", strlen("start"));
278     int i = 0;
279     while(text_arr[i] != NULL) {
280         rws_socket_send_bin_continue(_socket, text_arr[i], strlen(text_arr[i]));
281         // aos_msleep(100);
282         i++;
283     }
284     rws_socket_send_bin_finish(_socket, "finish", strlen("finish"));
285 #endif
286 
287     if (_socket) {
288         rws_socket_disconnect_and_release(_socket);
289     }
290 
291     _socket = NULL;
292 
293     return ret;
294 }
295 
websoc_cli_test_entry(void * arg)296 void websoc_cli_test_entry(void *arg)
297 {
298     int ret = 0, ssl_ret = 0;
299 
300 #if WEBSOCKET_SSL_TEST
301     char *cert = (char *)ECHO_WEBSOCKET_CER;
302     printf("Test client wss.");
303     ssl_ret = websoc_cli_test_int("wss", "echo.websocket.org", "/", 443, cert);
304 #else
305     printf("Test client ws.");
306     // ret = websoc_cli_test_int("ws", "echo.websocket.org", "/", 80, NULL);
307     ret = websoc_cli_test_int("ws", "121.40.165.18", "/", 8800, NULL);
308 #endif
309 
310     if (0 == ret && 0 == ssl_ret) {
311         printf("example websocket test success!");
312     } else {
313         printf("example websocket test failed! ret:%d, ssl_ret:%d", ret, ssl_ret);
314     }
315 }
316 
websocket_comp_example(int argc,char ** argv)317 void websocket_comp_example(int argc, char **argv)
318 {
319     aos_task_new("ws-test", websoc_cli_test_entry, NULL, 10 * 1024);
320 }
321 
322 
323 #if AOS_COMP_CLI
324 /* reg args: fun, cmd, description*/
325 ALIOS_CLI_CMD_REGISTER(websocket_comp_example, websocket_example, websocket component base example)
326 #endif
327