Beispiel #1
0
/**
 * \brief This function tries to handle Tag_Destroy command
 */
int vs_handle_tag_destroy(struct VS_CTX *vs_ctx,
                          struct VSession *vsession,
                          struct Generic_Cmd *tag_destroy)
{
    struct VSNode			*node;
    struct VSTagGroup		*tg;
    struct VSTag			*tag;
    uint32 					node_id = UINT32(tag_destroy->data[0]);
    uint16 					taggroup_id = UINT16(tag_destroy->data[UINT32_SIZE]);
    uint16					tag_id = UINT16(tag_destroy->data[UINT32_SIZE + UINT16_SIZE]);
    int						ret = 0;

    /* Try to find node */
    if((node = vs_node_find(vs_ctx, node_id)) == NULL) {
        v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n",
                    __FUNCTION__, node_id);
        return 0;
    }

    pthread_mutex_lock(&node->mutex);

    /* Node has to be created */
    if(vs_node_is_created(node) != 1) {
        goto end;
    }

    /* Is user owner of this node or can user write to this node? */
    if(vs_node_can_write(vsession, node) != 1) {
        v_print_log(VRS_PRINT_DEBUG_MSG,
                    "%s(): user: %s can't write to node: %d\n",
                    __FUNCTION__,
                    ((struct VSUser *)vsession->user)->username,
                    node->id);
        goto end;
    }

    /* Try to find TagGroup */
    if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) {
        v_print_log(VRS_PRINT_DEBUG_MSG,
                    "%s() tag_group (id: %d) in node (id: %d) not found\n",
                    __FUNCTION__, taggroup_id, node_id);
        goto end;
    }

    /* Try to find Tag */
    if ( (tag = vs_tag_find(tg, tag_id)) == NULL) {
        v_print_log(VRS_PRINT_DEBUG_MSG,
                    "%s() tag (id: %d) in tag_group (id: %d), node (id: %d) not found\n",
                    __FUNCTION__, tag_id, taggroup_id, node_id);
        goto end;
    }

    ret = vs_tag_send_destroy(node, tg, tag);

end:
    pthread_mutex_unlock(&node->mutex);

    return ret;
}
Beispiel #2
0
/**
 * \brief This function handle taggroup_unsubscribe command
 */
int vs_handle_taggroup_unsubscribe(struct VS_CTX *vs_ctx,
		struct VSession *vsession,
		struct Generic_Cmd *taggroup_unsubscribe)
{
	struct VSNode				*node;
	struct VSTagGroup			*tg;
	uint32						node_id = UINT32(taggroup_unsubscribe->data[0]);
	uint16						taggroup_id = UINT16(taggroup_unsubscribe->data[UINT32_SIZE]);
	int							ret = 0;

	/* Try to find node */
	if((node = vs_node_find(vs_ctx, node_id)) == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n",
				__FUNCTION__, node_id);
		return 0;
	}

	pthread_mutex_lock(&node->mutex);

	/* Node has to be created */
	if( vs_node_is_created(node) != 1 ) {
		ret = 0;
	} else {
		/* Try to find TagGroup */
		if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) {
			v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_group (id: %d) in node (id: %d) not found\n",
					__FUNCTION__, taggroup_id, node_id);
			ret = 0;
		} else {
			ret = vs_taggroup_unsubscribe(tg, vsession);
		}
	}

	pthread_mutex_unlock(&node->mutex);

	return ret;
}
Beispiel #3
0
/**
 * \brief This function handle node_subscribe command
 */
int vs_handle_taggroup_subscribe(struct VS_CTX *vs_ctx,
		struct VSession *vsession,
		struct Generic_Cmd *taggroup_subscribe)
{
	struct VSNode	*node;
	uint32			node_id = UINT32(taggroup_subscribe->data[0]);
	uint16			taggroup_id = UINT16(taggroup_subscribe->data[UINT32_SIZE]);
	int				ret = 0;

	/* Try to find node */
	if((node = vs_node_find(vs_ctx, node_id)) == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n",
				__FUNCTION__, node_id);
		return 0;
	}

	pthread_mutex_lock(&node->mutex);

	/* Node has to be created */
	if( vs_node_is_created(node) != 1 ) {
		goto end;
	}

	/* Is user owner of the node or can user read the node? */
	if(vs_node_can_read(vsession, node) == 1) {
		struct VSNodeSubscriber		*node_subscriber;
		struct VSTagGroup			*tg;
		struct VSTag				*tag;
		struct VSEntitySubscriber	*tg_subscriber;
		struct VBucket				*bucket;

		/* Try to find node subscriber */
		node_subscriber = node->node_subs.first;
		while(node_subscriber != NULL) {
			if(node_subscriber->session == vsession) {
				break;
			}
			node_subscriber = node_subscriber->next;
		}

		/* Client has to be subscribed to the node first */
		if(node_subscriber == NULL) {
			v_print_log(VRS_PRINT_DEBUG_MSG,
					"%s(): client has to be subscribed to the node: %d before subscribing to the tag_group: %d\n",
					__FUNCTION__, node_id, taggroup_id);
			goto end;
		}

		/* Try to find TagGroup */
		if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) {
			v_print_log(VRS_PRINT_DEBUG_MSG,
					"%s() tag_group (id: %d) in node (id: %d) not found\n",
					__FUNCTION__, taggroup_id, node_id);
			goto end;
		}

		/* Is Client already subscribed to this tag group? */
		tg_subscriber = tg->tg_subs.first;
		while(tg_subscriber != NULL) {
			if(tg_subscriber->node_sub->session->session_id == vsession->session_id) {
				v_print_log(VRS_PRINT_DEBUG_MSG,
						"%s() client already subscribed to the tag_group (id: %d) in node (id: %d)\n",
						__FUNCTION__, taggroup_id, node_id);
				goto end;
			}
			tg_subscriber = tg_subscriber->next;
		}

		ret = 1;

		/* Add new subscriber to the list of tag group subscribers */
		tg_subscriber = (struct VSEntitySubscriber*)malloc(sizeof(struct VSEntitySubscriber));
		tg_subscriber->node_sub = node_subscriber;
		v_list_add_tail(&tg->tg_subs, tg_subscriber);

		/* Send tag create for all tags in this tag group
		 * TODO: do not send all tags at once, when there is lot of tags in this
		 * tag group. Implement this, when queue limits will be finished. */
		bucket = tg->tags.lb.first;
		while(bucket != NULL) {
			tag = (struct VSTag*)bucket->data;
			if(tag->state == ENTITY_CREATING || tag->state == ENTITY_CREATED) {
				if(vs_tag_send_create(tg_subscriber, node, tg, tag) != 1) {
					ret = 0;
				}
			}
			bucket = bucket->next;
		}
	} else {
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"%s(): user: %s doesn't have permissions to subscribe to taggroup: %d in node: %d\n",
				__FUNCTION__,
				((struct VSUser *)vsession->user)->username,
				taggroup_id, node->id);
	}

end:

	pthread_mutex_unlock(&node->mutex);

	return ret;
}
Beispiel #4
0
/**
 * \brief This function tries to handle node_create command
 */
int vs_handle_taggroup_create(struct VS_CTX *vs_ctx,
		struct VSession *vsession,
		struct Generic_Cmd *taggroup_create_cmd)
{
	struct VSNode			*node;
	struct VSTagGroup		*tg;
	struct VBucket			*vbucket;
	uint32 					node_id = UINT32(taggroup_create_cmd->data[0]);
	uint16 					taggroup_id = UINT16(taggroup_create_cmd->data[UINT32_SIZE]);
	uint16 					type = UINT16(taggroup_create_cmd->data[UINT32_SIZE+UINT16_SIZE]);
	int						ret = 0;

	/* Client has to send taggroup_create command with taggroup_id equal to
	 * the value 0xFFFF */
	if(taggroup_id != VRS_RESERVED_TAGGROUP_ID) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s() taggroup_id: %d is not 0xFFFF\n",
				__FUNCTION__, taggroup_id);
		return 0;
	}

	/* Try to find node */
	if((node = vs_node_find(vs_ctx, node_id)) == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n",
				__FUNCTION__, node_id);
		return 0;
	}

	pthread_mutex_lock(&node->mutex);

	/* Node has to be created */
	if( vs_node_is_created(node) != 1 ) {
		goto end;
	}

	vbucket = node->tag_groups.lb.first;
	/* Check, if there isn't tag group with the same type */
	while(vbucket != NULL) {
		tg = vbucket->data;
		if(tg->custom_type == type) {
			v_print_log(VRS_PRINT_DEBUG_MSG,
					"%s() taggroup type: %d is already used in node: %d\n",
					__FUNCTION__, type, node->id);
			goto end;
		}
		vbucket = vbucket->next;
	}

	/* Is user owner of this node or can user write to this node? */
	if(vs_node_can_write(vsession, node) != 1) {
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"%s(): user: %s can't write to node: %d\n",
				__FUNCTION__,
				((struct VSUser *)vsession->user)->username,
				node->id);
		goto end;
	}

	/* Try to create new tag group */
	tg = vs_taggroup_create(node, VRS_RESERVED_TAGGROUP_ID, type);
	if(tg == NULL) {
		goto end;
	} else {
		struct VSNodeSubscriber *node_subscriber;

		/* Set state for this entity */
		tg->state = ENTITY_CREATING;

		ret = 1;

		/* Send tag group create command to all subscribers to the node
		 * that can read this node */
		for(node_subscriber = node->node_subs.first;
				node_subscriber != NULL;
				node_subscriber = node_subscriber->next)
		{
			if( vs_node_can_read(node_subscriber->session, node) == 1) {
				if(vs_taggroup_send_create(node_subscriber, node, tg) != 1) {
					ret = 0;
				}
			}
		}
	}

end:

	pthread_mutex_unlock(&node->mutex);

	return ret;
}
Beispiel #5
0
/**
 * \brief This function tries to handle Tag_Set_Int8 command
 */
int vs_handle_tag_set(struct VS_CTX *vs_ctx,
                      struct VSession *vsession,
                      struct Generic_Cmd *tag_set,
                      uint8 data_type,
                      uint8 count)
{
    struct VSNode				*node;
    struct VSTagGroup			*tg;
    struct VSTag				*tag;
    struct VSEntitySubscriber	*tg_subscriber;
    uint32 						node_id;
    uint16 						taggroup_id;
    uint16						tag_id;
    int							ret = 0;

    node_id = UINT32(tag_set->data[0]);
    taggroup_id = UINT16(tag_set->data[UINT32_SIZE]);
    tag_id = UINT16(tag_set->data[UINT32_SIZE + UINT16_SIZE]);

    /* Try to find node */
    if((node = vs_node_find(vs_ctx, node_id)) == NULL) {
        v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n",
                    __FUNCTION__, node_id);
        return 0;
    }

    pthread_mutex_lock(&node->mutex);

    /* Node has to be created */
    if(vs_node_is_created(node) != 1) {
        goto end;
    }

    /* Is user owner of this node or can user write to this node? */
    if(vs_node_can_write(vsession, node) != 1) {
        v_print_log(VRS_PRINT_DEBUG_MSG,
                    "%s(): user: %s can't write to node: %d\n",
                    __FUNCTION__,
                    ((struct VSUser *)vsession->user)->username,
                    node->id);
        goto end;
    }

    /* Try to find TagGroup */
    if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) {
        v_print_log(VRS_PRINT_DEBUG_MSG,
                    "%s() tag_group (id: %d) in node (id: %d) not found\n",
                    __FUNCTION__, taggroup_id, node_id);
        goto end;
    }

    /* Try to find Tag */
    if ( (tag = vs_tag_find(tg, tag_id)) == NULL) {
        v_print_log(VRS_PRINT_DEBUG_MSG,
                    "%s() tag (id: %d) in tag_group (id: %d), node (id: %d) not found\n",
                    __FUNCTION__, tag_id, taggroup_id, node_id);
        goto end;
    }

    /* Data type has to match */
    if(data_type != tag->data_type) {
        v_print_log(VRS_PRINT_DEBUG_MSG,
                    "%s() data type (%d) of tag (id: %d) in tg (id: %d) in node (id: %d) does not match data type of received command (%d)\n",
                    __FUNCTION__, tag->data_type, tag_id,
                    taggroup_id, node_id, data_type);
        goto end;
    }

    /* Count of values has to match */
    if(count != tag->count) {
        v_print_log(VRS_PRINT_DEBUG_MSG,
                    "%s() count of values (%d) of tag (id: %d) in tg (id: %d) in node (id: %d) does not match count of values of received command (%d)\n",
                    __FUNCTION__, tag->count, tag_id, taggroup_id, node_id, count);
        goto end;
    }

    /* Set value in tag */
    switch(tag->data_type) {
    case VRS_VALUE_TYPE_UINT8:
        memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], UINT8_SIZE*tag->count);
        break;
    case VRS_VALUE_TYPE_UINT16:
        memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], UINT16_SIZE*tag->count);
        break;
    case VRS_VALUE_TYPE_UINT32:
        memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], UINT32_SIZE*tag->count);
        break;
    case VRS_VALUE_TYPE_UINT64:
        memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], UINT64_SIZE*tag->count);
        break;
    case VRS_VALUE_TYPE_REAL16:
        memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], REAL16_SIZE*tag->count);
        break;
    case VRS_VALUE_TYPE_REAL32:
        memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], REAL32_SIZE*tag->count);
        break;
    case VRS_VALUE_TYPE_REAL64:
        memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], REAL64_SIZE*tag->count);
        break;
    case VRS_VALUE_TYPE_STRING8:
        if(tag->value == NULL) {
            tag->value = strdup(PTR(tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE]));
        } else {
            size_t new_str_len = strlen(PTR(tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE]));
            size_t old_str_len = strlen((char*)tag->value);
            /* Rewrite old string */
            if(new_str_len == old_str_len) {
                strcpy((char*)tag->value, PTR(tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE]));
            } else {
                tag->value = (char*)realloc(tag->value, new_str_len*sizeof(char));
                strcpy((char*)tag->value, PTR(tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE]));
            }
        }
        break;
    default:
        assert(0);
        break;
    }

    ret = 1;

    /* Set this tag as initialized, because value of this tag was set. */
    tag->flag = TAG_INITIALIZED;

    vs_taggroup_inc_version(tg);

    /* Send this tag to all client subscribed to the TagGroup */
    tg_subscriber = tg->tg_subs.first;
    while(tg_subscriber != NULL) {
        if(vs_tag_send_set(tg_subscriber->node_sub->session, tg_subscriber->node_sub->prio, node, tg, tag) != 1) {
            ret = 0;
        }
        tg_subscriber = tg_subscriber->next;
    }

end:
    pthread_mutex_unlock(&node->mutex);

    return ret;
}
Beispiel #6
0
/**
 * \brief This function tries to handle Tag_Create command
 */
int vs_handle_tag_create(struct VS_CTX *vs_ctx,
                         struct VSession *vsession,
                         struct Generic_Cmd *tag_create)
{
    struct VSNode			*node;
    struct VSTagGroup		*tg;
    struct VSTag			*tag;
    struct VBucket			*vbucket;
    struct VSEntitySubscriber	*tg_subscriber;
    uint32 					node_id = UINT32(tag_create->data[0]);
    uint16 					taggroup_id = UINT16(tag_create->data[UINT32_SIZE]);
    uint16					tag_id = UINT16(tag_create->data[UINT32_SIZE + UINT16_SIZE]);
    uint8					data_type = UINT8(tag_create->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE]);
    uint8					count = UINT8(tag_create->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE + UINT8_SIZE]);
    uint16 					type = UINT16(tag_create->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE + UINT8_SIZE + UINT8_SIZE]);
    int						ret = 0;

    /* Try to find node */
    if((node = vs_node_find(vs_ctx, node_id)) == NULL) {
        v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n",
                    __FUNCTION__, node_id);
        return 0;
    }

    pthread_mutex_lock(&node->mutex);

    /* Node has to be created */
    if(vs_node_is_created(node) != 1) {
        goto end;
    }

    /* User has to have permission to write to the node */
    if(vs_node_can_write(vsession, node) != 1) {
        v_print_log(VRS_PRINT_DEBUG_MSG,
                    "%s(): user: %s can't write to node: %d\n",
                    __FUNCTION__,
                    ((struct VSUser *)vsession->user)->username,
                    node->id);
        goto end;
    }

    /* Try to find TagGroup */
    if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) {
        v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_group (id: %d) in node (id: %d) not found\n",
                    __FUNCTION__, taggroup_id, node_id);
        goto end;
    }

    /* Tag Group has to be created too (it can't be in DELETING or DELETED state ) */
    if(!(tg->state == ENTITY_CREATED || tg->state == ENTITY_CREATING)) {
        v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag group (id: %d) from node (id: %d) is not in CREATING or CREATED state: %d\n",
                    __FUNCTION__, tg->id, node->id, tg->state);
        goto end;
    }

    /* Client has to send tag_create command with tag_id equal to
     * the value 0xFFFF */
    if(tag_id != RESERVED_TAG_ID) {
        v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_id: %d is not 0xFFFF\n",
                    __FUNCTION__, tag_id);
        goto end;
    }

    /* Is type of Tag supported? */
    if(!(data_type>VRS_VALUE_TYPE_RESERVED && data_type<=VRS_VALUE_TYPE_STRING8)) {
        v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_type: %d is not supported\n",
                    __FUNCTION__, data_type);
        goto end;
    }

    vbucket = tg->tags.lb.first;
    /* Check, if there isn't tag with the same type */
    while(vbucket != NULL) {
        tag = vbucket->data;
        if(tag->custom_type == type) {
            v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag type: %d is already used in taggroup: %d\n",
                        __FUNCTION__, type, tg->id);
            goto end;
        }
        vbucket = vbucket->next;
    }

    if (v_hash_array_count_items(&tg->tags) > MAX_TAGS_COUNT) {
        v_print_log(VRS_PRINT_DEBUG_MSG, "%s() max number of tags in node: %d tag_group: %d was reached\n",
                    tg->id);
        goto end;
    }

    /* Try to create new tag */
    tag = vs_tag_create(tg, RESERVED_TAG_ID, data_type, count, type);
    if(tag == NULL) {
        goto end;
    }

    ret = 1;

    tag->state = ENTITY_CREATING;

    /* Send TagCreate to all subscribers of tag group */
    tg_subscriber = tg->tg_subs.first;
    while(tg_subscriber != NULL) {
        if(vs_tag_send_create(tg_subscriber, node, tg, tag) != 1) {
            ret = 0;
        }
        tg_subscriber = tg_subscriber->next;
    }

end:
    pthread_mutex_unlock(&node->mutex);

    return ret;
}
Beispiel #7
0
/**
 * \brief This function handle node_subscribe command
 */
int vs_handle_taggroup_subscribe(struct VS_CTX *vs_ctx,
		struct VSession *vsession,
		struct Generic_Cmd *taggroup_subscribe)
{
	struct VSNode	*node;
	uint32			node_id = UINT32(taggroup_subscribe->data[0]);
	uint16			taggroup_id = UINT16(taggroup_subscribe->data[UINT32_SIZE]);
	int				ret = 0;

	/* Try to find node */
	if((node = vs_node_find(vs_ctx, node_id)) == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n",
				__func__, node_id);
		return 0;
	}

	pthread_mutex_lock(&node->mutex);

	/* Node has to be created */
	if( vs_node_is_created(node) != 1 ) {
		goto end;
	}

	/* Is user owner of the node or can user read the node? */
	if(vs_node_can_read(vsession, node) == 1) {
		struct VSNodeSubscriber		*node_subscriber;
		struct VSTagGroup			*tg;
		struct VSTag				*tag;
		struct VSEntitySubscriber	*tg_subscriber;
		struct VBucket				*bucket;

		/* Try to find node subscriber */
		node_subscriber = node->node_subs.first;
		while(node_subscriber != NULL) {
			if(node_subscriber->session == vsession) {
				break;
			}
			node_subscriber = node_subscriber->next;
		}

		/* Client has to be subscribed to the node first */
		if(node_subscriber == NULL) {
			v_print_log(VRS_PRINT_DEBUG_MSG,
					"%s(): client has to be subscribed to the node: %d before subscribing to the tag_group: %d\n",
					__func__, node_id, taggroup_id);
			goto end;
		}

		/* Try to find TagGroup */
		if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) {
			v_print_log(VRS_PRINT_DEBUG_MSG,
					"%s() tag_group (id: %d) in node (id: %d) not found\n",
					__func__, taggroup_id, node_id);
			goto end;
		}

		/* Is Client already subscribed to this tag group? */
		tg_subscriber = tg->tg_subs.first;
		while(tg_subscriber != NULL) {
			if(tg_subscriber->node_sub->session->session_id == vsession->session_id) {
				v_print_log(VRS_PRINT_DEBUG_MSG,
						"%s() client already subscribed to the tag_group (id: %d) in node (id: %d)\n",
						__func__, taggroup_id, node_id);
				goto end;
			}
			tg_subscriber = tg_subscriber->next;
		}

		ret = 1;

		/* Add new subscriber to the list of tag group subscribers */
		tg_subscriber = (struct VSEntitySubscriber*)malloc(sizeof(struct VSEntitySubscriber));
		tg_subscriber->node_sub = node_subscriber;
		v_list_add_tail(&tg->tg_subs, tg_subscriber);

		/* Try to send tag_create for all tags in this tag group */
		bucket = tg->tags.lb.first;
		while(bucket != NULL) {
			tag = (struct VSTag*)bucket->data;
			vs_tag_send_create(tg_subscriber, node, tg, tag);
			/* When TCP/WebSocket is used and tag is initialized, then it
			 * is possible (necessary) to send value too. */
			if( ((vsession->flags & VRS_TP_TCP) ||
					(vsession->flags & VRS_TP_WEBSOCKET)) &&
					(tag->flag & TAG_INITIALIZED))
			{
				vs_tag_send_set(vsession, node_subscriber->prio, node, tg, tag);
			}
			bucket = bucket->next;
		}
	} else {
		v_print_log(VRS_PRINT_DEBUG_MSG,
				"%s(): user: %s doesn't have permissions to subscribe to taggroup: %d in node: %d\n",
				__func__,
				((struct VSUser *)vsession->user)->username,
				taggroup_id, node->id);
	}

end:

	pthread_mutex_unlock(&node->mutex);

	return ret;
}