/[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.7 - (hide annotations)
Wed Oct 22 05:50:13 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.6: +21 -4 lines
Content type: text/x-csrc
Refine handling of Guest

1 sysadm 1.1 /***************************************************************************
2 sysadm 1.6 user_list.c - description
3     -------------------
4     Copyright : (C) 2004-2025 by Leaflet
5     Email : leaflet@leafok.com
6 sysadm 1.1 ***************************************************************************/
7    
8     /***************************************************************************
9     * *
10     * This program is free software; you can redistribute it and/or modify *
11     * it under the terms of the GNU General Public License as published by *
12     * the Free Software Foundation; either version 3 of the License, or *
13     * (at your option) any later version. *
14     * *
15     ***************************************************************************/
16    
17     #include "common.h"
18     #include "database.h"
19     #include "log.h"
20 sysadm 1.6 #include "trie_dict.h"
21 sysadm 1.1 #include "user_list.h"
22     #include <errno.h>
23     #include <stdlib.h>
24     #include <string.h>
25     #include <time.h>
26     #include <sys/ipc.h>
27     #include <sys/mman.h>
28 sysadm 1.2 #include <sys/param.h>
29 sysadm 1.1 #include <sys/sem.h>
30     #include <sys/shm.h>
31    
32     #ifdef _SEM_SEMUN_UNDEFINED
33     union semun
34     {
35 sysadm 1.6 int val; /* Value for SETVAL */
36     struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
37     unsigned short *array; /* Array for GETALL, SETALL */
38     struct seminfo *__buf; /* Buffer for IPC_INFO
39     (Linux-specific) */
40 sysadm 1.1 };
41     #endif // #ifdef _SEM_SEMUN_UNDEFINED
42    
43     #define USER_LIST_TRY_LOCK_WAIT_TIME 1 // second
44     #define USER_LIST_TRY_LOCK_TIMES 10
45    
46     struct user_list_pool_t
47     {
48 sysadm 1.6 int shmid;
49     int semid;
50     USER_LIST user_list[2];
51     USER_LIST *p_current;
52     USER_LIST *p_new;
53     USER_ONLINE_LIST user_online_list[2];
54     USER_ONLINE_LIST *p_online_current;
55     USER_ONLINE_LIST *p_online_new;
56 sysadm 1.1 };
57     typedef struct user_list_pool_t USER_LIST_POOL;
58    
59     static USER_LIST_POOL *p_user_list_pool = NULL;
60 sysadm 1.6 static TRIE_NODE *p_trie_action_dict = NULL;
61    
62     typedef struct user_action_map_t
63     {
64     char name[BBS_current_action_max_len + 1];
65     char title[BBS_current_action_max_len + 1];
66     } USER_ACTION_MAP;
67    
68     const USER_ACTION_MAP user_action_map[] =
69     {
70     {"ARTICLE_FAVOR", "浏览收藏"},
71     {"BBS_NET", "站点穿梭"},
72     {"CHICKEN", "电子小鸡"},
73     {"EDIT_ARTICLE", "修改文章"},
74 sysadm 1.7 {"LOGIN", "进入大厅"},
75 sysadm 1.6 {"MENU", "菜单选择"},
76     {"POST_ARTICLE", "撰写文章"},
77     {"REPLY_ARTICLE", "回复文章"},
78     {"USER_LIST", "查花名册"},
79     {"USER_ONLINE", "环顾四周"},
80     {"VIEW_ARTICLE", "阅读文章"},
81 sysadm 1.7 {"VIEW_FILE", "查看文档"},
82     {"WWW", "Web浏览"}};
83 sysadm 1.6
84 sysadm 1.7 const int user_action_map_size = sizeof(user_action_map) / sizeof(USER_ACTION_MAP);
85 sysadm 1.1
86 sysadm 1.5 static int user_list_try_rd_lock(int semid, int wait_sec);
87     static int user_list_try_rw_lock(int semid, int wait_sec);
88     static int user_list_rd_unlock(int semid);
89     static int user_list_rw_unlock(int semid);
90     static int user_list_rd_lock(int semid);
91     static int user_list_rw_lock(int semid);
92    
93 sysadm 1.6 static int user_list_load(MYSQL *db, USER_LIST *p_list);
94     static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list);
95    
96 sysadm 1.1 int user_list_load(MYSQL *db, USER_LIST *p_list)
97     {
98 sysadm 1.6 MYSQL_RES *rs = NULL;
99     MYSQL_ROW row;
100     char sql[SQL_BUFFER_LEN];
101     int ret = 0;
102     int i;
103    
104     if (db == NULL || p_list == NULL)
105     {
106     log_error("NULL pointer error\n");
107     return -1;
108     }
109    
110     snprintf(sql, sizeof(sql),
111     "SELECT user_list.UID AS UID, username, nickname, gender, gender_pub, life, exp, "
112     "UNIX_TIMESTAMP(signup_dt), UNIX_TIMESTAMP(last_login_dt), UNIX_TIMESTAMP(birthday) "
113     "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "
114     "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "
115     "WHERE enable ORDER BY UID");
116    
117     if (mysql_query(db, sql) != 0)
118     {
119     log_error("Query user info error: %s\n", mysql_error(db));
120     ret = -1;
121     goto cleanup;
122     }
123    
124     if ((rs = mysql_use_result(db)) == NULL)
125     {
126     log_error("Get user info data failed\n");
127     ret = -1;
128     goto cleanup;
129     }
130    
131     i = 0;
132     while ((row = mysql_fetch_row(rs)))
133     {
134     p_list->users[i].uid = atoi(row[0]);
135     strncpy(p_list->users[i].username, row[1], sizeof(p_list->users[i].username) - 1);
136     p_list->users[i].username[sizeof(p_list->users[i].username) - 1] = '\0';
137     strncpy(p_list->users[i].nickname, row[2], sizeof(p_list->users[i].nickname) - 1);
138     p_list->users[i].nickname[sizeof(p_list->users[i].nickname) - 1] = '\0';
139     p_list->users[i].gender = row[3][0];
140     p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));
141     p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));
142     p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));
143     p_list->users[i].signup_dt = (row[7] == NULL ? 0 : atol(row[7]));
144     p_list->users[i].last_login_dt = (row[8] == NULL ? 0 : atol(row[8]));
145     p_list->users[i].birthday = (row[9] == NULL ? 0 : atol(row[9]));
146    
147     i++;
148     if (i >= BBS_max_user_count)
149     {
150     log_error("Too many users, exceed limit %d\n", BBS_max_user_count);
151     break;
152     }
153     }
154     mysql_free_result(rs);
155     rs = NULL;
156 sysadm 1.1
157 sysadm 1.6 p_list->user_count = i;
158 sysadm 1.1
159     #ifdef _DEBUG
160 sysadm 1.6 log_error("Loaded %d users\n", p_list->user_count);
161 sysadm 1.1 #endif
162    
163     cleanup:
164 sysadm 1.6 mysql_free_result(rs);
165 sysadm 1.1
166 sysadm 1.6 return ret;
167     }
168    
169     int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list)
170     {
171     MYSQL_RES *rs = NULL;
172     MYSQL_ROW row;
173     char sql[SQL_BUFFER_LEN];
174     int ret = 0;
175     int i;
176    
177     if (db == NULL || p_list == NULL)
178     {
179     log_error("NULL pointer error\n");
180     return -1;
181     }
182    
183     snprintf(sql, sizeof(sql),
184     "SELECT SID, UID, ip, current_action, UNIX_TIMESTAMP(login_tm), "
185     "UNIX_TIMESTAMP(last_tm) FROM user_online "
186     "WHERE last_tm >= SUBDATE(NOW(), INTERVAL %d SECOND) "
187     "ORDER BY last_tm DESC",
188     BBS_user_off_line);
189    
190     if (mysql_query(db, sql) != 0)
191     {
192     log_error("Query user online error: %s\n", mysql_error(db));
193     ret = -1;
194     goto cleanup;
195     }
196    
197     if ((rs = mysql_use_result(db)) == NULL)
198     {
199     log_error("Get user online data failed\n");
200     ret = -1;
201     goto cleanup;
202     }
203    
204     i = 0;
205     while ((row = mysql_fetch_row(rs)))
206     {
207     strncpy(p_list->users[i].session_id, row[0], sizeof(p_list->users[i].session_id) - 1);
208    
209     p_list->users[i].session_id[sizeof(p_list->users[i].session_id) - 1] = '\0';
210 sysadm 1.7 if ((ret = query_user_info(atoi(row[1]), &(p_list->users[i].user_info))) < 0)
211 sysadm 1.6 {
212     log_error("query_user_info(%d) error\n", atoi(row[1]));
213     continue;
214     }
215 sysadm 1.7 else if (ret == 0) // Guest
216     {
217     p_list->users[i].user_info.uid = 0;
218     strncpy(p_list->users[i].user_info.username, "guest", sizeof(p_list->users[i].user_info.username) - 1);
219     p_list->users[i].user_info.username[sizeof(p_list->users[i].user_info.username) - 1] = '\0';
220     strncpy(p_list->users[i].user_info.nickname, "Guest", sizeof(p_list->users[i].user_info.nickname) - 1);
221     p_list->users[i].user_info.nickname[sizeof(p_list->users[i].user_info.nickname) - 1] = '\0';
222     p_list->users[i].user_info.gender = 'M';
223     p_list->users[i].user_info.gender_pub = 0;
224     p_list->users[i].user_info.life = 150;
225     p_list->users[i].user_info.exp = 0;
226     p_list->users[i].user_info.signup_dt = 0;
227     p_list->users[i].user_info.last_login_dt = 0;
228     p_list->users[i].user_info.birthday = 0;
229     }
230 sysadm 1.6
231     strncpy(p_list->users[i].ip, row[2], sizeof(p_list->users[i].ip) - 1);
232     p_list->users[i].ip[sizeof(p_list->users[i].ip) - 1] = '\0';
233    
234     strncpy(p_list->users[i].current_action, row[3], sizeof(p_list->users[i].current_action) - 1);
235     p_list->users[i].current_action[sizeof(p_list->users[i].current_action) - 1] = '\0';
236     p_list->users[i].current_action_title = NULL;
237     if (p_list->users[i].current_action[0] == '\0')
238     {
239 sysadm 1.7 p_list->users[i].current_action_title = "";
240 sysadm 1.6 }
241     else if (trie_dict_get(p_trie_action_dict, p_list->users[i].current_action, (int64_t *)(&(p_list->users[i].current_action_title))) < 0)
242     {
243     log_error("trie_dict_get(p_trie_action_dict, %s) error on session_id=%s\n",
244     p_list->users[i].current_action, p_list->users[i].session_id);
245     continue;
246     }
247    
248     p_list->users[i].login_tm = (row[4] == NULL ? 0 : atol(row[4]));
249     p_list->users[i].last_tm = (row[5] == NULL ? 0 : atol(row[5]));
250    
251     i++;
252     if (i >= BBS_max_user_online_count)
253     {
254     log_error("Too many online users, exceed limit %d\n", BBS_max_user_online_count);
255     break;
256     }
257     }
258     mysql_free_result(rs);
259     rs = NULL;
260    
261     p_list->user_count = i;
262    
263     #ifdef _DEBUG
264     log_error("Loaded %d users\n", p_list->user_count);
265     #endif
266    
267     cleanup:
268     mysql_free_result(rs);
269    
270     return ret;
271 sysadm 1.1 }
272    
273     int user_list_pool_init(void)
274     {
275 sysadm 1.6 int shmid;
276     int semid;
277     int proj_id;
278     key_t key;
279     size_t size;
280     void *p_shm;
281     union semun arg;
282     int i;
283    
284     if (p_user_list_pool != NULL || p_trie_action_dict != NULL)
285     {
286     log_error("p_user_list_pool already initialized\n");
287     return -1;
288     }
289    
290     p_trie_action_dict = trie_dict_create();
291     if (p_trie_action_dict == NULL)
292     {
293     log_error("trie_dict_create() error\n");
294     return -1;
295     }
296    
297     for (i = 0; i < user_action_map_size; i++)
298     {
299     if (trie_dict_set(p_trie_action_dict, user_action_map[i].name, (int64_t)(user_action_map[i].title)) < 0)
300     {
301     log_error("trie_dict_set(p_trie_action_dict, %s) error\n", user_action_map[i].name);
302     }
303     }
304    
305     // Allocate shared memory
306     proj_id = (int)(time(NULL) % getpid());
307     key = ftok(VAR_USER_LIST_SHM, proj_id);
308     if (key == -1)
309     {
310     log_error("ftok(%s %d) error (%d)\n", VAR_USER_LIST_SHM, proj_id, errno);
311     return -2;
312     }
313    
314     size = sizeof(USER_LIST_POOL);
315     shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
316     if (shmid == -1)
317     {
318     log_error("shmget(size = %d) error (%d)\n", size, errno);
319     return -3;
320     }
321     p_shm = shmat(shmid, NULL, 0);
322     if (p_shm == (void *)-1)
323     {
324     log_error("shmat(shmid=%d) error (%d)\n", shmid, errno);
325     return -3;
326     }
327    
328     p_user_list_pool = p_shm;
329     p_user_list_pool->shmid = shmid;
330    
331     // Allocate semaphore as user list pool lock
332     size = 2; // r_sem and w_sem
333     semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
334     if (semid == -1)
335     {
336     log_error("semget(user_list_pool_sem, size = %d) error (%d)\n", size, errno);
337     return -3;
338     }
339    
340     // Initialize sem value to 0
341     arg.val = 0;
342     for (i = 0; i < size; i++)
343     {
344     if (semctl(semid, i, SETVAL, arg) == -1)
345     {
346     log_error("semctl(user_list_pool_sem, SETVAL) error (%d)\n", errno);
347     return -3;
348     }
349     }
350    
351     p_user_list_pool->semid = semid;
352    
353     // Set user counts to 0
354     p_user_list_pool->user_list[0].user_count = 0;
355     p_user_list_pool->user_list[1].user_count = 0;
356    
357     p_user_list_pool->p_current = &(p_user_list_pool->user_list[0]);
358     p_user_list_pool->p_new = &(p_user_list_pool->user_list[1]);
359 sysadm 1.1
360 sysadm 1.6 p_user_list_pool->p_online_current = &(p_user_list_pool->user_online_list[0]);
361     p_user_list_pool->p_online_new = &(p_user_list_pool->user_online_list[1]);
362 sysadm 1.1
363 sysadm 1.6 return 0;
364 sysadm 1.1 }
365    
366     void user_list_pool_cleanup(void)
367     {
368 sysadm 1.6 int shmid;
369 sysadm 1.1
370 sysadm 1.6 if (p_user_list_pool == NULL)
371     {
372     return;
373     }
374    
375     shmid = p_user_list_pool->shmid;
376    
377     if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)
378     {
379     log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);
380     }
381    
382     if (shmdt(p_user_list_pool) == -1)
383     {
384     log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
385     }
386    
387     if (shmctl(shmid, IPC_RMID, NULL) == -1)
388     {
389     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
390     }
391    
392     p_user_list_pool = NULL;
393    
394     if (p_trie_action_dict != NULL)
395     {
396     trie_dict_destroy(p_trie_action_dict);
397 sysadm 1.1
398 sysadm 1.6 p_trie_action_dict = NULL;
399     }
400 sysadm 1.1 }
401    
402     int set_user_list_pool_shm_readonly(void)
403     {
404 sysadm 1.6 int shmid;
405     void *p_shm;
406 sysadm 1.1
407 sysadm 1.6 if (p_user_list_pool == NULL)
408     {
409     log_error("p_user_list_pool not initialized\n");
410     return -1;
411     }
412    
413     shmid = p_user_list_pool->shmid;
414    
415     // Remap shared memory in read-only mode
416     p_shm = shmat(shmid, p_user_list_pool, SHM_RDONLY | SHM_REMAP);
417     if (p_shm == (void *)-1)
418     {
419     log_error("shmat(user_list_pool shmid = %d) error (%d)\n", shmid, errno);
420     return -3;
421     }
422 sysadm 1.1
423 sysadm 1.6 p_user_list_pool = p_shm;
424 sysadm 1.1
425 sysadm 1.6 return 0;
426 sysadm 1.1 }
427    
428     int detach_user_list_pool_shm(void)
429     {
430 sysadm 1.6 if (p_user_list_pool != NULL && shmdt(p_user_list_pool) == -1)
431     {
432     log_error("shmdt(user_list_pool) error (%d)\n", errno);
433     return -1;
434     }
435    
436     p_user_list_pool = NULL;
437    
438     return 0;
439     }
440    
441     int user_list_pool_reload(int online_user)
442     {
443     MYSQL *db = NULL;
444     USER_LIST *p_tmp;
445     USER_ONLINE_LIST *p_online_tmp;
446    
447     if (p_user_list_pool == NULL)
448     {
449     log_error("p_user_list_pool not initialized\n");
450     return -1;
451     }
452    
453     db = db_open();
454     if (db == NULL)
455     {
456     log_error("db_open() error: %s\n", mysql_error(db));
457     return -1;
458     }
459    
460     if (online_user)
461     {
462     if (user_online_list_load(db, p_user_list_pool->p_online_new) < 0)
463     {
464     log_error("user_online_list_load() error\n");
465     return -2;
466     }
467     }
468     else
469     {
470     if (user_list_load(db, p_user_list_pool->p_new) < 0)
471     {
472     log_error("user_list_load() error\n");
473     return -2;
474     }
475     }
476    
477     mysql_close(db);
478    
479     if (user_list_rw_lock(p_user_list_pool->semid) < 0)
480     {
481     log_error("user_list_rw_lock() error\n");
482     return -3;
483     }
484    
485     if (online_user)
486     {
487     // Swap p_online_current and p_online_new
488     p_online_tmp = p_user_list_pool->p_online_current;
489     p_user_list_pool->p_online_current = p_user_list_pool->p_online_new;
490     p_user_list_pool->p_online_new = p_online_tmp;
491     }
492     else
493     {
494     // Swap p_current and p_new
495     p_tmp = p_user_list_pool->p_current;
496     p_user_list_pool->p_current = p_user_list_pool->p_new;
497     p_user_list_pool->p_new = p_tmp;
498     }
499    
500     if (user_list_rw_unlock(p_user_list_pool->semid) < 0)
501     {
502     log_error("user_list_rw_unlock() error\n");
503     return -3;
504     }
505 sysadm 1.1
506 sysadm 1.6 return 0;
507 sysadm 1.1 }
508    
509 sysadm 1.5 int user_list_try_rd_lock(int semid, int wait_sec)
510 sysadm 1.1 {
511 sysadm 1.6 struct sembuf sops[2];
512     struct timespec timeout;
513     int ret;
514    
515     sops[0].sem_num = 1; // w_sem
516     sops[0].sem_op = 0; // wait until unlocked
517     sops[0].sem_flg = 0;
518    
519     sops[1].sem_num = 0; // r_sem
520     sops[1].sem_op = 1; // lock
521     sops[1].sem_flg = SEM_UNDO; // undo on terminate
522    
523     timeout.tv_sec = wait_sec;
524     timeout.tv_nsec = 0;
525    
526     ret = semtimedop(semid, sops, 2, &timeout);
527     if (ret == -1 && errno != EAGAIN && errno != EINTR)
528     {
529     log_error("semtimedop(lock read) error %d\n", errno);
530     }
531 sysadm 1.1
532 sysadm 1.6 return ret;
533 sysadm 1.1 }
534    
535 sysadm 1.5 int user_list_try_rw_lock(int semid, int wait_sec)
536 sysadm 1.1 {
537 sysadm 1.6 struct sembuf sops[3];
538     struct timespec timeout;
539     int ret;
540    
541     sops[0].sem_num = 1; // w_sem
542     sops[0].sem_op = 0; // wait until unlocked
543     sops[0].sem_flg = 0;
544    
545     sops[1].sem_num = 1; // w_sem
546     sops[1].sem_op = 1; // lock
547     sops[1].sem_flg = SEM_UNDO; // undo on terminate
548    
549     sops[2].sem_num = 0; // r_sem
550     sops[2].sem_op = 0; // wait until unlocked
551     sops[2].sem_flg = 0;
552    
553     timeout.tv_sec = wait_sec;
554     timeout.tv_nsec = 0;
555    
556     ret = semtimedop(semid, sops, 3, &timeout);
557     if (ret == -1 && errno != EAGAIN && errno != EINTR)
558     {
559     log_error("semtimedop(lock write) error %d\n", errno);
560     }
561 sysadm 1.1
562 sysadm 1.6 return ret;
563 sysadm 1.1 }
564    
565 sysadm 1.5 int user_list_rd_unlock(int semid)
566 sysadm 1.1 {
567 sysadm 1.6 struct sembuf sops[2];
568     int ret;
569 sysadm 1.1
570 sysadm 1.6 sops[0].sem_num = 0; // r_sem
571     sops[0].sem_op = -1; // unlock
572     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
573    
574     ret = semop(semid, sops, 1);
575     if (ret == -1 && errno != EAGAIN && errno != EINTR)
576     {
577     log_error("semop(unlock read) error %d\n", errno);
578     }
579 sysadm 1.1
580 sysadm 1.6 return ret;
581 sysadm 1.1 }
582    
583 sysadm 1.5 int user_list_rw_unlock(int semid)
584 sysadm 1.1 {
585 sysadm 1.6 struct sembuf sops[1];
586     int ret;
587 sysadm 1.1
588 sysadm 1.6 sops[0].sem_num = 1; // w_sem
589     sops[0].sem_op = -1; // unlock
590     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
591    
592     ret = semop(semid, sops, 1);
593     if (ret == -1 && errno != EAGAIN && errno != EINTR)
594     {
595     log_error("semop(unlock write) error %d\n", errno);
596     }
597 sysadm 1.1
598 sysadm 1.6 return ret;
599 sysadm 1.1 }
600    
601 sysadm 1.5 int user_list_rd_lock(int semid)
602 sysadm 1.1 {
603 sysadm 1.6 int timer = 0;
604     int ret = -1;
605 sysadm 1.1
606 sysadm 1.6 while (!SYS_server_exit)
607     {
608     ret = user_list_try_rd_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
609     if (ret == 0) // success
610     {
611     break;
612     }
613     else if (errno == EAGAIN || errno == EINTR) // retry
614     {
615     timer++;
616     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
617     {
618     log_error("user_list_try_rd_lock() tried %d times\n", timer);
619     }
620     }
621     else // failed
622     {
623     log_error("user_list_try_rd_lock() failed\n");
624     break;
625     }
626     }
627 sysadm 1.1
628 sysadm 1.6 return ret;
629 sysadm 1.1 }
630    
631 sysadm 1.5 int user_list_rw_lock(int semid)
632 sysadm 1.1 {
633 sysadm 1.6 int timer = 0;
634     int ret = -1;
635 sysadm 1.1
636 sysadm 1.6 while (!SYS_server_exit)
637     {
638     ret = user_list_try_rw_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
639     if (ret == 0) // success
640     {
641     break;
642     }
643     else if (errno == EAGAIN || errno == EINTR) // retry
644     {
645     timer++;
646     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
647     {
648     log_error("user_list_try_rw_lock() tried %d times\n", timer);
649     }
650     }
651     else // failed
652     {
653     log_error("user_list_try_rw_lock() failed\n");
654     break;
655     }
656     }
657 sysadm 1.1
658 sysadm 1.6 return ret;
659 sysadm 1.1 }
660 sysadm 1.2
661     int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
662     {
663 sysadm 1.6 int ret = 0;
664 sysadm 1.2
665 sysadm 1.6 if (p_users == NULL || p_user_count == NULL || p_page_count == NULL)
666     {
667     log_error("NULL pointer error\n");
668     return -1;
669     }
670    
671     // acquire lock of user list
672     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
673     {
674     log_error("user_list_rd_lock() error\n");
675     return -2;
676     }
677    
678     if (p_user_list_pool->p_current->user_count == 0)
679     {
680     // empty list
681     ret = 0;
682     goto cleanup;
683     }
684    
685     *p_page_count = p_user_list_pool->p_current->user_count / BBS_user_limit_per_page +
686     (p_user_list_pool->p_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
687    
688     if (page_id < 0 || page_id >= *p_page_count)
689     {
690     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
691     ret = -3;
692     goto cleanup;
693     }
694    
695     *p_user_count = MIN(BBS_user_limit_per_page,
696     p_user_list_pool->p_current->user_count -
697     page_id * BBS_user_limit_per_page);
698    
699     memcpy(p_users,
700     p_user_list_pool->p_current->users + page_id * BBS_user_limit_per_page,
701     sizeof(USER_INFO) * (size_t)(*p_user_count));
702    
703     cleanup:
704     // release lock of user list
705     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
706     {
707     log_error("user_list_rd_unlock() error\n");
708     ret = -1;
709     }
710    
711     return ret;
712     }
713    
714     int query_user_online_list(int page_id, USER_ONLINE_INFO *p_online_users, int *p_user_count, int *p_page_count)
715     {
716     int ret = 0;
717    
718     if (p_online_users == NULL || p_user_count == NULL || p_page_count == NULL)
719     {
720     log_error("NULL pointer error\n");
721     return -1;
722     }
723    
724     // acquire lock of user list
725     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
726     {
727     log_error("user_list_rd_lock() error\n");
728     return -2;
729     }
730    
731     if (p_user_list_pool->p_online_current->user_count == 0)
732     {
733     // empty list
734     ret = 0;
735     goto cleanup;
736     }
737    
738     *p_page_count = p_user_list_pool->p_online_current->user_count / BBS_user_limit_per_page +
739     (p_user_list_pool->p_online_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
740    
741     if (page_id < 0 || page_id >= *p_page_count)
742     {
743     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
744     ret = -3;
745     goto cleanup;
746     }
747    
748     *p_user_count = MIN(BBS_user_limit_per_page,
749     p_user_list_pool->p_online_current->user_count -
750     page_id * BBS_user_limit_per_page);
751    
752     memcpy(p_online_users,
753     p_user_list_pool->p_online_current->users + page_id * BBS_user_limit_per_page,
754     sizeof(USER_ONLINE_INFO) * (size_t)(*p_user_count));
755 sysadm 1.2
756     cleanup:
757 sysadm 1.6 // release lock of user list
758     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
759     {
760     log_error("user_list_rd_unlock() error\n");
761     ret = -1;
762     }
763 sysadm 1.2
764 sysadm 1.6 return ret;
765 sysadm 1.2 }
766 sysadm 1.4
767     int query_user_info(int32_t uid, USER_INFO *p_user)
768     {
769 sysadm 1.6 int left;
770     int right;
771     int mid;
772     int ret = 0;
773    
774     if (p_user == NULL)
775     {
776     log_error("NULL pointer error\n");
777     return -1;
778     }
779    
780     // acquire lock of user list
781     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
782     {
783     log_error("user_list_rd_lock() error\n");
784     return -2;
785     }
786    
787     left = 0;
788     right = p_user_list_pool->p_current->user_count - 1;
789    
790     while (left < right)
791     {
792     mid = (left + right) / 2;
793     if (uid < p_user_list_pool->p_current->users[mid].uid)
794     {
795     right = mid;
796     }
797     else if (uid > p_user_list_pool->p_current->users[mid].uid)
798     {
799     left = mid + 1;
800     }
801     else // if (uid == p_user_list_pool->p_current->users[mid].uid)
802     {
803     left = mid;
804     break;
805     }
806     }
807    
808     if (uid == p_user_list_pool->p_current->users[left].uid) // Found
809     {
810     *p_user = p_user_list_pool->p_current->users[left];
811     ret = 1;
812     }
813    
814     // release lock of user list
815     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
816     {
817     log_error("user_list_rd_unlock() error\n");
818     ret = -1;
819     }
820 sysadm 1.4
821 sysadm 1.6 return ret;
822 sysadm 1.4 }

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