1 /*
2  *   Copyright (c) 2014 - 2019 Oleh Kulykov <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 
24 #ifndef __LIBRWS_H__
25 #define __LIBRWS_H__ 1
26 
27 #include <stdio.h>
28 #include <stdbool.h>
29 #ifndef _AMLOGIC_
30 #include "ulog/ulog.h"
31 #else
32 #include <printf.h>
33 #endif
34 #define RWS_VERSION_MAJOR 1
35 #define RWS_VERSION_MINOR 2
36 #define RWS_VERSION_PATCH 4
37 
38 #define WEBSOC_TAG "websoc"
39 #if defined(WEBSOCKET_DEBUG)
40 #define DBG(format, arg...)   LOGD(WEBSOC_TAG, format, ##arg)
41 #define WRN(format,arg...)    LOGW(WEBSOC_TAG, format, ##arg)
42 #define ERR(format,arg...)    LOGE(WEBSOC_TAG, format, ##arg)
43 #else
44 #define DBG(format,arg...)    LOGD(WEBSOC_TAG, format, ##arg)
45 #define WRN(format,arg...)    LOGW(WEBSOC_TAG, format, ##arg)
46 #define ERR(format,arg...)    LOGE(WEBSOC_TAG, format, ##arg)
47 #endif
48 
49 // check windows
50 #if defined(WIN32) || defined(_WIN32) || defined(WIN32_LEAN_AND_MEAN) || defined(_WIN64) || defined(WIN64)
51 #define RWS_OS_WINDOWS 1
52 #endif
53 
54 
55 // extern
56 #if defined(__cplusplus) || defined(_cplusplus)
57 #define RWS_EXTERN extern "C"
58 #else
59 #define RWS_EXTERN extern
60 #endif
61 
62 
63 // attribute
64 #if defined(__GNUC__)
65 #if (__GNUC__ >= 4)
66 #if defined(__cplusplus) || defined(_cplusplus)
67 #define RWS_ATTRIB __attribute__((visibility("default")))
68 #else
69 #define RWS_ATTRIB __attribute__((visibility("default")))
70 #endif
71 #endif
72 #endif
73 
74 
75 // check attrib and define empty if not defined
76 #if !defined(RWS_ATTRIB)
77 #define RWS_ATTRIB
78 #endif
79 
80 
81 // dll api
82 #if defined(RWS_OS_WINDOWS)
83 #if defined(RWS_BUILD)
84 #define RWS_DYLIB_API __declspec(dllexport)
85 #else
86 #define RWS_DYLIB_API __declspec(dllimport)
87 #endif
88 #endif
89 
90 
91 // check dll api and define empty if not defined
92 #if !defined(RWS_DYLIB_API)
93 #define RWS_DYLIB_API
94 #endif
95 
96 
97 // combined lib api
98 #define RWS_API(return_type) RWS_EXTERN RWS_ATTRIB RWS_DYLIB_API return_type
99 
100 
101 // types
102 
103 /**
104  @brief Boolean type as unsigned byte type.
105  */
106 typedef unsigned char rws_bool;
107 #define rws_true 1
108 #define rws_false 0
109 
110 #define RWS_WAIT_FOREVER 0xffffffffu
111 
112 /**
113  @brief Type of all public objects.
114  */
115 typedef void* rws_handle;
116 
117 
118 /**
119  @brief Socket handle.
120  */
121 typedef struct rws_socket_struct * rws_socket;
122 
123 
124 /**
125  @brief Error object handle.
126  */
127 typedef struct rws_error_struct * rws_error;
128 
129 
130 /**
131  @brief Mutex object handle.
132  */
133 typedef rws_handle rws_mutex;
134 
135 /**
136  @brief Mutex object handle.
137  */
138 typedef rws_handle rws_sem;
139 
140 /**
141  @brief Thread object handle.
142  */
143 typedef struct rws_thread_struct * rws_thread;
144 
145 
146 /**
147  @brief Callback type of thread function.
148  @param user_object User object provided during thread creation.
149  */
150 typedef void (*rws_thread_funct)(void * user_object);
151 
152 
153 /**
154  @brief Callback type of socket object.
155  @param socket Socket object.
156  */
157 typedef void (*rws_on_socket)(rws_socket socket);
158 
159 
160 /**
161  @brief Callback type on socket receive text frame.
162  @param socket Socket object.
163  @param text Pointer to reseived text.
164  @param length Received text lenght without null terminated char.
165  */
166 typedef void (*rws_on_socket_recvd_text)(rws_socket socket, const char * text, const unsigned int length, bool is_finished);
167 
168 
169 /**
170  @brief Callback type on socket receive binary frame.
171  @param socket Socket object.
172  @param data Received binary data.
173  @param length Received binary data lenght.
174  */
175 typedef void (*rws_on_socket_recvd_bin)(rws_socket socket, const void * data, const unsigned int length, bool is_finished);
176 
177 
178 /**
179  @brief Callback type on socket receive pong.
180  @param socket Socket object.
181  */
182 typedef void (*rws_on_socket_recvd_pong)(rws_socket socket);
183 
184 
185 /**
186  @brief Callback type on socket send ping.
187  @param socket Socket object.
188  */
189 typedef void (*rws_on_socket_send_ping)(rws_socket socket);
190 
191 // socket
192 
193 /**
194  @brief Create new socket.
195  @return Socket handler or NULL on error.
196  */
197 RWS_API(rws_socket) rws_socket_create(void);
198 
199 
200 /**
201  @brief Set socket connect URL.
202  @param socket Socket object.
203  @param scheme Connect URL scheme, "http" or "ws"
204  @param scheme Connect URL host, "echo.websocket.org"
205  @param scheme Connect URL port.
206  @param scheme Connect URL path started with '/' character, "/" - for empty, "/path"
207  @code
208  rws_socket_set_url(socket, "http", "echo.websocket.org", 80, "/");
209  rws_socket_set_url(socket, "ws", "echo.websocket.org", 80, "/");
210  @endcode
211  */
212 RWS_API(void) rws_socket_set_url(rws_socket socket,
213 								 const char * scheme,
214 								 const char * host,
215 								 const int port,
216 								 const char * path);
217 
218 /**
219  @brief Set socket connect URL scheme string.
220  @param socket Socket object.
221  @param scheme Connect URL scheme, "http" or "ws"
222  @code
223  rws_socket_set_scheme(socket, "http");
224  rws_socket_set_scheme(socket, "ws");
225  @endcode
226  */
227 RWS_API(void) rws_socket_set_scheme(rws_socket socket, const char * scheme);
228 
229 
230 /**
231  @brief Get socket connect URL scheme string.
232  @param socket Socket object.
233  @return Connect URL cheme or null.
234  */
235 RWS_API(const char *) rws_socket_get_scheme(rws_socket socket);
236 
237 
238 /**
239  @brief Set socket connect URL scheme string.
240  @param socket Socket object.
241  @param scheme Connect URL host, "echo.websocket.org"
242  @code
243  rws_socket_set_host(socket, "echo.websocket.org");
244  @endcode
245  */
246 RWS_API(void) rws_socket_set_host(rws_socket socket, const char * host);
247 
248 
249 /**
250  @brief Get socket connect URL host string.
251  @param socket Socket object.
252  @return Connect URL host or null.
253  */
254 RWS_API(const char *) rws_socket_get_host(rws_socket socket);
255 
256 
257 /**
258  @brief Set socket connect URL port.
259  @param socket Socket object.
260  @param scheme Connect URL port.
261  @code
262  rws_socket_set_port(socket, 80);
263  @endcode
264  */
265 RWS_API(void) rws_socket_set_port(rws_socket socket, const int port);
266 
267 
268 /**
269  @brief Get socket connect URL port.
270  @param socket Socket object.
271  @return Connect URL port or 0.
272  */
273 RWS_API(int) rws_socket_get_port(rws_socket socket);
274 
275 
276 /**
277  @brief Set socket connect URL path string.
278  @param socket Socket object.
279  @param scheme Connect URL path started with '/' character, "/" - for empty, "/path"
280  @code
281  rws_socket_set_path(socket, "/"); // empty path
282  rws_socket_set_path(socket, "/path"); // some path
283  @endcode
284  */
285 RWS_API(void) rws_socket_set_path(rws_socket socket, const char * path);
286 
287 
288 /**
289  @brief Get socket connect URL path string.
290  @param socket Socket object.
291  @return Connect URL path or null.
292  */
293 RWS_API(const char *) rws_socket_get_path(rws_socket socket);
294 
295 
296 /**
297  @brief Set  socket connect Sec-WebSocket-Protocol field.
298  @param socket Socket object.
299  @param Sec-WebSocket-Protocol.
300  @code
301  rws_socket_set_protocol(socket, "echo-protocol")
302  rws_socket_set_protocol(socket, "chat, superchat")
303  @endcode
304  */
305 RWS_API(void) rws_socket_set_protocol(rws_socket socket, const char * protocol);
306 
307 #ifdef WEBSOCKET_SSL_ENABLE
308 /**
309  @brief Set server certificate for ssl connection.
310  @param socket Socket object.
311  @param server_cert Server certificate.
312  @param server_cert_len The length of the server certificate caculated by sizeof
313 */
314 RWS_API(void) rws_socket_set_server_cert(rws_socket socket, const char *server_cert, int server_cert_len);
315 #endif
316 
317 
318 /**
319  @brief Get socket last error object handle.
320  @param socket Socket object.
321  @return Last error object handle or null if no error.
322  */
323 RWS_API(rws_error) rws_socket_get_error(rws_socket socket);
324 
325 
326 /**
327  @brief Start connection.
328  @detailed This method can generate error object.
329  @param socket Socket object.
330  @return rws_true - all params exists and connection started, otherwice rws_false.
331  */
332 RWS_API(rws_bool) rws_socket_connect(rws_socket socket);
333 
334 
335 /**
336  @brief Disconnect socket.
337  @detailed Cleanup prev. send messages and start disconnection sequence.
338  SHOULD forget about this socket handle and don't use it anymore.
339  @warning Don't use this socket object handler after this command.
340  @param socket Socket object.
341  */
342 RWS_API(void) rws_socket_disconnect_and_release(rws_socket socket);
343 
344 
345 /**
346  @brief Check is socket has connection to host and handshake(sucessfully done).
347  @detailed Thread safe getter.
348  @param socket Socket object.
349  @return trw_true - connected to host and handshacked, otherwice rws_false.
350  */
351 RWS_API(rws_bool) rws_socket_is_connected(rws_socket socket);
352 
353 
354 /**
355  @brief Send text to connect socket.
356  @detailed Thread safe method.
357  @param socket Socket object.
358  @param text Text string for sending.
359  @return rws_true - socket and text exists and placed to send queue, otherwice rws_false.
360  */
361 RWS_API(rws_bool) rws_socket_send_text(rws_socket socket, const char * text);
362 
363 
364 /**
365  @brief Set socket user defined object pointer for identificating socket object.
366  @param socket Socket object.
367  @param user_object Void pointer to user object.
368  */
369 RWS_API(void) rws_socket_set_user_object(rws_socket socket, void * user_object);
370 
371 
372 /**
373  @brief Get socket user defined object.
374  @param socket Socket object.
375  @return User defined object pointer or null.
376  */
377 RWS_API(void *) rws_socket_get_user_object(rws_socket socket);
378 
379 
380 RWS_API(void) rws_socket_set_on_connected(rws_socket socket, rws_on_socket callback);
381 
382 
383 RWS_API(void) rws_socket_set_on_disconnected(rws_socket socket, rws_on_socket callback);
384 
385 
386 RWS_API(void) rws_socket_set_on_received_text(rws_socket socket, rws_on_socket_recvd_text callback);
387 
388 
389 RWS_API(void) rws_socket_set_on_received_bin(rws_socket socket, rws_on_socket_recvd_bin callback);
390 
391 /**
392  @brief Get socket user defined object.
393  @param socket Socket object.
394 */
395 RWS_API(void) rws_socket_set_on_received_pong(rws_socket socket, rws_on_socket_recvd_pong callback);
396 
397 
398 /**
399  @brief Get socket user defined object.
400  @param socket Socket object.
401 */
402 RWS_API(void) rws_socket_set_on_send_ping(rws_socket socket, rws_on_socket_send_ping callback);
403 
404 
405 /**
406  @brief Send bin header to connect socket.
407  @detailed Thread safe method.
408  @param socket Socket object.
409  @param bin header string for sending.
410  @param len length of header, 8 bytes.
411  @return rws_true - socket and bin header exists and placed to send queue, otherwice rws_false
412  */
413 RWS_API(rws_bool) rws_socket_send_bin_start(rws_socket socket, const char *bin, size_t len);
414 
415 /**
416  @brief Send bin content to connect socket.
417  @detailed Thread safe method.
418  @param socket Socket object.
419  @param binary content for sending.
420  @param len length of binary content.
421  @return rws_true - socket and bin content exists and placed to send queue, otherwice rws_false.
422 */
423 RWS_API(rws_bool) rws_socket_send_bin_continue(rws_socket socket, const char *bin, size_t len);
424 
425 
426 /**
427  @brief Send final bin to connect socket.
428  @detailed Thread safe method.
429  @param socket Socket object.
430  @param final bin string for sending.
431  @param len length of final, 6 bytes.
432  @return rws_true - socket and final bin exists and placed to send queue, otherwice rws_false
433 */
434 RWS_API(rws_bool) rws_socket_send_bin_finish(rws_socket socket, const char * bin, size_t len);
435 
436 
437 /**
438  @brief Send ping async to connect socket.
439  @detailed Thread safe method.
440  @param socket Socket object.
441  @return rws_true - send ping success, otherwice rws_false
442 */
443 RWS_API(rws_bool) rws_socket_send_ping(rws_socket socket);
444 
445 // error
446 typedef enum _rws_error_code {
447 	rws_error_code_none = 0,
448 
449 	rws_error_code_missed_parameter,
450 
451 	rws_error_code_send_handshake,
452 	rws_error_code_parse_handshake,
453 	rws_error_code_read_write_socket,
454 	rws_error_code_connect_to_host,
455 
456 	/**
457 	 @brief Connection was closed by endpoint.
458 	 Reasons: an endpoint shutting down, an endpoint having received a frame too large, or an
459 	 endpoint having received a frame that does not conform to the format expected by the endpoint.
460 	 */
461 	rws_error_code_connection_closed,
462 
463 
464 } rws_error_code;
465 
466 
467 /**
468  @return 0 - if error is empty or no error, otherwice error code.
469  */
470 RWS_API(int) rws_error_get_code(rws_error error);
471 
472 
473 /**
474  @return 0 - if error is empty or no error, otherwice HTTP error.
475  */
476 RWS_API(int) rws_error_get_http_error(rws_error error);
477 
478 
479 /**
480  @brief Get description of the error object.
481  */
482 RWS_API(const char *) rws_error_get_description(rws_error error);
483 
484 
485 // mutex
486 
487 /**
488  @brief Creates recursive mutex object.
489  */
490 RWS_API(rws_mutex) rws_mutex_create_recursive(void);
491 
492 
493 /**
494  @brief Lock mutex object.
495  */
496 RWS_API(void) rws_mutex_lock(rws_mutex mutex);
497 
498 
499 /**
500  @brief Unlock mutex object.
501  */
502 RWS_API(void) rws_mutex_unlock(rws_mutex mutex);
503 
504 
505 
506 /**
507  @brief Unlock mutex object.
508  */
509 RWS_API(void) rws_mutex_delete(rws_mutex mutex);
510 
511 // semphore
512 
513 /**
514  @brief Creates semhpore object.
515  */
516 RWS_API(rws_sem) rws_sem_create(void);
517 
518 
519 /**
520  @brief  Release a semhpore
521  */
522 RWS_API(void) rws_sem_signal(rws_sem sem);
523 
524 
525 /**
526  @brief Wait for a semhpore
527  */
528 RWS_API(int) rws_sem_wait(rws_sem sem, unsigned int timeout);
529 
530 
531 /**
532  @brief Free semhpore object.
533  */
534 RWS_API(void) rws_sem_delete(rws_sem sem);
535 
536 
537 // thread
538 
539 /**
540  @brief Create thread object that start immidiatelly.
541  */
542 RWS_API(rws_thread) rws_thread_create(rws_thread_funct thread_function, void * user_object);
543 
544 
545 /**
546  @brief Pause current thread for a number of milliseconds.
547  */
548 RWS_API(void) rws_thread_sleep(const unsigned int millisec);
549 
550 #endif
551