From ef6539e93caf79e3bb38b796b8e2d87a1a50e81c Mon Sep 17 00:00:00 2001 From: bossjisu Date: Tue, 30 May 2017 04:12:46 -0700 Subject: [PATCH] netutils/websocket: organizing code 1. Deleted Unused wqueue function code 2. Added guide line for websocket handler timeout value. It is not supposed to be 0 becaust it makes busy waiting. 3. Added definition on checking a NULL parameter 4. Changed Inappropriate names: websocket_ping_timer() -> websocket_ping_counter() websocket_make_block() -> websocket_config_socket() WEBSOCKET_SERVER_CHECK_INTERVAL -> WEBSOCKET_ACCEPT_TIMEOUT Change-Id: I742f5f0a3c6b50252d7a38fe8a10e927b341837a Signed-off-by: bossjisu --- apps/include/netutils/websocket.h | 21 +++--- apps/netutils/websocket/websocket.c | 128 ++++++++++++++++++++---------------- 2 files changed, 82 insertions(+), 67 deletions(-) diff --git a/apps/include/netutils/websocket.h b/apps/include/netutils/websocket.h index 54eee9f..ad0e0d7 100644 --- a/apps/include/netutils/websocket.h +++ b/apps/include/netutils/websocket.h @@ -107,7 +107,7 @@ /** * @brief Websocket accept server select() timeout value, msec. */ -#define WEBSOCKET_SERVER_CHECK_INTERVAL (500) //mili second +#define WEBSOCKET_ACCEPT_TIMEOUT (500) //mili second /** * @brief Websocket accept server select() timeout limit, msec. */ @@ -115,6 +115,7 @@ /** * @brief Websocket event handler select() timeout value, msec. + Don't set this 0, it will be busy waiting. */ #define WEBSOCKET_HANDLER_TIMEOUT (100) //mili second @@ -128,7 +129,7 @@ #define WEBSOCKET_PING_INTERVAL (20 * 100) //MSEC_PER_TICK /** - * @brief The maximum amount of websocket messages to be stored in queue. + * @brief The maximum length of websocket messages to be stored in queue. */ #define WEBSOCKET_MAX_LENGTH_QUEUE (100 * 1024) /** @@ -137,7 +138,7 @@ #define WEBSOCKET_MAX_NUMBER_QUEUE (20) /** - * @brief The maximum amount of client to accept from server. + * @brief The maximum amount of client to be accepted in server. */ #define WEBSOCKET_MAX_CLIENT (3) @@ -149,7 +150,7 @@ /** * @brief Enable and disable the Server name indication(SNI) */ -#define WEBSOCKET_CONF_CHECK_TLS_HOSTNAME (0) // 0- disable, 1- enable +#define WEBSOCKET_CONF_CHECK_TLS_HOSTNAME (0) // 0- disable, 1- enable /* * Pre-definition variables from wslay below. @@ -484,10 +485,10 @@ websocket_return_t websocket_server_init(websocket_t *server); * but users can change callbacks with this function. * @param[in] websocket websocket structure to store callbacks. * @param[in] cb callbacks structure pointer to change - * @return none + * @return On success, return WEBSOCKET_SUCCESS. On failure, return values defined in websocket_return_t. * @since Tizen RT v1.0 */ -void websocket_register_cb(websocket_t *websocket, websocket_cb_t *cb); +websocket_return_t websocket_register_cb(websocket_t *websocket, websocket_cb_t *cb); /* * @brief websocket_queue_msg() queues a message into websocket context. @@ -532,10 +533,10 @@ websocket_return_t websocket_queue_close(websocket_t *websocket, const char *clo * websocket state are defined at websocket_state. * @param[in] websocket websocket structure. * @param[in] state websocket state. - * @return none + * @return On success, return WEBSOCKET_SUCCESS. On failure, return values defined in websocket_return_t. * @since Tizen RT v1.0 */ -void websocket_update_state(websocket_t *websocket, int state); +websocket_return_t websocket_update_state(websocket_t *websocket, int state); /** * @brief websocket_set_error() sets an error number to websocket context. @@ -544,10 +545,10 @@ void websocket_update_state(websocket_t *websocket, int state); * After this function triggered, websocket context will be closed. * @param[in] websocket websocket structure manages websocket context. * @param[in] val error value to be set. - * @return none + * @return On success, return WEBSOCKET_SUCCESS. On failure, return values defined in websocket_return_t. * @since Tizen RT v1.0 */ -void websocket_set_error(websocket_t *websocket, int val); +websocket_return_t websocket_set_error(websocket_t *websocket, int val); #undef EXTERN #undef EXTERN diff --git a/apps/netutils/websocket/websocket.c b/apps/netutils/websocket/websocket.c index f555a9d..dc0db1e 100644 --- a/apps/netutils/websocket/websocket.c +++ b/apps/netutils/websocket/websocket.c @@ -44,8 +44,6 @@ #include #include -#include - /**************************************************************************** * Definitions ****************************************************************************/ @@ -86,7 +84,6 @@ int websocket_tls_handshake(websocket_t *data, char *hostname, int auth_mode) WEBSOCKET_DEBUG("Error: mbedtls_ssl_setup returned %d\n", r); return -1; } - #if WEBSOCKET_CONF_CHECK_TLS_HOSTNAME if (hostname != NULL) { if ((r = mbedtls_ssl_set_hostname(data->tls_ssl, hostname)) != 0) { @@ -112,7 +109,7 @@ int websocket_tls_handshake(websocket_t *data, char *hostname, int auth_mode) return WEBSOCKET_SUCCESS; } -int websocket_make_block(int fd) +websocket_return_t websocket_config_socket(int fd) { int r; int flags; @@ -127,7 +124,7 @@ int websocket_make_block(int fd) tv.tv_sec = (WEBSOCKET_SOCK_RCV_TIMEOUT / 1000); tv.tv_usec = ((WEBSOCKET_SOCK_RCV_TIMEOUT % 1000) * 1000); - if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (FAR const void *)&tv, (socklen_t)sizeof(struct timeval)) == -1) { + if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (FAR const void *)&tv, (socklen_t) sizeof(struct timeval)) == -1) { WEBSOCKET_DEBUG("setsockopt fail in server\n"); return WEBSOCKET_SOCKET_ERROR; } @@ -135,25 +132,31 @@ int websocket_make_block(int fd) return WEBSOCKET_SUCCESS; } -void websocket_wait_state(websocket_t *websocket, int state, int utime) +websocket_return_t websocket_wait_state(websocket_t *websocket, int state, int utime) { if (websocket == NULL) { - WEBSOCKET_DEBUG("function returned for null parameter\n"); - } else if (!(state >= WEBSOCKET_STOP && state <= WEBSOCKET_MAX_STATE)) { - WEBSOCKET_DEBUG("function returned for invalid parameter\n"); - } else { + WEBSOCKET_DEBUG("NULL parameter\n"); + return WEBSOCKET_ALLOCATION_ERROR; + } + + if (state >= WEBSOCKET_STOP && state < WEBSOCKET_MAX_STATE) { while ((websocket->state) != state) { usleep(utime); } + } else { + WEBSOCKET_DEBUG("function returned for invalid parameter\n"); } + + return WEBSOCKET_SUCCESS; } -void websocket_ping_timer(FAR void *arg) +void websocket_ping_counter(FAR void *arg) { websocket_t *websocket = arg; if (websocket->state != WEBSOCKET_STOP) { websocket->ping_cnt++; + if (websocket->ping_cnt >= WEBSOCKET_MAX_PING_IGNORE) { WEBSOCKET_DEBUG("ping messages couldn't receive pong messages for %d times, closing.\n", WEBSOCKET_MAX_PING_IGNORE); websocket_update_state(websocket, WEBSOCKET_STOP); @@ -174,10 +177,6 @@ int websocket_handler(websocket_t *websocket) wslay_event_context_ptr ctx = (wslay_event_context_ptr) websocket->ctx; struct timeval tv; - if (WEBSOCKET_HANDLER_TIMEOUT == 0) { - work_queue(WEBSOCKET_WQ, &websocket->time_worker, websocket_ping_timer, websocket, WEBSOCKET_PING_INTERVAL); - } - while (websocket->state != WEBSOCKET_STOP) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); @@ -196,9 +195,11 @@ int websocket_handler(websocket_t *websocket) websocket_update_state(websocket, WEBSOCKET_STOP); return WEBSOCKET_SOCKET_ERROR; } + if (errno == EAGAIN || errno == EBUSY || errno == EINTR) { continue; } + WEBSOCKET_DEBUG("select function returned errno == %d\n", errno); continue; } else if (r == 0) { @@ -206,12 +207,14 @@ int websocket_handler(websocket_t *websocket) timeout++; if ((WEBSOCKET_HANDLER_TIMEOUT * timeout) >= (WEBSOCKET_PING_INTERVAL * 10)) { timeout = 0; - websocket_ping_timer((void *)websocket); + websocket_ping_counter((void *)websocket); } } + continue; } else { timeout = 0; + if (FD_ISSET(fd, &read_fds)) { if (wslay_event_recv(ctx) != WEBSOCKET_SUCCESS) { WEBSOCKET_DEBUG("fail to process recv event\n"); @@ -219,6 +222,7 @@ int websocket_handler(websocket_t *websocket) return WEBSOCKET_SOCKET_ERROR; } } + if (FD_ISSET(fd, &write_fds)) { if (wslay_event_send(ctx) != WEBSOCKET_SUCCESS) { WEBSOCKET_DEBUG("fail to process send event\n"); @@ -229,10 +233,6 @@ int websocket_handler(websocket_t *websocket) } } - if (WEBSOCKET_HANDLER_TIMEOUT == 0) { - work_cancel(WEBSOCKET_WQ, &websocket->time_worker); - } - return WEBSOCKET_SUCCESS; } @@ -336,16 +336,19 @@ EXIT_WEBSOCKET_HANDSHAKE_ERROR: return WEBSOCKET_HANDSHAKE_ERROR; } -void websocket_socket_free(websocket_t *ctx) +websocket_return_t websocket_socket_free(websocket_t *ctx) { if (ctx == NULL) { - return; + WEBSOCKET_DEBUG("NULL parameter\n"); + return WEBSOCKET_ALLOCATION_ERROR; } if (ctx->fd >= 0) { close(ctx->fd); ctx->fd = -1; } + + return WEBSOCKET_SUCCESS; } int connect_socket(websocket_t *client, const char *host, const char *port) @@ -406,16 +409,14 @@ TLS_HS_RETRY: websocket_update_state(client, WEBSOCKET_RUNNING); - if (websocket_make_block(client->fd) != WEBSOCKET_SUCCESS) { + if (websocket_config_socket(client->fd) != WEBSOCKET_SUCCESS) { websocket_socket_free(client); return WEBSOCKET_SOCKET_ERROR; } if (client->tls_enabled) { if ((r = websocket_tls_handshake(client, host, client->auth_mode)) != WEBSOCKET_SUCCESS) { - if (r == MBEDTLS_ERR_NET_SEND_FAILED || - r == MBEDTLS_ERR_NET_RECV_FAILED || - r == MBEDTLS_ERR_SSL_CONN_EOF) { + if (r == MBEDTLS_ERR_NET_SEND_FAILED || r == MBEDTLS_ERR_NET_RECV_FAILED || r == MBEDTLS_ERR_SSL_CONN_EOF) { if (tls_hs_retry-- > 0) { WEBSOCKET_DEBUG("Handshake again.... \n"); mbedtls_net_free(&(client->tls_net)); @@ -576,8 +577,8 @@ int websocket_accept_loop(websocket_t *init_server) FD_ZERO(&init_server_read_fds); FD_SET(listen_fd, &init_server_read_fds); - tv.tv_sec = WEBSOCKET_SERVER_CHECK_INTERVAL / 1000; - tv.tv_usec = (WEBSOCKET_SERVER_CHECK_INTERVAL & 1000) * 1000; + tv.tv_sec = WEBSOCKET_ACCEPT_TIMEOUT / 1000; + tv.tv_usec = (WEBSOCKET_ACCEPT_TIMEOUT & 1000) * 1000; r = select(listen_fd + 1, &init_server_read_fds, NULL, NULL, &tv); if (r == -1) { if (errno == EINVAL) { @@ -597,7 +598,7 @@ int websocket_accept_loop(websocket_t *init_server) } if (i == WEBSOCKET_MAX_CLIENT) { timeout_cnt++; - if (timeout_cnt * WEBSOCKET_SERVER_CHECK_INTERVAL >= WEBSOCKET_SERVER_TIMEOUT) { + if (timeout_cnt * WEBSOCKET_ACCEPT_TIMEOUT >= WEBSOCKET_SERVER_TIMEOUT) { WEBSOCKET_DEBUG("websocket server is inactive for %d msec, closing.\n", WEBSOCKET_SERVER_TIMEOUT); r = WEBSOCKET_SUCCESS; goto EXIT_INIT_SERVER; @@ -633,7 +634,7 @@ int websocket_accept_loop(websocket_t *init_server) } } - if (websocket_make_block(accept_fd) != WEBSOCKET_SUCCESS) { + if (websocket_config_socket(accept_fd) != WEBSOCKET_SUCCESS) { if (server_handler->tls_ssl) { free(server_handler->tls_ssl); } @@ -651,7 +652,7 @@ int websocket_accept_loop(websocket_t *init_server) ws_sparam.sched_priority = WEBSOCKET_PRI; pthread_attr_setschedparam(&server_handler->thread_attr, &ws_sparam); pthread_attr_setschedpolicy(&server_handler->thread_attr, WEBSOCKET_SCHED_POLICY); - if (pthread_create(&server_handler->thread_id, &server_handler->thread_attr, (pthread_startroutine_t)websocket_server_start, (pthread_addr_t)server_handler) != 0) { + if (pthread_create(&server_handler->thread_id, &server_handler->thread_attr, (pthread_startroutine_t) websocket_server_start, (pthread_addr_t) server_handler) != 0) { WEBSOCKET_DEBUG("fail to create thread, fd == %d\n", accept_fd); close(accept_fd); if (server_handler->tls_ssl) { @@ -661,7 +662,7 @@ int websocket_accept_loop(websocket_t *init_server) continue; } pthread_setname_np(server_handler->thread_id, "websocket server handler"); - /* Detach thread in order to avoid memory leaks. */ + /* Detach thread in order to avoid memory leaks. */ pthread_detach(server_handler->thread_id); } } @@ -683,7 +684,7 @@ int websocket_listen(int *listen_fd, int port) return WEBSOCKET_SOCKET_ERROR; } - if (setsockopt(*listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, (socklen_t)sizeof(int)) == -1) { + if (setsockopt(*listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, (socklen_t) sizeof(int)) == -1) { WEBSOCKET_DEBUG("setsockopt fail\n"); close(*listen_fd); return WEBSOCKET_SOCKET_ERROR; @@ -748,10 +749,12 @@ websocket_t *websocket_find_table(void) break; } } + if (i == WEBSOCKET_MAX_CLIENT) { WEBSOCKET_DEBUG("websocket clients are too many. limit : %d\n", WEBSOCKET_MAX_CLIENT); return NULL; } + websocket_update_state(&ws_srv_table[i], WEBSOCKET_RUNNING); return &ws_srv_table[i]; @@ -765,7 +768,7 @@ websocket_return_t websocket_client_open(websocket_t *client, char *host, char * struct sched_param ws_sparam; if (client == NULL || host == NULL || port == NULL || path == NULL) { - WEBSOCKET_DEBUG("function returned for null parameter\n"); + WEBSOCKET_DEBUG("NULL parameter\n"); return WEBSOCKET_ALLOCATION_ERROR; } @@ -805,7 +808,7 @@ websocket_return_t websocket_client_open(websocket_t *client, char *host, char * ws_sparam.sched_priority = WEBSOCKET_PRI; pthread_attr_setschedparam(&client->thread_attr, &ws_sparam); pthread_attr_setschedpolicy(&client->thread_attr, WEBSOCKET_SCHED_POLICY); - if (pthread_create(&client->thread_id, &client->thread_attr, (pthread_startroutine_t)websocket_handler, (pthread_addr_t)client) != 0) { + if (pthread_create(&client->thread_id, &client->thread_attr, (pthread_startroutine_t) websocket_handler, (pthread_addr_t) client) != 0) { WEBSOCKET_DEBUG("fail to create websocket client thread\n"); r = WEBSOCKET_ALLOCATION_ERROR; goto EXIT_CLIENT_OPEN; @@ -835,9 +838,10 @@ websocket_return_t websocket_server_open(websocket_t *init_server) int r = WEBSOCKET_SUCCESS; if (init_server == NULL) { - WEBSOCKET_DEBUG("function returned for null parameter\n"); + WEBSOCKET_DEBUG("NULL parameter\n"); return WEBSOCKET_ALLOCATION_ERROR; } + port = init_server->tls_enabled ? 443 : 80; if (websocket_listen(&(init_server->fd), port) != WEBSOCKET_SUCCESS) { @@ -859,7 +863,7 @@ websocket_return_t websocket_server_init(websocket_t *server) struct websocket_info_t *socket_data = NULL; if (server == NULL) { - WEBSOCKET_DEBUG("function returned for null parameter\n"); + WEBSOCKET_DEBUG("NULL parameter\n"); return WEBSOCKET_ALLOCATION_ERROR; } @@ -880,7 +884,7 @@ websocket_return_t websocket_server_init(websocket_t *server) goto EXIT_SERVER_INIT; } - if (websocket_make_block(server->fd) != WEBSOCKET_SUCCESS) { + if (websocket_config_socket(server->fd) != WEBSOCKET_SUCCESS) { r = WEBSOCKET_SOCKET_ERROR; goto EXIT_SERVER_INIT; } @@ -896,6 +900,7 @@ EXIT_SERVER_INIT: mbedtls_ssl_free(server->tls_ssl); free(server->tls_ssl); } + if (server->ctx) { wslay_event_context_free(server->ctx); server->ctx = NULL; @@ -906,19 +911,22 @@ EXIT_SERVER_INIT: return r; } -void websocket_register_cb(websocket_t *websocket, websocket_cb_t *cb) +websocket_return_t websocket_register_cb(websocket_t *websocket, websocket_cb_t *cb) { if (websocket == NULL) { - WEBSOCKET_DEBUG("function returned for null parameter\n"); - } else { - wslay_event_config_set_callbacks(websocket->ctx, cb); + WEBSOCKET_DEBUG("NULL parameter\n"); + return WEBSOCKET_ALLOCATION_ERROR; } + + wslay_event_config_set_callbacks(websocket->ctx, cb); + + return WEBSOCKET_SUCCESS; } websocket_return_t websocket_queue_msg(websocket_t *websocket, websocket_frame_t *tx_frame) { if (websocket == NULL || tx_frame == NULL) { - WEBSOCKET_DEBUG("function returned for null parameter\n"); + WEBSOCKET_DEBUG("NULL parameter\n"); return WEBSOCKET_ALLOCATION_ERROR; } @@ -935,7 +943,7 @@ websocket_return_t websocket_queue_ping(websocket_t *websocket) websocket_frame_t tx_frame; if (websocket == NULL) { - WEBSOCKET_DEBUG("function returned for null parameter\n"); + WEBSOCKET_DEBUG("NULL parameter\n"); return WEBSOCKET_ALLOCATION_ERROR; } @@ -945,7 +953,7 @@ websocket_return_t websocket_queue_ping(websocket_t *websocket) } tx_frame.opcode = WEBSOCKET_PING; - tx_frame.msg = (uint8_t *)"\0"; + tx_frame.msg = (uint8_t *) "\0"; tx_frame.msg_length = strlen((const char *)tx_frame.msg); return wslay_event_queue_msg(websocket->ctx, &tx_frame); @@ -954,7 +962,7 @@ websocket_return_t websocket_queue_ping(websocket_t *websocket) websocket_return_t websocket_queue_close(websocket_t *websocket, const char *close_message) { if (websocket == NULL) { - WEBSOCKET_DEBUG("function returned for null parameter\n"); + WEBSOCKET_DEBUG("NULL parameter\n"); return WEBSOCKET_ALLOCATION_ERROR; } @@ -983,24 +991,30 @@ websocket_return_t websocket_queue_close(websocket_t *websocket, const char *clo return WEBSOCKET_SUCCESS; } -void websocket_update_state(websocket_t *websocket, int state) +websocket_return_t websocket_update_state(websocket_t *websocket, int state) { if (websocket == NULL) { - WEBSOCKET_DEBUG("function returned for null parameter\n"); + WEBSOCKET_DEBUG("NULL parameter\n"); + return WEBSOCKET_ALLOCATION_ERROR; + } + + if (state >= WEBSOCKET_STOP && state < WEBSOCKET_MAX_STATE) { + websocket->state = state; } else { - if (WEBSOCKET_STOP <= state && state < WEBSOCKET_MAX_STATE) { - websocket->state = state; - } else { - WEBSOCKET_DEBUG("function returned for invalid parameter\n"); - } + WEBSOCKET_DEBUG("function returned for invalid parameter\n"); } + + return WEBSOCKET_SUCCESS; } -void websocket_set_error(websocket_t *websocket, int val) +websocket_return_t websocket_set_error(websocket_t *websocket, int val) { if (websocket == NULL) { - WEBSOCKET_DEBUG("function returned for null parameter\n"); - } else { - wslay_event_set_error(websocket->ctx, val); + WEBSOCKET_DEBUG("NULL parameter\n"); + return WEBSOCKET_ALLOCATION_ERROR; } + + wslay_event_set_error(websocket->ctx, val); + + return WEBSOCKET_SUCCESS; } -- 2.7.4