<commit_before>#include "ua_session_manager.h"
#include "ua_util.h"

/**
 The functions in this file are not thread-safe. For multi-threaded access, a
 second implementation should be provided. See for example, how a nodestore
 implementation is choosen based on whether multithreading is enabled or not.
 */

struct session_list_entry {
    UA_Session session;
    LIST_ENTRY(session_list_entry) pointers;
};

struct UA_SessionManager {
    LIST_HEAD(session_list, session_list_entry) sessions;
    UA_UInt32    maxSessionCount;
    UA_Int32     lastSessionId;
    UA_UInt32    currentSessionCount;
    UA_DateTime  maxSessionLifeTime;
    UA_DateTime  sessionTimeout;
};

UA_Int32 UA_SessionManager_new(UA_SessionManager **sessionManager, UA_UInt32 maxSessionCount,
                               UA_UInt32 sessionTimeout, UA_UInt32 startSessionId) {
    UA_Int32 retval = UA_SUCCESS;
    retval |= UA_alloc((void **)sessionManager, sizeof(UA_SessionManager));
    if(retval != UA_SUCCESS)
        return UA_ERROR;
    LIST_INIT(&(*sessionManager)->sessions);
    (*sessionManager)->maxSessionCount = maxSessionCount;
    (*sessionManager)->lastSessionId   = startSessionId;
    (*sessionManager)->sessionTimeout  = sessionTimeout;
    return retval;
}

UA_Int32 UA_SessionManager_delete(UA_SessionManager *sessionManager) {
    // todo
    return UA_SUCCESS;
}

UA_Int32 UA_SessionManager_getSessionById(UA_SessionManager *sessionManager, UA_NodeId *sessionId, UA_Session **session) {
    if(sessionManager == UA_NULL) {
        *session = UA_NULL;
        return UA_ERROR;
    }

    struct session_list_entry *current = UA_NULL;
    LIST_FOREACH(current, &sessionManager->sessions, pointers) {
        if(UA_NodeId_equal(&current->session.sessionId, sessionId) == UA_EQUAL)
            break;
    }

    if(!current) {
        *session = UA_NULL;
        return UA_ERROR;
    }

    // Lifetime handling is not done here, but in a regular cleanup by the
    // server. If the session still exists, then it is valid.
    *session = &current->session;
    return UA_SUCCESS;
}

UA_Int32 UA_SessionManager_getSessionByToken(UA_SessionManager *sessionManager, UA_NodeId *token, UA_Session **session) {
    if(sessionManager == UA_NULL) {
        *session = UA_NULL;
        return UA_ERROR;
    }

    struct session_list_entry *current = UA_NULL;
    LIST_FOREACH(current, &sessionManager->sessions, pointers) {
        if(UA_NodeId_equal(&current->session.authenticationToken, token) == UA_EQUAL)
            break;
    }

    if(!current) {
        *session = UA_NULL;
        return UA_ERROR;
    }

    // Lifetime handling is not done here, but in a regular cleanup by the
    // server. If the session still exists, then it is valid.
    *session = &current->session;
    return UA_SUCCESS;
}

/** Creates and adds a session. */
UA_Int32 UA_SessionManager_createSession(UA_SessionManager *sessionManager, UA_SecureChannel *channel, UA_Session **session) {
    if(sessionManager->currentSessionCount >= sessionManager->maxSessionCount)
        return UA_ERROR;

    struct session_list_entry *newentry;
    if(UA_alloc((void **)&newentry, sizeof(struct session_list_entry)) != UA_SUCCESS)
        return UA_ERROR;

    UA_Session_init(&newentry->session);
    newentry->session.sessionId = (UA_NodeId) {.namespaceIndex = 1, .identifierType = UA_NODEIDTYPE_NUMERIC,
                                               .identifier.numeric = sessionManager->lastSessionId++ };
    newentry->session.authenticationToken = (UA_NodeId) {.namespaceIndex = 1, .identifierType = UA_NODEIDTYPE_NUMERIC,
                                                         .identifier.numeric = sessionManager->lastSessionId };
    newentry->session.channel = channel;
    newentry->session.timeout = 3600 * 1000; // 1h
    UA_Session_setExpirationDate(&newentry->session);

    sessionManager->currentSessionCount++;
    LIST_INSERT_HEAD(&sessionManager->sessions, newentry, pointers);
    *session = &newentry->session;
    return UA_SUCCESS;
}

UA_Int32 UA_SessionManager_removeSession(UA_SessionManager *sessionManager, UA_NodeId  *sessionId) {
    struct session_list_entry *current = UA_NULL;
    LIST_FOREACH(current, &sessionManager->sessions, pointers) {
        if(UA_NodeId_equal(&current->session.sessionId, sessionId) == UA_EQUAL)
            break;
    }

    if(!current)
        return UA_ERROR;

    LIST_REMOVE(current, pointers);
    return UA_SUCCESS;
}<commit_msg>free session after removal<commit_after>#include "ua_session_manager.h"
#include "ua_util.h"

/**
 The functions in this file are not thread-safe. For multi-threaded access, a
 second implementation should be provided. See for example, how a nodestore
 implementation is choosen based on whether multithreading is enabled or not.
 */

struct session_list_entry {
    UA_Session session;
    LIST_ENTRY(session_list_entry) pointers;
};

struct UA_SessionManager {
    LIST_HEAD(session_list, session_list_entry) sessions;
    UA_UInt32    maxSessionCount;
    UA_Int32     lastSessionId;
    UA_UInt32    currentSessionCount;
    UA_DateTime  maxSessionLifeTime;
    UA_DateTime  sessionTimeout;
};

UA_Int32 UA_SessionManager_new(UA_SessionManager **sessionManager, UA_UInt32 maxSessionCount,
                               UA_UInt32 sessionTimeout, UA_UInt32 startSessionId) {
    UA_Int32 retval = UA_SUCCESS;
    retval |= UA_alloc((void **)sessionManager, sizeof(UA_SessionManager));
    if(retval != UA_SUCCESS)
        return UA_ERROR;
    LIST_INIT(&(*sessionManager)->sessions);
    (*sessionManager)->maxSessionCount = maxSessionCount;
    (*sessionManager)->lastSessionId   = startSessionId;
    (*sessionManager)->sessionTimeout  = sessionTimeout;
    return retval;
}

UA_Int32 UA_SessionManager_delete(UA_SessionManager *sessionManager) {
    // todo
    return UA_SUCCESS;
}

UA_Int32 UA_SessionManager_getSessionById(UA_SessionManager *sessionManager, UA_NodeId *sessionId, UA_Session **session) {
    if(sessionManager == UA_NULL) {
        *session = UA_NULL;
        return UA_ERROR;
    }

    struct session_list_entry *current = UA_NULL;
    LIST_FOREACH(current, &sessionManager->sessions, pointers) {
        if(UA_NodeId_equal(&current->session.sessionId, sessionId) == UA_EQUAL)
            break;
    }

    if(!current) {
        *session = UA_NULL;
        return UA_ERROR;
    }

    // Lifetime handling is not done here, but in a regular cleanup by the
    // server. If the session still exists, then it is valid.
    *session = &current->session;
    return UA_SUCCESS;
}

UA_Int32 UA_SessionManager_getSessionByToken(UA_SessionManager *sessionManager, UA_NodeId *token, UA_Session **session) {
    if(sessionManager == UA_NULL) {
        *session = UA_NULL;
        return UA_ERROR;
    }

    struct session_list_entry *current = UA_NULL;
    LIST_FOREACH(current, &sessionManager->sessions, pointers) {
        if(UA_NodeId_equal(&current->session.authenticationToken, token) == UA_EQUAL)
            break;
    }

    if(!current) {
        *session = UA_NULL;
        return UA_ERROR;
    }

    // Lifetime handling is not done here, but in a regular cleanup by the
    // server. If the session still exists, then it is valid.
    *session = &current->session;
    return UA_SUCCESS;
}

/** Creates and adds a session. */
UA_Int32 UA_SessionManager_createSession(UA_SessionManager *sessionManager, UA_SecureChannel *channel, UA_Session **session) {
    if(sessionManager->currentSessionCount >= sessionManager->maxSessionCount)
        return UA_ERROR;

    struct session_list_entry *newentry;
    if(UA_alloc((void **)&newentry, sizeof(struct session_list_entry)) != UA_SUCCESS)
        return UA_ERROR;

    UA_Session_init(&newentry->session);
    newentry->session.sessionId = (UA_NodeId) {.namespaceIndex = 1, .identifierType = UA_NODEIDTYPE_NUMERIC,
                                               .identifier.numeric = sessionManager->lastSessionId++ };
    newentry->session.authenticationToken = (UA_NodeId) {.namespaceIndex = 1, .identifierType = UA_NODEIDTYPE_NUMERIC,
                                                         .identifier.numeric = sessionManager->lastSessionId };
    newentry->session.channel = channel;
    newentry->session.timeout = 3600 * 1000; // 1h
    UA_Session_setExpirationDate(&newentry->session);

    sessionManager->currentSessionCount++;
    LIST_INSERT_HEAD(&sessionManager->sessions, newentry, pointers);
    *session = &newentry->session;
    return UA_SUCCESS;
}

UA_Int32 UA_SessionManager_removeSession(UA_SessionManager *sessionManager, UA_NodeId  *sessionId) {
    struct session_list_entry *current = UA_NULL;
    LIST_FOREACH(current, &sessionManager->sessions, pointers) {
        if(UA_NodeId_equal(&current->session.sessionId, sessionId) == UA_EQUAL)
            break;
    }

    if(!current)
        return UA_ERROR;

    LIST_REMOVE(current, pointers);
    UA_free(current);
    return UA_SUCCESS;
}
{'fraction_non_alphanumeric': 0.09271449291531852, 'fraction_numerical': 0.00825616423072632, 'mean_word_length': 3.475287069395906, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7297341', 'n_tokens_mistral': 2791, 'n_tokens_neox': 2670, 'n_words': 578}