Fix timing issue
[platform/core/api/vine.git] / plugins / libwebsockets / libwebsockets-plugin.cpp
index f9a5112..096fcf3 100755 (executable)
@@ -54,6 +54,7 @@ typedef struct {
        struct lws_vhost *vh;
        bool is_server;
        bool close_requested;
+       bool destroy_requested;
        int curr_conn;
        int max_conn;
 
@@ -71,11 +72,13 @@ typedef enum {
        WEBSOCKET_OP_CONNECT,
        WEBSOCKET_OP_WRITE,
        WEBSOCKET_OP_TERMINATE,
+       WEBSOCKET_OP_DESTROY,
 } websocket_op_code_e;
 
 typedef struct {
        websocket_op_code_e code;
        websocket_s *ws;
+       struct lws_vhost *vh;
        int addr_family;
        char *ip; // connect only
        int port; // open, connect only
@@ -227,10 +230,9 @@ static void _notify_websocket_op_request()
 }
 
 static int _add_websocket_op_request(websocket_op_code_e code,
-               websocket_s *ws, int addr_family,
+               websocket_s *ws, struct lws_vhost *vh, int addr_family,
                const char *ip, int port, const char *iface_name,
-               int max_conn,
-               vine_dp_ssl *ssl)
+               int max_conn, vine_dp_ssl *ssl)
 {
        websocket_op_s *op = (websocket_op_s *)calloc(1, sizeof(websocket_op_s));
        if (!op)
@@ -238,6 +240,7 @@ static int _add_websocket_op_request(websocket_op_code_e code,
 
        op->code = code;
        op->ws = ws;
+       op->vh = vh;
        op->addr_family = addr_family;
        op->ip = STRDUP(ip);
        op->port = port;
@@ -268,13 +271,53 @@ static void _del_websocket_op_request(websocket_op_s *op)
        free(op);
 }
 
-static void _process_pending_destroy(void)
+static void _process_pending_destroy(struct lws_vhost *vh)
 {
        VINE_LOGD("Process pending destroy");
+       if (!vh)
+               return;
+
+       const struct lws_protocols *protocol = lws_vhost_name_to_protocol(vh,
+                       VINE_PROTOCOL_NAME);
+       if (!protocol)
+               return;
+
+       lws_callback_all_protocol_vhost_args(vh, protocol, LWS_CALLBACK_USER, NULL, 0);
+       listen_vh_list.erase(vh);
+       lws_vhost_destroy(vh);
+       VINE_LOGI("vh[%p] is destroyed", vh);
+
        while (!lws_service_adjust_timeout(g_context, 1, 0))
                lws_service_tsi(g_context, -1, 0);
 }
 
+
+static void _destroy_websocket(websocket_s *ws)
+{
+       if (!ws)
+               return;
+
+       VINE_LOGD("ws[%s] is destroyed.", ws);
+
+       ws->wsi = NULL;
+       ws->vh = NULL;
+       ws->user = NULL;
+
+       free(ws->host_name);
+       ws->host_name = NULL;
+       free(ws->token);
+       ws->token = NULL;
+       ws->token_len = 0;
+
+       delete ws->recv_buffer;
+       delete ws->write_buffer;
+
+       ws->recv_buffer = NULL;
+       ws->write_buffer = NULL;
+
+       free(ws);
+}
+
 static void _process_websocket_op_request(void)
 {
        RET_IF(op_queue.empty(), "operation queue is NULL");
@@ -299,7 +342,10 @@ static void _process_websocket_op_request(void)
                _request_write(op->ws);
                break;
        case WEBSOCKET_OP_TERMINATE:
-               _process_pending_destroy();
+               _process_pending_destroy(op->vh);
+               break;
+       case WEBSOCKET_OP_DESTROY:
+               _destroy_websocket(op->ws);
                break;
        default:
                break;
@@ -570,7 +616,7 @@ static int _websocket_protocol_cb(struct lws *wsi,
        /* --- client callbacks --- */
        case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
                VINE_LOGI("Failed connection request to server.");
-               if (ws && g_callbacks.connected_cb)
+               if (ws && !ws->destroy_requested && g_callbacks.connected_cb)
                        _invoke_connected_cb(wsi, false, ws->user);
                break;
 
@@ -591,7 +637,7 @@ static int _websocket_protocol_cb(struct lws *wsi,
 
        case LWS_CALLBACK_CLIENT_ESTABLISHED:
                VINE_LOGI("Connected with server.");
-               if (ws && g_callbacks.connected_cb)
+               if (ws && !ws->destroy_requested && g_callbacks.connected_cb)
                        _invoke_connected_cb(wsi, true, ws->user);
                break;
 
@@ -604,7 +650,8 @@ static int _websocket_protocol_cb(struct lws *wsi,
                size_t total_len = _save_data(ws, in, len,
                                lws_is_first_fragment(wsi),
                                lws_is_final_fragment(wsi));
-               if (lws_is_final_fragment(wsi) && g_callbacks.received_cb)
+               if (lws_is_final_fragment(wsi)
+                               && !ws->destroy_requested && g_callbacks.received_cb)
                        g_callbacks.received_cb(total_len, ws->user);
                break;
        }
@@ -620,6 +667,11 @@ static int _websocket_protocol_cb(struct lws *wsi,
                        return -1;
                }
 
+               if (ws->destroy_requested) {
+                       VINE_LOGI("ws[%p] will be destroyed.", ws);
+                       return -1;
+               }
+
                VINE_LOGI("Writeable to server.");
                n = _write_data(ws);
                if (g_callbacks.written_cb)
@@ -629,7 +681,8 @@ static int _websocket_protocol_cb(struct lws *wsi,
        case LWS_CALLBACK_CLIENT_CLOSED:
                VINE_LOGI("Connected server is closed.");
                // call terminated_cb() when close isn't requested only.
-               if (ws && !ws->close_requested && g_callbacks.terminated_cb)
+               if (ws && !ws->close_requested
+                               && !ws->destroy_requested && g_callbacks.terminated_cb)
                        g_callbacks.terminated_cb(ws->user);
                break;
 
@@ -759,7 +812,6 @@ static void _open_server(websocket_s *ws, int addr_family,
                return;
        }
 
-       //listen_vh_list.insert((void *)ws->vh);
        listen_vh_list.insert(ws->vh);
 
        void *user_data = lws_protocol_vh_priv_zalloc(ws->vh, protocols, sizeof(websocket_s));
@@ -781,7 +833,8 @@ static int websocket_open(vine_dp_plugin_h handle,
        ws->is_server = true;
        VINE_LOGD("ws[%p]", ws);
        if (_add_websocket_op_request(WEBSOCKET_OP_OPEN,
-                               (websocket_s *)handle, addr_family, NULL, port, iface_name, max_conn, &ssl) < 0)
+                               (websocket_s *)handle, NULL,
+                               addr_family, NULL, port, iface_name, max_conn, &ssl) < 0)
                return VINE_DATA_PATH_ERROR_OPERATION_FAILED;
 
        _notify_websocket_op_request();
@@ -826,7 +879,8 @@ static int websocket_connect(vine_dp_plugin_h handle,
        RET_VAL_IF(!g_context, VINE_DATA_PATH_ERROR_INVALID_OPERATION, "g_context is NULL");
 
        if (_add_websocket_op_request(WEBSOCKET_OP_CONNECT,
-                               (websocket_s *)handle, addr_family, ip, port, iface_name, 0, &ssl) < 0)
+                               (websocket_s *)handle, NULL,
+                               addr_family, ip, port, iface_name, 0, &ssl) < 0)
                return VINE_DATA_PATH_ERROR_OPERATION_FAILED;
 
        _notify_websocket_op_request();
@@ -983,7 +1037,8 @@ static int websocket_write(vine_dp_plugin_h handle, unsigned char *buf, size_t l
        ws->write_buffer->push(wd);
        VINE_LOGD("websocket_data[%p] is pushed to write_buffer. len[%d]", wd, len);
 
-       if (_add_websocket_op_request(WEBSOCKET_OP_WRITE, ws, 0, NULL, -1, NULL, 0, NULL) < 0)
+       if (_add_websocket_op_request(WEBSOCKET_OP_WRITE, ws, NULL,
+                               0, NULL, -1, NULL, 0, NULL) < 0)
                return VINE_DATA_PATH_ERROR_OPERATION_FAILED;
 
        _notify_websocket_op_request();
@@ -996,22 +1051,17 @@ static int websocket_close(vine_dp_plugin_h handle)
        RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "plugin handle is NULL");
        websocket_s *ws = (websocket_s *)handle;
 
+       if (ws->close_requested) {
+               VINE_LOGI("Already requested.");
+               return VINE_DATA_PATH_ERROR_NONE;
+       }
+
+       VINE_LOGD("ws[%p] will be closed.", ws);
        ws->close_requested = true;
        if (ws->is_server) {
-               const struct lws_protocols *protocol = lws_vhost_name_to_protocol(ws->vh,
-                               VINE_PROTOCOL_NAME);
-               if (!protocol)
-                       return VINE_DATA_PATH_ERROR_OPERATION_FAILED;
-
-               lws_callback_all_protocol_vhost_args(ws->vh, protocol, LWS_CALLBACK_USER, NULL, 0);
-               listen_vh_list.erase(ws->vh);
-               lws_vhost_destroy(ws->vh);
-               ws->vh = NULL;
-
                _add_websocket_op_request(WEBSOCKET_OP_TERMINATE,
-                                       ws, 0, NULL, 0, NULL, 0, NULL);
+                               ws, ws->vh, 0, NULL, 0, NULL, 0, NULL);
                _notify_websocket_op_request();
-
                return VINE_DATA_PATH_ERROR_NONE;
        }
 
@@ -1058,8 +1108,6 @@ static int websocket_create(vine_dp_plugin_h *handle, void *plugin_data, void *u
                (websocket_s *)plugin_data : (websocket_s *)calloc(1, sizeof(websocket_s));
        RET_VAL_IF(ws == NULL, VINE_DATA_PATH_ERROR_OUT_OF_MEMORY, "Out of memory");
 
-       VINE_LOGD("ws[%p], user[%p]", ws, user);
-
        ws->close_requested = false;
        ws->curr_conn = 0;
        ws->max_conn = 0;
@@ -1075,27 +1123,16 @@ static int websocket_destroy(vine_dp_plugin_h handle)
 {
        RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
 
-       VINE_LOGE("ws[%p] is destroyed", handle);
-       websocket_s *ws = (websocket_s *)handle;
-
-       ws->wsi = NULL;
-       ws->vh = NULL;
-       ws->user = NULL;
 
-       free(ws->host_name);
-       ws->host_name = NULL;
-       free(ws->token);
-       ws->token = NULL;
-       ws->token_len = 0;
-
-       delete ws->recv_buffer;
-       delete ws->write_buffer;
-
-       ws->recv_buffer = NULL;
-       ws->write_buffer = NULL;
-
-       free(ws);
+       websocket_s *ws = (websocket_s *)handle;
+       if (ws->destroy_requested) {
+               VINE_LOGD("Already requested.");
+               return VINE_DATA_PATH_ERROR_NONE;
+       }
 
+       ws->destroy_requested = true;
+       _add_websocket_op_request(WEBSOCKET_OP_DESTROY, ws, NULL, 0, NULL, 0, NULL, 0, NULL);
+       _notify_websocket_op_request();
        return VINE_DATA_PATH_ERROR_NONE;
 }