/[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.6 - (hide annotations)
Wed Oct 22 04:48:53 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.5: +675 -456 lines
Content type: text/x-csrc
Add user_online_list

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

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