/[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.44 - (hide annotations)
Thu Nov 20 11:31:56 2025 UTC (3 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.43: +52 -0 lines
Content type: text/x-csrc
Add mechanism to detect and resolve dead lock caused by POSIX semaphore.

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

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