/[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.43 - (hide annotations)
Thu Nov 20 10:20:51 2025 UTC (3 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.42: +4 -4 lines
Content type: text/x-csrc
Add alternative POSIX semaphore based rd/rw (un)lock in section_list

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

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