7 n__user_8c
gullradriel edited this page 2026-10-29 20:54:40 +01:00

src/n_user.c

Network user handling functions. More...

Detailed Description

Network user handling functions.

Author: Castagnier Mickael

Version: 1.0

Date: 20/02/2006

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#include "nilorea/n_user.h"

N_USERLIST* userlist_new(int max) {
    N_USERLIST* ulist = NULL;
    __n_assert(max > 0, return NULL);
    Malloc(ulist, N_USERLIST, 1);
    __n_assert(ulist, return NULL);

    Malloc(ulist->list, N_USER, (size_t)max);
    __n_assert(ulist->list, Free(ulist); return NULL);

    ulist->max = max;
    ulist->highter = -1;
    for (int it = 0; it < max; it++) {
        ulist->list[it].state = 0;
        ulist->list[it].nb_rec_pos = 10;
        ulist->list[it].only_last_pos = 1;
        ulist->list[it].id = -1;
        Malloc(ulist->list[it].last_positions, VECTOR3D, 10);
        ulist->list[it].netw_waitlist = new_generic_list(MAX_LIST_ITEMS);
        memset(ulist->list[it].position, 0, 3 * sizeof(double));
        ulist->list[it].netw = NULL;
        memset(ulist->list[it].name, 0, 1024);
        ulist->list[it].netw = NULL;
    }

    init_lock(ulist->user_rwbolt);

    return ulist;
} /* userlist_new() */

int userlist_set_position_behavior(N_USERLIST* ulist, int id, int nb_rec_pos, int only_last_pos) {
    __n_assert(ulist, return FALSE);
    /* nb_rec_pos must be at least 1 */
    if (nb_rec_pos < 1) return FALSE;
    /* only_last_pos is a boolean: 0 or 1 */
    if (only_last_pos < 0 || only_last_pos > 1) return FALSE;

    read_lock(ulist->user_rwbolt);
    if (id < 0 || id >= ulist->max) {
        unlock(ulist->user_rwbolt);
        return FALSE;
    }
    /* user slot must be active */
    if (ulist->list[id].state == 0) {
        unlock(ulist->user_rwbolt);
        return FALSE;
    }
    unlock(ulist->user_rwbolt);

    write_lock(ulist->user_rwbolt);
    ulist->list[id].nb_rec_pos = nb_rec_pos;
    ulist->list[id].only_last_pos = only_last_pos;
    if (only_last_pos) {
        if (Realloc(ulist->list[id].last_positions, VECTOR3D, 1) == FALSE) {
            n_log(LOG_ERR, "could not resize to only_last_pos VECTOR3D");
            unlock(ulist->user_rwbolt);
            return FALSE;
        }
    } else {
        if (Realloc(ulist->list[id].last_positions, VECTOR3D, (size_t)nb_rec_pos) == FALSE) {
            n_log(LOG_ERR, "could not resize to %d VECTOR3D", nb_rec_pos);
            unlock(ulist->user_rwbolt);
            return FALSE;
        }
        /* nb_rec_pos is already set correctly above; do not overwrite it */
    }
    unlock(ulist->user_rwbolt);

    return TRUE;
} /* userlist_set_position_behavior() */

int userlist_add_user(N_USERLIST* ulist, NETWORK* netw) {
    __n_assert(ulist, return -1);
    __n_assert(netw, return -1);

    int it = -1;
    write_lock(ulist->user_rwbolt);
    do {
        it++;
    } while (it < ulist->max && ulist->list[it].state != 0);
    if (it < ulist->max) {
        ulist->list[it].state = 1;
        ulist->list[it].netw = netw;
        if (it > ulist->highter)
            ulist->highter = it;
        unlock(ulist->user_rwbolt);
        return it;
    }
    unlock(ulist->user_rwbolt);
    return -1;
} /* userlist_add_user() */

int userlist_del_user(N_USERLIST* ulist, int id) {
    __n_assert(ulist, return FALSE);
    __n_assert(id >= 0, return FALSE);

    write_lock(ulist->user_rwbolt);
    if (id >= ulist->max) {
        unlock(ulist->user_rwbolt);
        return FALSE;
    }
    if (ulist->list[id].state == 0) {
        unlock(ulist->user_rwbolt);
        return FALSE;
    }
    ulist->list[id].state = 0;
    ulist->list[id].nb_rec_pos = 1;
    ulist->list[id].only_last_pos = 1;
    ulist->list[id].id = -1;
    if (Realloc(ulist->list[id].last_positions, VECTOR3D, 1) == FALSE) {
        n_log(LOG_ERR, "couldn't resize to 1 element");
    }
    list_empty(ulist->list[id].netw_waitlist);
    memset(ulist->list[id].position, 0, 3 * sizeof(double));
    ulist->list[id].netw = NULL;
    memset(ulist->list[id].name, 0, 1024);

    if (id >= ulist->highter) {
        int it = id;
        while (it >= 0) {
            if (ulist->list[it].state == 1) {
                ulist->highter = it;
                break;
            }
            it--;
        }
        if (it < 0) ulist->highter = -1;
    }
    unlock(ulist->user_rwbolt);
    return TRUE;
} /* userlist_del_user() */

int userlist_add_msg_to_ex(N_USERLIST* ulist, N_STR* msg, int mode, int id) {
    __n_assert(ulist, return FALSE);
    __n_assert(msg, return FALSE);

    switch (mode) {
        case (USERLIST_ALL):
            read_lock(ulist->user_rwbolt);
            for (int it = 0; it <= ulist->highter; it++) {
                if (ulist->list[it].state == 1)
                    netw_add_msg(ulist->list[it].netw, nstrdup(msg));
            }
            unlock(ulist->user_rwbolt);
            break;
        case (USERLIST_ALL_EXCEPT):
            __n_assert(id >= 0, return FALSE);
            read_lock(ulist->user_rwbolt);
            for (int it = 0; it <= ulist->highter; it++) {
                if (it == id)
                    continue;
                if (ulist->list[it].state == 1)
                    netw_add_msg(ulist->list[it].netw, nstrdup(msg));
            }
            unlock(ulist->user_rwbolt);
            break;
        default:
        case (USERLIST_ONE):
            __n_assert(id >= 0, return FALSE);

            read_lock(ulist->user_rwbolt);
            netw_add_msg(ulist->list[id].netw, msg);
            unlock(ulist->user_rwbolt);
            break;
    }
    return TRUE;
} /* userlist_add_msg_to_ex() */

int userlist_add_msg_to(N_USERLIST* ulist, N_STR* msg, int id) {
    return userlist_add_msg_to_ex(ulist, msg, USERLIST_ONE, id);
} /* userlist_add_msg_to() */

int userlist_add_msg_to_all(N_USERLIST* ulist, N_STR* msg) {
    return userlist_add_msg_to_ex(ulist, msg, USERLIST_ALL, -1);
} /* userlist_add_msg_to_all() */

int userlist_add_msg_to_all_except(N_USERLIST* ulist, N_STR* msg, int id) {
    return userlist_add_msg_to_ex(ulist, msg, USERLIST_ALL_EXCEPT, id);
} /* userlist_add_msg_to_all_except() */

int userlist_destroy(N_USERLIST** ulist) {
    __n_assert(ulist && (*ulist), return FALSE);

    write_lock((*ulist)->user_rwbolt);
    for (int it = 0; it < (*ulist)->max; it++) {
        Free((*ulist)->list[it].last_positions);
        list_destroy(&(*ulist)->list[it].netw_waitlist);
    }
    Free((*ulist)->list);
    unlock((*ulist)->user_rwbolt);

    pthread_rwlock_destroy(&(*ulist)->user_rwbolt);
    Free((*ulist));

    return TRUE;
} /* userlist_destroy() */

int userlist_user_add_waiting_msg(N_USERLIST* ulist, int id, N_STR* netmsg) {
    __n_assert(ulist, return FALSE);
    __n_assert(netmsg, return FALSE);
    __n_assert(id >= 0, return FALSE);

    int ret = FALSE;

    write_lock(ulist->user_rwbolt);
    if (id <= ulist->highter) {
        if (ulist->list[id].state == 1) {
            ret = list_push(ulist->list[id].netw_waitlist, netmsg, NULL);
        }
    }
    unlock(ulist->user_rwbolt);
    return ret;
} /* userlist_user_add_waiting_msg() */

int userlist_user_send_waiting_msgs(N_USERLIST* ulist, int id) {
    __n_assert(ulist, return FALSE);
    __n_assert(id >= 0, return FALSE);

    write_lock(ulist->user_rwbolt);
    if (id <= ulist->highter) {
        if (ulist->list[id].state == 1) {
            list_foreach(node, ulist->list[id].netw_waitlist) {
                N_STR* netmsg = (N_STR*)node->ptr;
                netw_add_msg(ulist->list[id].netw, netmsg);
            }
            list_empty(ulist->list[id].netw_waitlist);
        }
    }
    unlock(ulist->user_rwbolt);
    return TRUE;
} /* userlist_user_send_waiting_msgs() */

int userlist_send_waiting_msgs(N_USERLIST* ulist) {
    __n_assert(ulist, return FALSE);

    write_lock(ulist->user_rwbolt);
    for (int id = 0; id <= ulist->highter; id++) {
        if (ulist->list[id].state == 1) {
            list_foreach(node, ulist->list[id].netw_waitlist) {
                N_STR* netmsg = (N_STR*)node->ptr;
                netw_add_msg(ulist->list[id].netw, netmsg);
            }
            list_empty(ulist->list[id].netw_waitlist);
        }
    }
    unlock(ulist->user_rwbolt);
    return TRUE;
} /* userlist_send_waiting_msgs() */