/[LeafOK_CVS]/lbbs/src/user_list.c
ViewVC logotype

Contents of /lbbs/src/user_list.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (show annotations)
Wed Oct 22 07:39:02 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.8: +3 -15 lines
Content type: text/x-csrc
Remove guest from online user list

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

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