/[LeafOK_CVS]/lbbs/src/user_list.c
ViewVC logotype

Annotation of /lbbs/src/user_list.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.46 - (hide annotations)
Thu Dec 18 02:56:01 2025 UTC (2 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.45: +5 -15 lines
Content type: text/x-csrc
Refine with log_debug()

1 sysadm 1.26 /* SPDX-License-Identifier: GPL-3.0-or-later */
2     /*
3     * user_list
4     * - data model and basic operations of (online) user list
5     *
6 sysadm 1.28 * Copyright (C) 2004-2025 Leaflet <leaflet@leafok.com>
7 sysadm 1.26 */
8 sysadm 1.1
9 sysadm 1.32 #ifdef HAVE_CONFIG_H
10     #include "config.h"
11     #endif
12    
13 sysadm 1.1 #include "common.h"
14     #include "database.h"
15     #include "log.h"
16 sysadm 1.6 #include "trie_dict.h"
17 sysadm 1.1 #include "user_list.h"
18 sysadm 1.18 #include "user_stat.h"
19 sysadm 1.1 #include <errno.h>
20 sysadm 1.39 #include <fcntl.h>
21 sysadm 1.1 #include <stdlib.h>
22     #include <string.h>
23     #include <time.h>
24     #include <sys/mman.h>
25 sysadm 1.2 #include <sys/param.h>
26 sysadm 1.42 #include <sys/stat.h>
27    
28     #ifdef HAVE_SYSTEM_V
29 sysadm 1.1 #include <sys/sem.h>
30    
31 sysadm 1.42 #ifdef _SEM_SEMUN_UNDEFINED
32 sysadm 1.1 union semun
33     {
34 sysadm 1.6 int val; /* Value for SETVAL */
35     struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
36     unsigned short *array; /* Array for GETALL, SETALL */
37     struct seminfo *__buf; /* Buffer for IPC_INFO
38 sysadm 1.42 (Linux-specific) */
39 sysadm 1.1 };
40 sysadm 1.42 #endif // #ifdef _SEM_SEMUN_UNDEFINED
41    
42     #else
43     #include <semaphore.h>
44     #endif
45 sysadm 1.1
46 sysadm 1.29 enum _user_list_constant_t
47     {
48     USER_LIST_TRY_LOCK_WAIT_TIME = 1, // second
49     USER_LIST_TRY_LOCK_TIMES = 10,
50 sysadm 1.44 USER_LIST_DEAD_LOCK_TIMEOUT = 15, // second
51 sysadm 1.29 };
52 sysadm 1.1
53     struct user_list_pool_t
54     {
55 sysadm 1.39 size_t shm_size;
56 sysadm 1.42 #ifndef HAVE_SYSTEM_V
57     sem_t sem;
58 sysadm 1.43 uint16_t read_lock_count;
59     uint16_t write_lock_count;
60 sysadm 1.42 #else
61 sysadm 1.6 int semid;
62 sysadm 1.42 #endif
63 sysadm 1.6 USER_LIST user_list[2];
64 sysadm 1.37 int user_list_index_current;
65     int user_list_index_new;
66 sysadm 1.6 USER_ONLINE_LIST user_online_list[2];
67 sysadm 1.37 int user_online_list_index_current;
68     int user_online_list_index_new;
69 sysadm 1.18 USER_STAT_MAP user_stat_map;
70 sysadm 1.24 int user_login_count;
71 sysadm 1.1 };
72     typedef struct user_list_pool_t USER_LIST_POOL;
73    
74 sysadm 1.41 static char user_list_shm_name[FILE_NAME_LEN];
75 sysadm 1.1 static USER_LIST_POOL *p_user_list_pool = NULL;
76 sysadm 1.6 static TRIE_NODE *p_trie_action_dict = NULL;
77    
78     typedef struct user_action_map_t
79     {
80     char name[BBS_current_action_max_len + 1];
81     char title[BBS_current_action_max_len + 1];
82     } USER_ACTION_MAP;
83    
84     const USER_ACTION_MAP user_action_map[] =
85     {
86     {"ARTICLE_FAVOR", "浏览收藏"},
87     {"BBS_NET", "站点穿梭"},
88     {"CHICKEN", "电子小鸡"},
89     {"EDIT_ARTICLE", "修改文章"},
90 sysadm 1.7 {"LOGIN", "进入大厅"},
91 sysadm 1.6 {"MENU", "菜单选择"},
92     {"POST_ARTICLE", "撰写文章"},
93     {"REPLY_ARTICLE", "回复文章"},
94 sysadm 1.45 {"TOP10_MENU", "十大热门"},
95 sysadm 1.6 {"USER_LIST", "查花名册"},
96     {"USER_ONLINE", "环顾四周"},
97     {"VIEW_ARTICLE", "阅读文章"},
98 sysadm 1.7 {"VIEW_FILE", "查看文档"},
99     {"WWW", "Web浏览"}};
100 sysadm 1.6
101 sysadm 1.7 const int user_action_map_size = sizeof(user_action_map) / sizeof(USER_ACTION_MAP);
102 sysadm 1.1
103 sysadm 1.39 static int user_list_try_rd_lock(int wait_sec);
104     static int user_list_try_rw_lock(int wait_sec);
105     static int user_list_rd_unlock(void);
106     static int user_list_rw_unlock(void);
107     static int user_list_rd_lock(void);
108     static int user_list_rw_lock(void);
109 sysadm 1.44 #ifndef HAVE_SYSTEM_V
110     static int user_list_reset_lock(void);
111     #endif
112 sysadm 1.17
113 sysadm 1.6 static int user_list_load(MYSQL *db, USER_LIST *p_list);
114 sysadm 1.25 static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_online_list);
115 sysadm 1.24 static int user_login_count_load(MYSQL *db);
116 sysadm 1.6
117 sysadm 1.8 static int user_info_index_uid_comp(const void *ptr1, const void *ptr2)
118     {
119     const USER_INFO_INDEX_UID *p1 = ptr1;
120     const USER_INFO_INDEX_UID *p2 = ptr2;
121    
122     if (p1->uid < p2->uid)
123     {
124     return -1;
125     }
126     else if (p1->uid > p2->uid)
127     {
128     return 1;
129     }
130 sysadm 1.10 else if (p1->id < p2->id)
131     {
132     return -1;
133     }
134     else if (p1->id > p2->id)
135     {
136     return 1;
137     }
138 sysadm 1.8 return 0;
139     }
140    
141 sysadm 1.1 int user_list_load(MYSQL *db, USER_LIST *p_list)
142     {
143 sysadm 1.6 MYSQL_RES *rs = NULL;
144     MYSQL_ROW row;
145     char sql[SQL_BUFFER_LEN];
146     int ret = 0;
147 sysadm 1.15 int i;
148     int j;
149     int32_t last_uid;
150     size_t intro_buf_offset;
151 sysadm 1.14 size_t intro_len;
152 sysadm 1.6
153     if (db == NULL || p_list == NULL)
154     {
155     log_error("NULL pointer error\n");
156     return -1;
157     }
158    
159 sysadm 1.10 if (p_list->user_count > 0)
160     {
161     last_uid = p_list->users[p_list->user_count - 1].uid;
162     }
163 sysadm 1.15 else
164     {
165     last_uid = -1;
166     }
167 sysadm 1.10
168 sysadm 1.6 snprintf(sql, sizeof(sql),
169 sysadm 1.14 "SELECT user_list.UID AS UID, username, nickname, gender, gender_pub, life, exp, visit_count, "
170 sysadm 1.21 "UNIX_TIMESTAMP(signup_dt), UNIX_TIMESTAMP(last_login_dt), UNIX_TIMESTAMP(last_logout_dt), "
171     "UNIX_TIMESTAMP(birthday), `introduction` "
172 sysadm 1.6 "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "
173     "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "
174 sysadm 1.8 "WHERE enable ORDER BY username");
175 sysadm 1.6
176     if (mysql_query(db, sql) != 0)
177     {
178     log_error("Query user info error: %s\n", mysql_error(db));
179     ret = -1;
180     goto cleanup;
181     }
182    
183     if ((rs = mysql_use_result(db)) == NULL)
184     {
185     log_error("Get user info data failed\n");
186     ret = -1;
187     goto cleanup;
188     }
189    
190 sysadm 1.14 intro_buf_offset = 0;
191 sysadm 1.6 i = 0;
192     while ((row = mysql_fetch_row(rs)))
193     {
194 sysadm 1.8 // record
195     p_list->users[i].id = i;
196 sysadm 1.6 p_list->users[i].uid = atoi(row[0]);
197     strncpy(p_list->users[i].username, row[1], sizeof(p_list->users[i].username) - 1);
198     p_list->users[i].username[sizeof(p_list->users[i].username) - 1] = '\0';
199     strncpy(p_list->users[i].nickname, row[2], sizeof(p_list->users[i].nickname) - 1);
200     p_list->users[i].nickname[sizeof(p_list->users[i].nickname) - 1] = '\0';
201     p_list->users[i].gender = row[3][0];
202     p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));
203     p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));
204     p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));
205 sysadm 1.14 p_list->users[i].visit_count = (row[7] == NULL ? 0 : atoi(row[7]));
206     p_list->users[i].signup_dt = (row[8] == NULL ? 0 : atol(row[8]));
207     p_list->users[i].last_login_dt = (row[9] == NULL ? 0 : atol(row[9]));
208 sysadm 1.21 p_list->users[i].last_logout_dt = (row[10] == NULL ? 0 : atol(row[10]));
209 sysadm 1.31 p_list->users[i].birthday = (row[11] == NULL ? 0 : atol(row[11]));
210 sysadm 1.21 intro_len = strlen((row[12] == NULL ? "" : row[12]));
211 sysadm 1.14 if (intro_len >= sizeof(p_list->user_intro_buf) - 1 - intro_buf_offset)
212     {
213     log_error("OOM for user introduction: len=%d, i=%d\n", intro_len, i);
214     break;
215     }
216     memcpy(p_list->user_intro_buf + intro_buf_offset,
217 sysadm 1.21 (row[12] == NULL ? "" : row[12]),
218 sysadm 1.14 intro_len + 1);
219     p_list->users[i].intro = p_list->user_intro_buf + intro_buf_offset;
220     intro_buf_offset += (intro_len + 1);
221 sysadm 1.6
222     i++;
223     if (i >= BBS_max_user_count)
224     {
225     log_error("Too many users, exceed limit %d\n", BBS_max_user_count);
226     break;
227     }
228     }
229     mysql_free_result(rs);
230     rs = NULL;
231 sysadm 1.1
232 sysadm 1.10 if (i != p_list->user_count || p_list->users[i - 1].uid != last_uid) // Count of users changed
233     {
234 sysadm 1.15 // Rebuild index
235     for (j = 0; j < i; j++)
236     {
237     p_list->index_uid[j].uid = p_list->users[j].uid;
238     p_list->index_uid[j].id = j;
239     }
240    
241     qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
242 sysadm 1.12
243 sysadm 1.46 log_debug("Rebuild index of %d users, last_uid=%d\n", i, p_list->users[i - 1].uid);
244 sysadm 1.10 }
245    
246 sysadm 1.6 p_list->user_count = i;
247 sysadm 1.1
248 sysadm 1.46 log_debug("Loaded %d users\n", p_list->user_count);
249 sysadm 1.1
250     cleanup:
251 sysadm 1.6 mysql_free_result(rs);
252 sysadm 1.1
253 sysadm 1.6 return ret;
254     }
255    
256 sysadm 1.25 int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_online_list)
257 sysadm 1.6 {
258     MYSQL_RES *rs = NULL;
259     MYSQL_ROW row;
260     char sql[SQL_BUFFER_LEN];
261     int ret = 0;
262     int i;
263 sysadm 1.15 int j;
264 sysadm 1.23 int user_cnt;
265     int guest_cnt;
266 sysadm 1.6
267 sysadm 1.25 if (db == NULL || p_online_list == NULL)
268 sysadm 1.6 {
269     log_error("NULL pointer error\n");
270     return -1;
271     }
272    
273     snprintf(sql, sizeof(sql),
274     "SELECT SID, UID, ip, current_action, UNIX_TIMESTAMP(login_tm), "
275     "UNIX_TIMESTAMP(last_tm) FROM user_online "
276 sysadm 1.23 "WHERE last_tm >= SUBDATE(NOW(), INTERVAL %d SECOND) "
277 sysadm 1.6 "ORDER BY last_tm DESC",
278     BBS_user_off_line);
279    
280     if (mysql_query(db, sql) != 0)
281     {
282     log_error("Query user online error: %s\n", mysql_error(db));
283     ret = -1;
284     goto cleanup;
285     }
286    
287     if ((rs = mysql_use_result(db)) == NULL)
288     {
289     log_error("Get user online data failed\n");
290     ret = -1;
291     goto cleanup;
292     }
293    
294     i = 0;
295 sysadm 1.23 user_cnt = 0;
296     guest_cnt = 0;
297 sysadm 1.6 while ((row = mysql_fetch_row(rs)))
298     {
299 sysadm 1.23 if (atoi(row[1]) == 0) // guest
300     {
301     guest_cnt++;
302     continue;
303     }
304     else
305     {
306     user_cnt++;
307     }
308    
309 sysadm 1.25 p_online_list->users[i].id = i;
310     strncpy(p_online_list->users[i].session_id, row[0], sizeof(p_online_list->users[i].session_id) - 1);
311     p_online_list->users[i].session_id[sizeof(p_online_list->users[i].session_id) - 1] = '\0';
312 sysadm 1.6
313 sysadm 1.25 if ((ret = query_user_info_by_uid(atoi(row[1]), &(p_online_list->users[i].user_info), NULL, 0)) <= 0)
314 sysadm 1.7 {
315 sysadm 1.12 log_error("query_user_info_by_uid(%d) error\n", atoi(row[1]));
316 sysadm 1.9 continue;
317 sysadm 1.7 }
318 sysadm 1.6
319 sysadm 1.25 strncpy(p_online_list->users[i].ip, row[2], sizeof(p_online_list->users[i].ip) - 1);
320     p_online_list->users[i].ip[sizeof(p_online_list->users[i].ip) - 1] = '\0';
321 sysadm 1.6
322 sysadm 1.25 strncpy(p_online_list->users[i].current_action, row[3], sizeof(p_online_list->users[i].current_action) - 1);
323     p_online_list->users[i].current_action[sizeof(p_online_list->users[i].current_action) - 1] = '\0';
324     p_online_list->users[i].current_action_title = NULL;
325     if (p_online_list->users[i].current_action[0] == '\0')
326 sysadm 1.6 {
327 sysadm 1.25 p_online_list->users[i].current_action_title = "";
328 sysadm 1.6 }
329 sysadm 1.25 else if (trie_dict_get(p_trie_action_dict, p_online_list->users[i].current_action, (int64_t *)(&(p_online_list->users[i].current_action_title))) < 0)
330 sysadm 1.6 {
331     log_error("trie_dict_get(p_trie_action_dict, %s) error on session_id=%s\n",
332 sysadm 1.25 p_online_list->users[i].current_action, p_online_list->users[i].session_id);
333 sysadm 1.6 continue;
334     }
335    
336 sysadm 1.25 p_online_list->users[i].login_tm = (row[4] == NULL ? 0 : atol(row[4]));
337     p_online_list->users[i].last_tm = (row[5] == NULL ? 0 : atol(row[5]));
338 sysadm 1.6
339     i++;
340     if (i >= BBS_max_user_online_count)
341     {
342     log_error("Too many online users, exceed limit %d\n", BBS_max_user_online_count);
343     break;
344     }
345     }
346     mysql_free_result(rs);
347     rs = NULL;
348    
349 sysadm 1.23 if (user_cnt > 0)
350 sysadm 1.10 {
351 sysadm 1.15 // Rebuild index
352 sysadm 1.23 for (j = 0; j < user_cnt; j++)
353 sysadm 1.15 {
354 sysadm 1.25 p_online_list->index_uid[j].uid = p_online_list->users[j].user_info.uid;
355     p_online_list->index_uid[j].id = j;
356 sysadm 1.15 }
357    
358 sysadm 1.25 qsort(p_online_list->index_uid, (size_t)user_cnt, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
359 sysadm 1.10 }
360    
361 sysadm 1.25 p_online_list->user_count = user_cnt;
362     p_online_list->guest_count = guest_cnt;
363 sysadm 1.6
364     cleanup:
365     mysql_free_result(rs);
366    
367     return ret;
368 sysadm 1.1 }
369    
370 sysadm 1.24 int user_login_count_load(MYSQL *db)
371     {
372     MYSQL_RES *rs = NULL;
373     MYSQL_ROW row;
374     char sql[SQL_BUFFER_LEN];
375    
376     if (db == NULL)
377     {
378     log_error("NULL pointer error\n");
379     return -1;
380     }
381    
382     snprintf(sql, sizeof(sql),
383     "SELECT ID FROM user_login_log ORDER BY ID DESC LIMIT 1");
384     if (mysql_query(db, sql) != 0)
385     {
386     log_error("Query user_login_log error: %s\n", mysql_error(db));
387     return -2;
388     }
389     if ((rs = mysql_store_result(db)) == NULL)
390     {
391     log_error("Get user_login_log data failed\n");
392     return -2;
393     }
394     if ((row = mysql_fetch_row(rs)))
395     {
396     p_user_list_pool->user_login_count = atoi(row[0]);
397     }
398     mysql_free_result(rs);
399    
400     return 0;
401     }
402    
403 sysadm 1.22 int user_list_pool_init(const char *filename)
404 sysadm 1.1 {
405 sysadm 1.39 char filepath[FILE_PATH_LEN];
406     int fd;
407     size_t size;
408     void *p_shm;
409 sysadm 1.42 #ifdef HAVE_SYSTEM_V
410 sysadm 1.6 int proj_id;
411     key_t key;
412 sysadm 1.39 int semid;
413 sysadm 1.6 union semun arg;
414 sysadm 1.42 #endif
415 sysadm 1.6 int i;
416    
417     if (p_user_list_pool != NULL || p_trie_action_dict != NULL)
418     {
419     log_error("p_user_list_pool already initialized\n");
420     return -1;
421     }
422    
423     p_trie_action_dict = trie_dict_create();
424     if (p_trie_action_dict == NULL)
425     {
426     log_error("trie_dict_create() error\n");
427     return -1;
428     }
429    
430     for (i = 0; i < user_action_map_size; i++)
431     {
432     if (trie_dict_set(p_trie_action_dict, user_action_map[i].name, (int64_t)(user_action_map[i].title)) < 0)
433     {
434     log_error("trie_dict_set(p_trie_action_dict, %s) error\n", user_action_map[i].name);
435     }
436     }
437    
438     // Allocate shared memory
439 sysadm 1.39 size = sizeof(USER_LIST_POOL);
440    
441     strncpy(filepath, filename, sizeof(filepath) - 1);
442     filepath[sizeof(filepath) - 1] = '\0';
443     snprintf(user_list_shm_name, sizeof(user_list_shm_name), "/USER_LIST_SHM_%s", basename(filepath));
444    
445     if (shm_unlink(user_list_shm_name) == -1 && errno != ENOENT)
446     {
447     log_error("shm_unlink(%s) error (%d)\n", user_list_shm_name, errno);
448     return -2;
449     }
450    
451     if ((fd = shm_open(user_list_shm_name, O_CREAT | O_EXCL | O_RDWR, 0600)) == -1)
452     {
453     log_error("shm_open(%s) error (%d)\n", user_list_shm_name, errno);
454     return -2;
455     }
456     if (ftruncate(fd, (off_t)size) == -1)
457 sysadm 1.6 {
458 sysadm 1.39 log_error("ftruncate(size=%d) error (%d)\n", size, errno);
459     close(fd);
460 sysadm 1.6 return -2;
461     }
462    
463 sysadm 1.39 p_shm = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0L);
464     if (p_shm == MAP_FAILED)
465 sysadm 1.6 {
466 sysadm 1.39 log_error("mmap() error (%d)\n", errno);
467     close(fd);
468     return -2;
469 sysadm 1.6 }
470 sysadm 1.39
471     if (close(fd) < 0)
472 sysadm 1.6 {
473 sysadm 1.39 log_error("close(fd) error (%d)\n", errno);
474     return -1;
475 sysadm 1.6 }
476    
477     p_user_list_pool = p_shm;
478 sysadm 1.39 p_user_list_pool->shm_size = size;
479 sysadm 1.6
480     // Allocate semaphore as user list pool lock
481 sysadm 1.42 #ifndef HAVE_SYSTEM_V
482     if (sem_init(&(p_user_list_pool->sem), 1, 1) == -1)
483     {
484     log_error("sem_init() error (%d)\n", errno);
485     return -3;
486     }
487    
488     p_user_list_pool->read_lock_count = 0;
489     p_user_list_pool->write_lock_count = 0;
490     #else
491 sysadm 1.39 proj_id = (int)(time(NULL) % getpid());
492     key = ftok(filename, proj_id);
493     if (key == -1)
494     {
495     log_error("ftok(%s %d) error (%d)\n", filename, proj_id, errno);
496     return -2;
497     }
498    
499 sysadm 1.6 size = 2; // r_sem and w_sem
500     semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
501     if (semid == -1)
502     {
503     log_error("semget(user_list_pool_sem, size = %d) error (%d)\n", size, errno);
504     return -3;
505     }
506    
507     // Initialize sem value to 0
508     arg.val = 0;
509     for (i = 0; i < size; i++)
510     {
511     if (semctl(semid, i, SETVAL, arg) == -1)
512     {
513     log_error("semctl(user_list_pool_sem, SETVAL) error (%d)\n", errno);
514     return -3;
515     }
516     }
517    
518     p_user_list_pool->semid = semid;
519 sysadm 1.42 #endif
520 sysadm 1.6
521     // Set user counts to 0
522     p_user_list_pool->user_list[0].user_count = 0;
523     p_user_list_pool->user_list[1].user_count = 0;
524    
525 sysadm 1.37 p_user_list_pool->user_list_index_current = 0;
526     p_user_list_pool->user_list_index_new = 1;
527 sysadm 1.1
528 sysadm 1.37 p_user_list_pool->user_online_list_index_current = 0;
529     p_user_list_pool->user_online_list_index_new = 1;
530 sysadm 1.1
531 sysadm 1.18 user_stat_map_init(&(p_user_list_pool->user_stat_map));
532    
533 sysadm 1.6 return 0;
534 sysadm 1.1 }
535    
536 sysadm 1.41 void user_list_pool_cleanup(void)
537 sysadm 1.1 {
538 sysadm 1.6 if (p_user_list_pool == NULL)
539     {
540 sysadm 1.41 return;
541 sysadm 1.6 }
542    
543 sysadm 1.42 #ifdef HAVE_SYSTEM_V
544 sysadm 1.40 if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)
545     {
546     log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);
547     }
548 sysadm 1.42 #else
549     if (sem_destroy(&(p_user_list_pool->sem)) == -1)
550     {
551     log_error("sem_destroy() error (%d)\n", errno);
552     }
553     #endif
554 sysadm 1.40
555 sysadm 1.39 detach_user_list_pool_shm();
556 sysadm 1.6
557 sysadm 1.39 if (shm_unlink(user_list_shm_name) == -1 && errno != ENOENT)
558 sysadm 1.6 {
559 sysadm 1.39 log_error("shm_unlink(%s) error (%d)\n", user_list_shm_name, errno);
560 sysadm 1.6 }
561    
562 sysadm 1.39 user_list_shm_name[0] = '\0';
563 sysadm 1.6
564     if (p_trie_action_dict != NULL)
565     {
566     trie_dict_destroy(p_trie_action_dict);
567 sysadm 1.1
568 sysadm 1.6 p_trie_action_dict = NULL;
569     }
570 sysadm 1.1 }
571    
572     int set_user_list_pool_shm_readonly(void)
573     {
574 sysadm 1.39 if (p_user_list_pool != NULL && mprotect(p_user_list_pool, p_user_list_pool->shm_size, PROT_READ) < 0)
575 sysadm 1.6 {
576 sysadm 1.39 log_error("mprotect() error (%d)\n", errno);
577 sysadm 1.6 return -1;
578     }
579    
580     return 0;
581 sysadm 1.1 }
582    
583     int detach_user_list_pool_shm(void)
584     {
585 sysadm 1.39 if (p_user_list_pool != NULL && munmap(p_user_list_pool, p_user_list_pool->shm_size) < 0)
586 sysadm 1.6 {
587 sysadm 1.39 log_error("munmap() error (%d)\n", errno);
588 sysadm 1.6 return -1;
589     }
590    
591     p_user_list_pool = NULL;
592    
593     return 0;
594     }
595    
596     int user_list_pool_reload(int online_user)
597     {
598     MYSQL *db = NULL;
599 sysadm 1.37 int tmp;
600 sysadm 1.11 int ret = 0;
601 sysadm 1.6
602     if (p_user_list_pool == NULL)
603     {
604     log_error("p_user_list_pool not initialized\n");
605     return -1;
606     }
607    
608     db = db_open();
609     if (db == NULL)
610     {
611     log_error("db_open() error: %s\n", mysql_error(db));
612     return -1;
613     }
614    
615     if (online_user)
616     {
617 sysadm 1.37 if (user_online_list_load(db, &(p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_new])) < 0)
618 sysadm 1.6 {
619     log_error("user_online_list_load() error\n");
620 sysadm 1.11 ret = -2;
621     goto cleanup;
622 sysadm 1.6 }
623 sysadm 1.24
624     if (user_login_count_load(db) < 0)
625     {
626     log_error("user_login_count_load() error\n");
627     ret = -2;
628     goto cleanup;
629     }
630 sysadm 1.6 }
631     else
632     {
633 sysadm 1.37 if (user_list_load(db, &(p_user_list_pool->user_list[p_user_list_pool->user_list_index_new])) < 0)
634 sysadm 1.6 {
635     log_error("user_list_load() error\n");
636 sysadm 1.11 ret = -2;
637     goto cleanup;
638 sysadm 1.6 }
639     }
640    
641     mysql_close(db);
642 sysadm 1.11 db = NULL;
643 sysadm 1.6
644 sysadm 1.39 if (user_list_rw_lock() < 0)
645 sysadm 1.6 {
646     log_error("user_list_rw_lock() error\n");
647 sysadm 1.11 ret = -3;
648     goto cleanup;
649 sysadm 1.6 }
650    
651     if (online_user)
652     {
653     // Swap p_online_current and p_online_new
654 sysadm 1.37 tmp = p_user_list_pool->user_online_list_index_current;
655     p_user_list_pool->user_online_list_index_current = p_user_list_pool->user_online_list_index_new;
656     p_user_list_pool->user_online_list_index_new = tmp;
657 sysadm 1.6 }
658     else
659     {
660 sysadm 1.37 // Swap index_current and index_new
661     tmp = p_user_list_pool->user_list_index_current;
662     p_user_list_pool->user_list_index_current = p_user_list_pool->user_list_index_new;
663     p_user_list_pool->user_list_index_new = tmp;
664 sysadm 1.6 }
665    
666 sysadm 1.39 if (user_list_rw_unlock() < 0)
667 sysadm 1.6 {
668     log_error("user_list_rw_unlock() error\n");
669 sysadm 1.11 ret = -3;
670     goto cleanup;
671 sysadm 1.6 }
672 sysadm 1.1
673 sysadm 1.11 cleanup:
674     mysql_close(db);
675    
676     return ret;
677 sysadm 1.1 }
678    
679 sysadm 1.39 int user_list_try_rd_lock(int wait_sec)
680 sysadm 1.1 {
681 sysadm 1.42 #ifdef HAVE_SYSTEM_V
682 sysadm 1.6 struct sembuf sops[2];
683 sysadm 1.42 #endif
684 sysadm 1.6 struct timespec timeout;
685 sysadm 1.42 int ret = 0;
686 sysadm 1.6
687 sysadm 1.39 if (p_user_list_pool == NULL)
688     {
689     log_error("p_user_list_pool not initialized\n");
690     return -1;
691     }
692    
693 sysadm 1.42 timeout.tv_sec = wait_sec;
694     timeout.tv_nsec = 0;
695    
696     #ifdef HAVE_SYSTEM_V
697 sysadm 1.6 sops[0].sem_num = 1; // w_sem
698     sops[0].sem_op = 0; // wait until unlocked
699     sops[0].sem_flg = 0;
700    
701     sops[1].sem_num = 0; // r_sem
702     sops[1].sem_op = 1; // lock
703     sops[1].sem_flg = SEM_UNDO; // undo on terminate
704    
705 sysadm 1.39 ret = semtimedop(p_user_list_pool->semid, sops, 2, &timeout);
706 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
707     {
708 sysadm 1.34 log_error("semop(lock read) error %d\n", errno);
709 sysadm 1.6 }
710 sysadm 1.42 #else
711     if (sem_timedwait(&(p_user_list_pool->sem), &timeout) == -1)
712     {
713     if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
714     {
715     log_error("sem_timedwait() error %d\n", errno);
716     }
717     return -1;
718     }
719    
720     if (p_user_list_pool->write_lock_count == 0)
721     {
722     p_user_list_pool->read_lock_count++;
723     }
724     else
725     {
726     errno = EAGAIN;
727     ret = -1;
728     }
729    
730     if (sem_post(&(p_user_list_pool->sem)) == -1)
731     {
732     log_error("sem_post() error %d\n", errno);
733     return -1;
734     }
735     #endif
736 sysadm 1.1
737 sysadm 1.6 return ret;
738 sysadm 1.1 }
739    
740 sysadm 1.39 int user_list_try_rw_lock(int wait_sec)
741 sysadm 1.1 {
742 sysadm 1.42 #ifdef HAVE_SYSTEM_V
743 sysadm 1.6 struct sembuf sops[3];
744 sysadm 1.42 #endif
745 sysadm 1.6 struct timespec timeout;
746 sysadm 1.42 int ret = 0;
747 sysadm 1.6
748 sysadm 1.39 if (p_user_list_pool == NULL)
749     {
750     log_error("p_user_list_pool not initialized\n");
751     return -1;
752     }
753    
754 sysadm 1.42 timeout.tv_sec = wait_sec;
755     timeout.tv_nsec = 0;
756    
757     #ifdef HAVE_SYSTEM_V
758 sysadm 1.6 sops[0].sem_num = 1; // w_sem
759     sops[0].sem_op = 0; // wait until unlocked
760     sops[0].sem_flg = 0;
761    
762     sops[1].sem_num = 1; // w_sem
763     sops[1].sem_op = 1; // lock
764     sops[1].sem_flg = SEM_UNDO; // undo on terminate
765    
766     sops[2].sem_num = 0; // r_sem
767     sops[2].sem_op = 0; // wait until unlocked
768     sops[2].sem_flg = 0;
769    
770 sysadm 1.39 ret = semtimedop(p_user_list_pool->semid, sops, 3, &timeout);
771 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
772     {
773 sysadm 1.34 log_error("semop(lock write) error %d\n", errno);
774 sysadm 1.6 }
775 sysadm 1.42 #else
776     if (sem_timedwait(&(p_user_list_pool->sem), &timeout) == -1)
777     {
778     if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
779     {
780     log_error("sem_timedwait() error %d\n", errno);
781     }
782     return -1;
783     }
784    
785     if (p_user_list_pool->read_lock_count == 0 && p_user_list_pool->write_lock_count == 0)
786     {
787     p_user_list_pool->write_lock_count++;
788     }
789     else
790     {
791     errno = EAGAIN;
792     ret = -1;
793     }
794    
795     if (sem_post(&(p_user_list_pool->sem)) == -1)
796     {
797     log_error("sem_post() error %d\n", errno);
798     return -1;
799     }
800     #endif
801 sysadm 1.1
802 sysadm 1.6 return ret;
803 sysadm 1.1 }
804    
805 sysadm 1.39 int user_list_rd_unlock(void)
806 sysadm 1.1 {
807 sysadm 1.42 #ifdef HAVE_SYSTEM_V
808 sysadm 1.6 struct sembuf sops[2];
809 sysadm 1.42 #endif
810     int ret = 0;
811 sysadm 1.1
812 sysadm 1.39 if (p_user_list_pool == NULL)
813     {
814     log_error("p_user_list_pool not initialized\n");
815     return -1;
816     }
817    
818 sysadm 1.42 #ifdef HAVE_SYSTEM_V
819 sysadm 1.6 sops[0].sem_num = 0; // r_sem
820     sops[0].sem_op = -1; // unlock
821     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
822    
823 sysadm 1.39 ret = semop(p_user_list_pool->semid, sops, 1);
824 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
825     {
826     log_error("semop(unlock read) error %d\n", errno);
827     }
828 sysadm 1.42 #else
829     if (sem_wait(&(p_user_list_pool->sem)) == -1)
830     {
831     if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
832     {
833 sysadm 1.43 log_error("sem_wait() error %d\n", errno);
834 sysadm 1.42 }
835     return -1;
836     }
837    
838     if (p_user_list_pool->read_lock_count > 0)
839     {
840     p_user_list_pool->read_lock_count--;
841     }
842     else
843     {
844     log_error("read_lock_count already 0\n");
845     }
846    
847     if (sem_post(&(p_user_list_pool->sem)) == -1)
848     {
849     log_error("sem_post() error %d\n", errno);
850     return -1;
851     }
852     #endif
853 sysadm 1.1
854 sysadm 1.6 return ret;
855 sysadm 1.1 }
856    
857 sysadm 1.39 int user_list_rw_unlock(void)
858 sysadm 1.1 {
859 sysadm 1.42 #ifdef HAVE_SYSTEM_V
860 sysadm 1.6 struct sembuf sops[1];
861 sysadm 1.42 #endif
862     int ret = 0;
863 sysadm 1.1
864 sysadm 1.39 if (p_user_list_pool == NULL)
865     {
866     log_error("p_user_list_pool not initialized\n");
867     return -1;
868     }
869    
870 sysadm 1.42 #ifdef HAVE_SYSTEM_V
871 sysadm 1.6 sops[0].sem_num = 1; // w_sem
872     sops[0].sem_op = -1; // unlock
873     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
874    
875 sysadm 1.39 ret = semop(p_user_list_pool->semid, sops, 1);
876 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
877     {
878     log_error("semop(unlock write) error %d\n", errno);
879     }
880 sysadm 1.42 #else
881     if (sem_wait(&(p_user_list_pool->sem)) == -1)
882     {
883     if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
884     {
885 sysadm 1.43 log_error("sem_wait() error %d\n", errno);
886 sysadm 1.42 }
887     return -1;
888     }
889    
890     if (p_user_list_pool->write_lock_count > 0)
891     {
892     p_user_list_pool->write_lock_count--;
893     }
894     else
895     {
896     log_error("write_lock_count already 0\n");
897     }
898    
899     if (sem_post(&(p_user_list_pool->sem)) == -1)
900     {
901     log_error("sem_post() error %d\n", errno);
902     return -1;
903     }
904     #endif
905 sysadm 1.1
906 sysadm 1.6 return ret;
907 sysadm 1.1 }
908    
909 sysadm 1.39 int user_list_rd_lock(void)
910 sysadm 1.1 {
911 sysadm 1.6 int timer = 0;
912     int ret = -1;
913 sysadm 1.44 time_t tm_first_failure = 0;
914 sysadm 1.1
915 sysadm 1.39 if (p_user_list_pool == NULL)
916     {
917     log_error("p_user_list_pool not initialized\n");
918     return -1;
919     }
920    
921 sysadm 1.6 while (!SYS_server_exit)
922     {
923 sysadm 1.39 ret = user_list_try_rd_lock(USER_LIST_TRY_LOCK_WAIT_TIME);
924 sysadm 1.6 if (ret == 0) // success
925     {
926     break;
927     }
928     else if (errno == EAGAIN || errno == EINTR) // retry
929     {
930     timer++;
931     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
932     {
933     log_error("user_list_try_rd_lock() tried %d times\n", timer);
934 sysadm 1.44
935     if (time(NULL) - tm_first_failure >= USER_LIST_DEAD_LOCK_TIMEOUT)
936     {
937     log_error("Unable to acquire rw_lock for %d seconds\n", time(NULL) - tm_first_failure);
938     #ifndef HAVE_SYSTEM_V
939     user_list_reset_lock();
940     log_error("Reset POSIX semaphore to resolve dead lock\n");
941     #endif
942     break;
943     }
944 sysadm 1.6 }
945 sysadm 1.42 usleep(100 * 1000); // 0.1 second
946 sysadm 1.6 }
947     else // failed
948     {
949     log_error("user_list_try_rd_lock() failed\n");
950     break;
951     }
952     }
953 sysadm 1.1
954 sysadm 1.6 return ret;
955 sysadm 1.1 }
956    
957 sysadm 1.39 int user_list_rw_lock(void)
958 sysadm 1.1 {
959 sysadm 1.6 int timer = 0;
960     int ret = -1;
961 sysadm 1.44 time_t tm_first_failure = 0;
962 sysadm 1.1
963 sysadm 1.39 if (p_user_list_pool == NULL)
964     {
965     log_error("p_user_list_pool not initialized\n");
966     return -1;
967     }
968    
969 sysadm 1.6 while (!SYS_server_exit)
970     {
971 sysadm 1.39 ret = user_list_try_rw_lock(USER_LIST_TRY_LOCK_WAIT_TIME);
972 sysadm 1.6 if (ret == 0) // success
973     {
974     break;
975     }
976     else if (errno == EAGAIN || errno == EINTR) // retry
977     {
978     timer++;
979     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
980     {
981     log_error("user_list_try_rw_lock() tried %d times\n", timer);
982 sysadm 1.44
983     if (time(NULL) - tm_first_failure >= USER_LIST_DEAD_LOCK_TIMEOUT)
984     {
985     log_error("Unable to acquire rw_lock for %d seconds\n", time(NULL) - tm_first_failure);
986     #ifndef HAVE_SYSTEM_V
987     user_list_reset_lock();
988     log_error("Reset POSIX semaphore to resolve dead lock\n");
989     #endif
990     break;
991     }
992 sysadm 1.6 }
993 sysadm 1.42 usleep(100 * 1000); // 0.1 second
994 sysadm 1.6 }
995     else // failed
996     {
997     log_error("user_list_try_rw_lock() failed\n");
998     break;
999     }
1000     }
1001 sysadm 1.1
1002 sysadm 1.6 return ret;
1003 sysadm 1.1 }
1004 sysadm 1.2
1005 sysadm 1.44 #ifndef HAVE_SYSTEM_V
1006     int user_list_reset_lock(void)
1007     {
1008     if (p_user_list_pool == NULL)
1009     {
1010     log_error("p_user_list_pool not initialized\n");
1011     return -1;
1012     }
1013    
1014     if (sem_destroy(&(p_user_list_pool->sem)) == -1)
1015     {
1016     log_error("sem_destroy() error (%d)\n", errno);
1017     }
1018    
1019     p_user_list_pool->read_lock_count = 0;
1020     p_user_list_pool->write_lock_count = 0;
1021    
1022     if (sem_init(&(p_user_list_pool->sem), 1, 1) == -1)
1023     {
1024     log_error("sem_init() error (%d)\n", errno);
1025     }
1026    
1027     return 0;
1028     }
1029     #endif
1030    
1031 sysadm 1.2 int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
1032     {
1033 sysadm 1.6 int ret = 0;
1034 sysadm 1.2
1035 sysadm 1.6 if (p_users == NULL || p_user_count == NULL || p_page_count == NULL)
1036     {
1037     log_error("NULL pointer error\n");
1038     return -1;
1039     }
1040    
1041 sysadm 1.12 *p_user_count = 0;
1042     *p_page_count = 0;
1043    
1044 sysadm 1.6 // acquire lock of user list
1045 sysadm 1.39 if (user_list_rd_lock() < 0)
1046 sysadm 1.6 {
1047     log_error("user_list_rd_lock() error\n");
1048     return -2;
1049     }
1050    
1051 sysadm 1.37 if (p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count == 0)
1052 sysadm 1.6 {
1053     // empty list
1054     ret = 0;
1055     goto cleanup;
1056     }
1057    
1058 sysadm 1.37 *p_page_count = (p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count + BBS_user_limit_per_page - 1) /
1059 sysadm 1.33 BBS_user_limit_per_page;
1060 sysadm 1.6
1061     if (page_id < 0 || page_id >= *p_page_count)
1062     {
1063     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
1064     ret = -3;
1065     goto cleanup;
1066     }
1067    
1068     *p_user_count = MIN(BBS_user_limit_per_page,
1069 sysadm 1.37 p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count -
1070 sysadm 1.6 page_id * BBS_user_limit_per_page);
1071    
1072     memcpy(p_users,
1073 sysadm 1.37 p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users + page_id * BBS_user_limit_per_page,
1074 sysadm 1.6 sizeof(USER_INFO) * (size_t)(*p_user_count));
1075    
1076     cleanup:
1077     // release lock of user list
1078 sysadm 1.39 if (user_list_rd_unlock() < 0)
1079 sysadm 1.6 {
1080     log_error("user_list_rd_unlock() error\n");
1081     ret = -1;
1082     }
1083    
1084     return ret;
1085     }
1086    
1087     int query_user_online_list(int page_id, USER_ONLINE_INFO *p_online_users, int *p_user_count, int *p_page_count)
1088     {
1089     int ret = 0;
1090    
1091     if (p_online_users == NULL || p_user_count == NULL || p_page_count == NULL)
1092     {
1093     log_error("NULL pointer error\n");
1094     return -1;
1095     }
1096    
1097 sysadm 1.12 *p_user_count = 0;
1098     *p_page_count = 0;
1099    
1100 sysadm 1.6 // acquire lock of user list
1101 sysadm 1.39 if (user_list_rd_lock() < 0)
1102 sysadm 1.6 {
1103     log_error("user_list_rd_lock() error\n");
1104     return -2;
1105     }
1106    
1107 sysadm 1.37 if (p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count == 0)
1108 sysadm 1.6 {
1109     // empty list
1110     ret = 0;
1111     goto cleanup;
1112     }
1113    
1114 sysadm 1.37 *p_page_count = (p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count + BBS_user_limit_per_page - 1) / BBS_user_limit_per_page;
1115 sysadm 1.6
1116     if (page_id < 0 || page_id >= *p_page_count)
1117     {
1118     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
1119     ret = -3;
1120     goto cleanup;
1121     }
1122    
1123     *p_user_count = MIN(BBS_user_limit_per_page,
1124 sysadm 1.37 p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count -
1125 sysadm 1.6 page_id * BBS_user_limit_per_page);
1126    
1127     memcpy(p_online_users,
1128 sysadm 1.37 p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].users + page_id * BBS_user_limit_per_page,
1129 sysadm 1.6 sizeof(USER_ONLINE_INFO) * (size_t)(*p_user_count));
1130 sysadm 1.2
1131     cleanup:
1132 sysadm 1.6 // release lock of user list
1133 sysadm 1.39 if (user_list_rd_unlock() < 0)
1134 sysadm 1.6 {
1135     log_error("user_list_rd_unlock() error\n");
1136     ret = -1;
1137     }
1138 sysadm 1.2
1139 sysadm 1.6 return ret;
1140 sysadm 1.2 }
1141 sysadm 1.4
1142 sysadm 1.23 int get_user_list_count(int *p_user_cnt)
1143     {
1144     if (p_user_cnt == NULL)
1145     {
1146     log_error("NULL pointer error\n");
1147     return -1;
1148     }
1149    
1150     // acquire lock of user list
1151 sysadm 1.39 if (user_list_rd_lock() < 0)
1152 sysadm 1.23 {
1153     log_error("user_list_rd_lock() error\n");
1154     return -2;
1155     }
1156    
1157 sysadm 1.37 *p_user_cnt = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count;
1158 sysadm 1.23
1159     // release lock of user list
1160 sysadm 1.39 if (user_list_rd_unlock() < 0)
1161 sysadm 1.23 {
1162     log_error("user_list_rd_unlock() error\n");
1163     return -2;
1164     }
1165    
1166     return 0;
1167     }
1168    
1169     int get_user_online_list_count(int *p_user_cnt, int *p_guest_cnt)
1170     {
1171     if (p_user_cnt == NULL || p_guest_cnt == NULL)
1172     {
1173     log_error("NULL pointer error\n");
1174     return -1;
1175     }
1176    
1177     // acquire lock of user list
1178 sysadm 1.39 if (user_list_rd_lock() < 0)
1179 sysadm 1.23 {
1180     log_error("user_list_rd_lock() error\n");
1181     return -2;
1182     }
1183    
1184 sysadm 1.37 *p_user_cnt = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count;
1185     *p_guest_cnt = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].guest_count;
1186 sysadm 1.23
1187     // release lock of user list
1188 sysadm 1.39 if (user_list_rd_unlock() < 0)
1189 sysadm 1.23 {
1190     log_error("user_list_rd_unlock() error\n");
1191     return -2;
1192     }
1193    
1194     return 0;
1195     }
1196    
1197 sysadm 1.24 int get_user_login_count(int *p_login_cnt)
1198     {
1199     if (p_login_cnt == NULL)
1200     {
1201     log_error("NULL pointer error\n");
1202     return -1;
1203     }
1204    
1205     *p_login_cnt = p_user_list_pool->user_login_count;
1206    
1207     return 0;
1208     }
1209    
1210 sysadm 1.8 int query_user_info(int32_t id, USER_INFO *p_user)
1211     {
1212     int ret = 0;
1213    
1214     if (p_user == NULL)
1215     {
1216     log_error("NULL pointer error\n");
1217     return -1;
1218     }
1219    
1220     // acquire lock of user list
1221 sysadm 1.39 if (user_list_rd_lock() < 0)
1222 sysadm 1.8 {
1223     log_error("user_list_rd_lock() error\n");
1224     return -2;
1225     }
1226    
1227 sysadm 1.37 if (id >= 0 && id < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count) // Found
1228 sysadm 1.8 {
1229 sysadm 1.37 *p_user = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[id];
1230 sysadm 1.8 ret = 1;
1231     }
1232    
1233     // release lock of user list
1234 sysadm 1.39 if (user_list_rd_unlock() < 0)
1235 sysadm 1.8 {
1236     log_error("user_list_rd_unlock() error\n");
1237     ret = -1;
1238     }
1239    
1240     return ret;
1241     }
1242    
1243 sysadm 1.25 int query_user_info_by_uid(int32_t uid, USER_INFO *p_user, char *p_intro_buf, size_t intro_buf_len)
1244 sysadm 1.4 {
1245 sysadm 1.6 int left;
1246     int right;
1247     int mid;
1248 sysadm 1.8 int32_t id;
1249 sysadm 1.6 int ret = 0;
1250    
1251     if (p_user == NULL)
1252     {
1253     log_error("NULL pointer error\n");
1254     return -1;
1255     }
1256    
1257     // acquire lock of user list
1258 sysadm 1.39 if (user_list_rd_lock() < 0)
1259 sysadm 1.6 {
1260     log_error("user_list_rd_lock() error\n");
1261     return -2;
1262     }
1263    
1264     left = 0;
1265 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1266 sysadm 1.6
1267     while (left < right)
1268     {
1269     mid = (left + right) / 2;
1270 sysadm 1.37 if (uid < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1271 sysadm 1.6 {
1272 sysadm 1.22 right = mid - 1;
1273 sysadm 1.6 }
1274 sysadm 1.37 else if (uid > p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1275 sysadm 1.6 {
1276     left = mid + 1;
1277     }
1278 sysadm 1.37 else // if (uid == p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1279 sysadm 1.6 {
1280     left = mid;
1281     break;
1282     }
1283     }
1284    
1285 sysadm 1.37 if (uid == p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[left].uid) // Found
1286 sysadm 1.8 {
1287 sysadm 1.37 id = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[left].id;
1288     *p_user = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[id];
1289 sysadm 1.12 ret = 1;
1290 sysadm 1.25
1291     if (p_intro_buf != NULL)
1292     {
1293 sysadm 1.37 strncpy(p_intro_buf, p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[id].intro, intro_buf_len - 1);
1294 sysadm 1.25 p_intro_buf[intro_buf_len - 1] = '\0';
1295     p_user->intro = p_intro_buf;
1296     }
1297     }
1298    
1299     // release lock of user list
1300 sysadm 1.39 if (user_list_rd_unlock() < 0)
1301 sysadm 1.25 {
1302     log_error("user_list_rd_unlock() error\n");
1303     ret = -1;
1304 sysadm 1.8 }
1305    
1306 sysadm 1.25 return ret;
1307     }
1308    
1309     int query_user_info_by_username(const char *username_prefix, int max_user_cnt,
1310     int32_t uid_list[], char username_list[][BBS_username_max_len + 1])
1311     {
1312     int left;
1313     int right;
1314     int mid;
1315     int left_save;
1316     int ret = 0;
1317     size_t prefix_len;
1318     int comp;
1319     int i;
1320    
1321     if (username_prefix == NULL || uid_list == NULL || username_list == NULL)
1322     {
1323     log_error("NULL pointer error\n");
1324     return -1;
1325     }
1326    
1327     prefix_len = strlen(username_prefix);
1328    
1329     // acquire lock of user list
1330 sysadm 1.39 if (user_list_rd_lock() < 0)
1331 sysadm 1.25 {
1332     log_error("user_list_rd_lock() error\n");
1333     return -2;
1334     }
1335    
1336     left = 0;
1337 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1338 sysadm 1.25
1339     while (left < right)
1340     {
1341     mid = (left + right) / 2;
1342 sysadm 1.37 comp = strncasecmp(username_prefix, p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[mid].username, prefix_len);
1343 sysadm 1.25 if (comp < 0)
1344     {
1345     right = mid - 1;
1346     }
1347     else if (comp > 0)
1348     {
1349     left = mid + 1;
1350     }
1351     else // if (comp == 0)
1352     {
1353     left = mid;
1354     break;
1355     }
1356     }
1357    
1358 sysadm 1.37 if (strncasecmp(username_prefix, p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[left].username, prefix_len) == 0) // Found
1359 sysadm 1.25 {
1360 sysadm 1.46 log_debug("Debug: match found, pos=%d\n", left);
1361 sysadm 1.25
1362     left_save = left;
1363     right = left;
1364     left = 0;
1365    
1366     while (left < right)
1367     {
1368     mid = (left + right) / 2;
1369 sysadm 1.37 comp = strncasecmp(username_prefix, p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[mid].username, prefix_len);
1370 sysadm 1.25 if (comp > 0)
1371     {
1372     left = mid + 1;
1373     }
1374     else if (comp == 0)
1375     {
1376     right = mid;
1377     }
1378     else // if (comp < 0)
1379     {
1380     log_error("Bug: left=%d right=%d mid=%d");
1381     ret = -2;
1382     goto cleanup;
1383     }
1384     }
1385    
1386 sysadm 1.46 log_debug("Debug: first match found, pos=%d\n", right);
1387 sysadm 1.25
1388     left = left_save;
1389     left_save = right;
1390 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1391 sysadm 1.25
1392     while (left < right)
1393     {
1394     mid = (left + right) / 2 + (left + right) % 2;
1395 sysadm 1.37 comp = strncasecmp(username_prefix, p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[mid].username, prefix_len);
1396 sysadm 1.25 if (comp < 0)
1397     {
1398     right = mid - 1;
1399     }
1400     else if (comp == 0)
1401     {
1402     left = mid;
1403     }
1404     else // if (comp > 0)
1405     {
1406     log_error("Bug: left=%d right=%d mid=%d");
1407     ret = -2;
1408     goto cleanup;
1409     }
1410     }
1411    
1412 sysadm 1.46 log_debug("Debug: last match found, pos=%d\n", left);
1413 sysadm 1.25
1414     right = left;
1415     left = left_save;
1416    
1417     for (i = 0; i < max_user_cnt && left + i <= right; i++)
1418     {
1419 sysadm 1.37 uid_list[i] = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[left + i].uid;
1420     strncpy(username_list[i], p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[left + i].username, sizeof(username_list[i]) - 1);
1421 sysadm 1.25 username_list[i][sizeof(username_list[i]) - 1] = '\0';
1422     }
1423     ret = i;
1424     }
1425    
1426     cleanup:
1427 sysadm 1.8 // release lock of user list
1428 sysadm 1.39 if (user_list_rd_unlock() < 0)
1429 sysadm 1.8 {
1430     log_error("user_list_rd_unlock() error\n");
1431     ret = -1;
1432     }
1433    
1434     return ret;
1435     }
1436    
1437     int query_user_online_info(int32_t id, USER_ONLINE_INFO *p_user)
1438     {
1439     int ret = 0;
1440    
1441     if (p_user == NULL)
1442     {
1443     log_error("NULL pointer error\n");
1444     return -1;
1445     }
1446    
1447     // acquire lock of user list
1448 sysadm 1.39 if (user_list_rd_lock() < 0)
1449 sysadm 1.8 {
1450     log_error("user_list_rd_lock() error\n");
1451     return -2;
1452     }
1453    
1454 sysadm 1.37 if (id >= 0 && id < p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count) // Found
1455 sysadm 1.6 {
1456 sysadm 1.37 *p_user = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].users[id];
1457 sysadm 1.6 ret = 1;
1458     }
1459    
1460     // release lock of user list
1461 sysadm 1.39 if (user_list_rd_unlock() < 0)
1462 sysadm 1.6 {
1463     log_error("user_list_rd_unlock() error\n");
1464     ret = -1;
1465     }
1466 sysadm 1.4
1467 sysadm 1.6 return ret;
1468 sysadm 1.4 }
1469 sysadm 1.11
1470     int query_user_online_info_by_uid(int32_t uid, USER_ONLINE_INFO *p_users, int *p_user_cnt, int start_id)
1471     {
1472     int left;
1473     int right;
1474     int mid;
1475     int32_t id;
1476     int ret = 0;
1477     int i;
1478 sysadm 1.20 int user_cnt;
1479 sysadm 1.11
1480     if (p_users == NULL || p_user_cnt == NULL)
1481     {
1482     log_error("NULL pointer error\n");
1483     return -1;
1484     }
1485    
1486 sysadm 1.20 user_cnt = *p_user_cnt;
1487     *p_user_cnt = 0;
1488    
1489 sysadm 1.11 // acquire lock of user list
1490 sysadm 1.39 if (user_list_rd_lock() < 0)
1491 sysadm 1.11 {
1492     log_error("user_list_rd_lock() error\n");
1493     return -2;
1494     }
1495    
1496     left = start_id;
1497 sysadm 1.37 right = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count - 1;
1498 sysadm 1.11
1499     while (left < right)
1500     {
1501     mid = (left + right) / 2;
1502 sysadm 1.37 if (uid < p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[mid].uid)
1503 sysadm 1.11 {
1504 sysadm 1.22 right = mid - 1;
1505 sysadm 1.11 }
1506 sysadm 1.37 else if (uid > p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[mid].uid)
1507 sysadm 1.11 {
1508     left = mid + 1;
1509     }
1510 sysadm 1.37 else // if (uid == p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[mid].uid)
1511 sysadm 1.11 {
1512     left = mid;
1513     break;
1514     }
1515     }
1516    
1517 sysadm 1.37 if (uid == p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[left].uid)
1518 sysadm 1.11 {
1519     right = left;
1520     left = start_id;
1521    
1522     while (left < right)
1523     {
1524     mid = (left + right) / 2;
1525 sysadm 1.37 if (uid - 1 < p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[mid].uid)
1526 sysadm 1.11 {
1527     right = mid;
1528     }
1529 sysadm 1.37 else // if (uid - 1 >= p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[mid].uid)
1530 sysadm 1.11 {
1531     left = mid + 1;
1532     }
1533     }
1534    
1535 sysadm 1.13 for (i = 0;
1536 sysadm 1.37 left < p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count && i < user_cnt &&
1537     uid == p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[left].uid;
1538 sysadm 1.13 left++, i++)
1539 sysadm 1.11 {
1540 sysadm 1.37 id = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[left].id;
1541     p_users[i] = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].users[id];
1542 sysadm 1.11 }
1543    
1544 sysadm 1.12 if (i > 0)
1545 sysadm 1.11 {
1546     *p_user_cnt = i;
1547     ret = 1;
1548     }
1549     }
1550    
1551     // release lock of user list
1552 sysadm 1.39 if (user_list_rd_unlock() < 0)
1553 sysadm 1.11 {
1554     log_error("user_list_rd_unlock() error\n");
1555     ret = -1;
1556     }
1557    
1558     return ret;
1559     }
1560 sysadm 1.18
1561     int get_user_id_list(int32_t *p_uid_list, int *p_user_cnt, int start_uid)
1562     {
1563     int left;
1564     int right;
1565     int mid;
1566     int ret = 0;
1567     int i;
1568    
1569     if (p_uid_list == NULL || p_user_cnt == NULL)
1570     {
1571     log_error("NULL pointer error\n");
1572     return -1;
1573     }
1574    
1575     // acquire lock of user list
1576 sysadm 1.39 if (user_list_rd_lock() < 0)
1577 sysadm 1.18 {
1578     log_error("user_list_rd_lock() error\n");
1579     return -2;
1580     }
1581    
1582     left = 0;
1583 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1584 sysadm 1.18
1585     while (left < right)
1586     {
1587     mid = (left + right) / 2;
1588 sysadm 1.37 if (start_uid < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1589 sysadm 1.18 {
1590 sysadm 1.22 right = mid - 1;
1591 sysadm 1.18 }
1592 sysadm 1.37 else if (start_uid > p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1593 sysadm 1.18 {
1594     left = mid + 1;
1595     }
1596 sysadm 1.37 else // if (start_uid == p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1597 sysadm 1.18 {
1598     left = mid;
1599     break;
1600     }
1601     }
1602    
1603 sysadm 1.37 for (i = 0; i < *p_user_cnt && left + i < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count; i++)
1604 sysadm 1.18 {
1605 sysadm 1.37 p_uid_list[i] = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[left + i].uid;
1606 sysadm 1.18 }
1607     *p_user_cnt = i;
1608    
1609     // release lock of user list
1610 sysadm 1.39 if (user_list_rd_unlock() < 0)
1611 sysadm 1.18 {
1612     log_error("user_list_rd_unlock() error\n");
1613     ret = -1;
1614     }
1615    
1616     return ret;
1617     }
1618    
1619     int user_stat_update(void)
1620     {
1621     return user_stat_map_update(&(p_user_list_pool->user_stat_map));
1622     }
1623    
1624 sysadm 1.19 int user_article_cnt_inc(int32_t uid, int n)
1625     {
1626     return user_stat_article_cnt_inc(&(p_user_list_pool->user_stat_map), uid, n);
1627     }
1628    
1629     int get_user_article_cnt(int32_t uid)
1630 sysadm 1.18 {
1631     const USER_STAT *p_stat;
1632     int ret;
1633    
1634     ret = user_stat_get(&(p_user_list_pool->user_stat_map), uid, &p_stat);
1635     if (ret < 0)
1636     {
1637     log_error("user_stat_get(uid=%d) error: %d\n", uid, ret);
1638     return -1;
1639     }
1640     else if (ret == 0) // user not found
1641     {
1642     return -1;
1643     }
1644    
1645     return p_stat->article_count;
1646     }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1