/[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.45 - (hide annotations)
Wed Dec 3 05:31:11 2025 UTC (3 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.44: +1 -0 lines
Content type: text/x-csrc
Refresh user online status during list item selection.

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

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