/[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.8 - (show annotations)
Wed Oct 22 07:16:48 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.7: +110 -9 lines
Content type: text/x-csrc
Set sort order of user list as by username
Add query_user_info_by_uid()

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) "
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) // Guest
242 {
243 p_list->users[i].user_info.id = -1;
244 p_list->users[i].user_info.uid = 0;
245 strncpy(p_list->users[i].user_info.username, "guest", sizeof(p_list->users[i].user_info.username) - 1);
246 p_list->users[i].user_info.username[sizeof(p_list->users[i].user_info.username) - 1] = '\0';
247 strncpy(p_list->users[i].user_info.nickname, "Guest", sizeof(p_list->users[i].user_info.nickname) - 1);
248 p_list->users[i].user_info.nickname[sizeof(p_list->users[i].user_info.nickname) - 1] = '\0';
249 p_list->users[i].user_info.gender = 'M';
250 p_list->users[i].user_info.gender_pub = 0;
251 p_list->users[i].user_info.life = 150;
252 p_list->users[i].user_info.exp = 0;
253 p_list->users[i].user_info.signup_dt = 0;
254 p_list->users[i].user_info.last_login_dt = 0;
255 p_list->users[i].user_info.birthday = 0;
256 }
257
258 strncpy(p_list->users[i].ip, row[2], sizeof(p_list->users[i].ip) - 1);
259 p_list->users[i].ip[sizeof(p_list->users[i].ip) - 1] = '\0';
260
261 strncpy(p_list->users[i].current_action, row[3], sizeof(p_list->users[i].current_action) - 1);
262 p_list->users[i].current_action[sizeof(p_list->users[i].current_action) - 1] = '\0';
263 p_list->users[i].current_action_title = NULL;
264 if (p_list->users[i].current_action[0] == '\0')
265 {
266 p_list->users[i].current_action_title = "";
267 }
268 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)
269 {
270 log_error("trie_dict_get(p_trie_action_dict, %s) error on session_id=%s\n",
271 p_list->users[i].current_action, p_list->users[i].session_id);
272 continue;
273 }
274
275 p_list->users[i].login_tm = (row[4] == NULL ? 0 : atol(row[4]));
276 p_list->users[i].last_tm = (row[5] == NULL ? 0 : atol(row[5]));
277
278 i++;
279 if (i >= BBS_max_user_online_count)
280 {
281 log_error("Too many online users, exceed limit %d\n", BBS_max_user_online_count);
282 break;
283 }
284 }
285 mysql_free_result(rs);
286 rs = NULL;
287
288 p_list->user_count = i;
289
290 #ifdef _DEBUG
291 log_error("Loaded %d users\n", p_list->user_count);
292 #endif
293
294 cleanup:
295 mysql_free_result(rs);
296
297 return ret;
298 }
299
300 int user_list_pool_init(void)
301 {
302 int shmid;
303 int semid;
304 int proj_id;
305 key_t key;
306 size_t size;
307 void *p_shm;
308 union semun arg;
309 int i;
310
311 if (p_user_list_pool != NULL || p_trie_action_dict != NULL)
312 {
313 log_error("p_user_list_pool already initialized\n");
314 return -1;
315 }
316
317 p_trie_action_dict = trie_dict_create();
318 if (p_trie_action_dict == NULL)
319 {
320 log_error("trie_dict_create() error\n");
321 return -1;
322 }
323
324 for (i = 0; i < user_action_map_size; i++)
325 {
326 if (trie_dict_set(p_trie_action_dict, user_action_map[i].name, (int64_t)(user_action_map[i].title)) < 0)
327 {
328 log_error("trie_dict_set(p_trie_action_dict, %s) error\n", user_action_map[i].name);
329 }
330 }
331
332 // Allocate shared memory
333 proj_id = (int)(time(NULL) % getpid());
334 key = ftok(VAR_USER_LIST_SHM, proj_id);
335 if (key == -1)
336 {
337 log_error("ftok(%s %d) error (%d)\n", VAR_USER_LIST_SHM, proj_id, errno);
338 return -2;
339 }
340
341 size = sizeof(USER_LIST_POOL);
342 shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
343 if (shmid == -1)
344 {
345 log_error("shmget(size = %d) error (%d)\n", size, errno);
346 return -3;
347 }
348 p_shm = shmat(shmid, NULL, 0);
349 if (p_shm == (void *)-1)
350 {
351 log_error("shmat(shmid=%d) error (%d)\n", shmid, errno);
352 return -3;
353 }
354
355 p_user_list_pool = p_shm;
356 p_user_list_pool->shmid = shmid;
357
358 // Allocate semaphore as user list pool lock
359 size = 2; // r_sem and w_sem
360 semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
361 if (semid == -1)
362 {
363 log_error("semget(user_list_pool_sem, size = %d) error (%d)\n", size, errno);
364 return -3;
365 }
366
367 // Initialize sem value to 0
368 arg.val = 0;
369 for (i = 0; i < size; i++)
370 {
371 if (semctl(semid, i, SETVAL, arg) == -1)
372 {
373 log_error("semctl(user_list_pool_sem, SETVAL) error (%d)\n", errno);
374 return -3;
375 }
376 }
377
378 p_user_list_pool->semid = semid;
379
380 // Set user counts to 0
381 p_user_list_pool->user_list[0].user_count = 0;
382 p_user_list_pool->user_list[1].user_count = 0;
383
384 p_user_list_pool->p_current = &(p_user_list_pool->user_list[0]);
385 p_user_list_pool->p_new = &(p_user_list_pool->user_list[1]);
386
387 p_user_list_pool->p_online_current = &(p_user_list_pool->user_online_list[0]);
388 p_user_list_pool->p_online_new = &(p_user_list_pool->user_online_list[1]);
389
390 return 0;
391 }
392
393 void user_list_pool_cleanup(void)
394 {
395 int shmid;
396
397 if (p_user_list_pool == NULL)
398 {
399 return;
400 }
401
402 shmid = p_user_list_pool->shmid;
403
404 if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)
405 {
406 log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);
407 }
408
409 if (shmdt(p_user_list_pool) == -1)
410 {
411 log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
412 }
413
414 if (shmctl(shmid, IPC_RMID, NULL) == -1)
415 {
416 log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
417 }
418
419 p_user_list_pool = NULL;
420
421 if (p_trie_action_dict != NULL)
422 {
423 trie_dict_destroy(p_trie_action_dict);
424
425 p_trie_action_dict = NULL;
426 }
427 }
428
429 int set_user_list_pool_shm_readonly(void)
430 {
431 int shmid;
432 void *p_shm;
433
434 if (p_user_list_pool == NULL)
435 {
436 log_error("p_user_list_pool not initialized\n");
437 return -1;
438 }
439
440 shmid = p_user_list_pool->shmid;
441
442 // Remap shared memory in read-only mode
443 p_shm = shmat(shmid, p_user_list_pool, SHM_RDONLY | SHM_REMAP);
444 if (p_shm == (void *)-1)
445 {
446 log_error("shmat(user_list_pool shmid = %d) error (%d)\n", shmid, errno);
447 return -3;
448 }
449
450 p_user_list_pool = p_shm;
451
452 return 0;
453 }
454
455 int detach_user_list_pool_shm(void)
456 {
457 if (p_user_list_pool != NULL && shmdt(p_user_list_pool) == -1)
458 {
459 log_error("shmdt(user_list_pool) error (%d)\n", errno);
460 return -1;
461 }
462
463 p_user_list_pool = NULL;
464
465 return 0;
466 }
467
468 int user_list_pool_reload(int online_user)
469 {
470 MYSQL *db = NULL;
471 USER_LIST *p_tmp;
472 USER_ONLINE_LIST *p_online_tmp;
473
474 if (p_user_list_pool == NULL)
475 {
476 log_error("p_user_list_pool not initialized\n");
477 return -1;
478 }
479
480 db = db_open();
481 if (db == NULL)
482 {
483 log_error("db_open() error: %s\n", mysql_error(db));
484 return -1;
485 }
486
487 if (online_user)
488 {
489 if (user_online_list_load(db, p_user_list_pool->p_online_new) < 0)
490 {
491 log_error("user_online_list_load() error\n");
492 return -2;
493 }
494 }
495 else
496 {
497 if (user_list_load(db, p_user_list_pool->p_new) < 0)
498 {
499 log_error("user_list_load() error\n");
500 return -2;
501 }
502 }
503
504 mysql_close(db);
505
506 if (user_list_rw_lock(p_user_list_pool->semid) < 0)
507 {
508 log_error("user_list_rw_lock() error\n");
509 return -3;
510 }
511
512 if (online_user)
513 {
514 // Swap p_online_current and p_online_new
515 p_online_tmp = p_user_list_pool->p_online_current;
516 p_user_list_pool->p_online_current = p_user_list_pool->p_online_new;
517 p_user_list_pool->p_online_new = p_online_tmp;
518 }
519 else
520 {
521 // Swap p_current and p_new
522 p_tmp = p_user_list_pool->p_current;
523 p_user_list_pool->p_current = p_user_list_pool->p_new;
524 p_user_list_pool->p_new = p_tmp;
525 }
526
527 if (user_list_rw_unlock(p_user_list_pool->semid) < 0)
528 {
529 log_error("user_list_rw_unlock() error\n");
530 return -3;
531 }
532
533 return 0;
534 }
535
536 int user_list_try_rd_lock(int semid, int wait_sec)
537 {
538 struct sembuf sops[2];
539 struct timespec timeout;
540 int ret;
541
542 sops[0].sem_num = 1; // w_sem
543 sops[0].sem_op = 0; // wait until unlocked
544 sops[0].sem_flg = 0;
545
546 sops[1].sem_num = 0; // r_sem
547 sops[1].sem_op = 1; // lock
548 sops[1].sem_flg = SEM_UNDO; // undo on terminate
549
550 timeout.tv_sec = wait_sec;
551 timeout.tv_nsec = 0;
552
553 ret = semtimedop(semid, sops, 2, &timeout);
554 if (ret == -1 && errno != EAGAIN && errno != EINTR)
555 {
556 log_error("semtimedop(lock read) error %d\n", errno);
557 }
558
559 return ret;
560 }
561
562 int user_list_try_rw_lock(int semid, int wait_sec)
563 {
564 struct sembuf sops[3];
565 struct timespec timeout;
566 int ret;
567
568 sops[0].sem_num = 1; // w_sem
569 sops[0].sem_op = 0; // wait until unlocked
570 sops[0].sem_flg = 0;
571
572 sops[1].sem_num = 1; // w_sem
573 sops[1].sem_op = 1; // lock
574 sops[1].sem_flg = SEM_UNDO; // undo on terminate
575
576 sops[2].sem_num = 0; // r_sem
577 sops[2].sem_op = 0; // wait until unlocked
578 sops[2].sem_flg = 0;
579
580 timeout.tv_sec = wait_sec;
581 timeout.tv_nsec = 0;
582
583 ret = semtimedop(semid, sops, 3, &timeout);
584 if (ret == -1 && errno != EAGAIN && errno != EINTR)
585 {
586 log_error("semtimedop(lock write) error %d\n", errno);
587 }
588
589 return ret;
590 }
591
592 int user_list_rd_unlock(int semid)
593 {
594 struct sembuf sops[2];
595 int ret;
596
597 sops[0].sem_num = 0; // r_sem
598 sops[0].sem_op = -1; // unlock
599 sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
600
601 ret = semop(semid, sops, 1);
602 if (ret == -1 && errno != EAGAIN && errno != EINTR)
603 {
604 log_error("semop(unlock read) error %d\n", errno);
605 }
606
607 return ret;
608 }
609
610 int user_list_rw_unlock(int semid)
611 {
612 struct sembuf sops[1];
613 int ret;
614
615 sops[0].sem_num = 1; // w_sem
616 sops[0].sem_op = -1; // unlock
617 sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
618
619 ret = semop(semid, sops, 1);
620 if (ret == -1 && errno != EAGAIN && errno != EINTR)
621 {
622 log_error("semop(unlock write) error %d\n", errno);
623 }
624
625 return ret;
626 }
627
628 int user_list_rd_lock(int semid)
629 {
630 int timer = 0;
631 int ret = -1;
632
633 while (!SYS_server_exit)
634 {
635 ret = user_list_try_rd_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
636 if (ret == 0) // success
637 {
638 break;
639 }
640 else if (errno == EAGAIN || errno == EINTR) // retry
641 {
642 timer++;
643 if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
644 {
645 log_error("user_list_try_rd_lock() tried %d times\n", timer);
646 }
647 }
648 else // failed
649 {
650 log_error("user_list_try_rd_lock() failed\n");
651 break;
652 }
653 }
654
655 return ret;
656 }
657
658 int user_list_rw_lock(int semid)
659 {
660 int timer = 0;
661 int ret = -1;
662
663 while (!SYS_server_exit)
664 {
665 ret = user_list_try_rw_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
666 if (ret == 0) // success
667 {
668 break;
669 }
670 else if (errno == EAGAIN || errno == EINTR) // retry
671 {
672 timer++;
673 if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
674 {
675 log_error("user_list_try_rw_lock() tried %d times\n", timer);
676 }
677 }
678 else // failed
679 {
680 log_error("user_list_try_rw_lock() failed\n");
681 break;
682 }
683 }
684
685 return ret;
686 }
687
688 int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
689 {
690 int ret = 0;
691
692 if (p_users == NULL || p_user_count == NULL || p_page_count == NULL)
693 {
694 log_error("NULL pointer error\n");
695 return -1;
696 }
697
698 // acquire lock of user list
699 if (user_list_rd_lock(p_user_list_pool->semid) < 0)
700 {
701 log_error("user_list_rd_lock() error\n");
702 return -2;
703 }
704
705 if (p_user_list_pool->p_current->user_count == 0)
706 {
707 // empty list
708 ret = 0;
709 goto cleanup;
710 }
711
712 *p_page_count = p_user_list_pool->p_current->user_count / BBS_user_limit_per_page +
713 (p_user_list_pool->p_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
714
715 if (page_id < 0 || page_id >= *p_page_count)
716 {
717 log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
718 ret = -3;
719 goto cleanup;
720 }
721
722 *p_user_count = MIN(BBS_user_limit_per_page,
723 p_user_list_pool->p_current->user_count -
724 page_id * BBS_user_limit_per_page);
725
726 memcpy(p_users,
727 p_user_list_pool->p_current->users + page_id * BBS_user_limit_per_page,
728 sizeof(USER_INFO) * (size_t)(*p_user_count));
729
730 cleanup:
731 // release lock of user list
732 if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
733 {
734 log_error("user_list_rd_unlock() error\n");
735 ret = -1;
736 }
737
738 return ret;
739 }
740
741 int query_user_online_list(int page_id, USER_ONLINE_INFO *p_online_users, int *p_user_count, int *p_page_count)
742 {
743 int ret = 0;
744
745 if (p_online_users == NULL || p_user_count == NULL || p_page_count == NULL)
746 {
747 log_error("NULL pointer error\n");
748 return -1;
749 }
750
751 // acquire lock of user list
752 if (user_list_rd_lock(p_user_list_pool->semid) < 0)
753 {
754 log_error("user_list_rd_lock() error\n");
755 return -2;
756 }
757
758 if (p_user_list_pool->p_online_current->user_count == 0)
759 {
760 // empty list
761 ret = 0;
762 goto cleanup;
763 }
764
765 *p_page_count = p_user_list_pool->p_online_current->user_count / BBS_user_limit_per_page +
766 (p_user_list_pool->p_online_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
767
768 if (page_id < 0 || page_id >= *p_page_count)
769 {
770 log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
771 ret = -3;
772 goto cleanup;
773 }
774
775 *p_user_count = MIN(BBS_user_limit_per_page,
776 p_user_list_pool->p_online_current->user_count -
777 page_id * BBS_user_limit_per_page);
778
779 memcpy(p_online_users,
780 p_user_list_pool->p_online_current->users + page_id * BBS_user_limit_per_page,
781 sizeof(USER_ONLINE_INFO) * (size_t)(*p_user_count));
782
783 cleanup:
784 // release lock of user list
785 if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
786 {
787 log_error("user_list_rd_unlock() error\n");
788 ret = -1;
789 }
790
791 return ret;
792 }
793
794 int query_user_info(int32_t id, USER_INFO *p_user)
795 {
796 int ret = 0;
797
798 if (p_user == NULL)
799 {
800 log_error("NULL pointer error\n");
801 return -1;
802 }
803
804 // acquire lock of user list
805 if (user_list_rd_lock(p_user_list_pool->semid) < 0)
806 {
807 log_error("user_list_rd_lock() error\n");
808 return -2;
809 }
810
811 if (id >= 0 && id < p_user_list_pool->p_current->user_count) // Found
812 {
813 *p_user = p_user_list_pool->p_current->users[id];
814 ret = 1;
815 }
816
817 // release lock of user list
818 if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
819 {
820 log_error("user_list_rd_unlock() error\n");
821 ret = -1;
822 }
823
824 return ret;
825 }
826
827 int query_user_info_by_uid(int32_t uid, USER_INFO *p_user)
828 {
829 int left;
830 int right;
831 int mid;
832 int32_t id;
833 int ret = 0;
834
835 if (p_user == NULL)
836 {
837 log_error("NULL pointer error\n");
838 return -1;
839 }
840
841 // acquire lock of user list
842 if (user_list_rd_lock(p_user_list_pool->semid) < 0)
843 {
844 log_error("user_list_rd_lock() error\n");
845 return -2;
846 }
847
848 left = 0;
849 right = p_user_list_pool->p_current->user_count - 1;
850
851 while (left < right)
852 {
853 mid = (left + right) / 2;
854 if (uid < p_user_list_pool->p_current->index_uid[mid].uid)
855 {
856 right = mid;
857 }
858 else if (uid > p_user_list_pool->p_current->index_uid[mid].uid)
859 {
860 left = mid + 1;
861 }
862 else // if (uid == p_user_list_pool->p_current->index_uid[mid].uid)
863 {
864 left = mid;
865 break;
866 }
867 }
868
869 if (uid == p_user_list_pool->p_current->index_uid[left].uid) // Found
870 {
871 id = p_user_list_pool->p_current->index_uid[left].id;
872 if ((ret = query_user_info(id, p_user)) <= 0)
873 {
874 log_error("query_user_info(id=%d) error: %d\n", id, ret);
875 }
876 else
877 {
878 ret = 1;
879 }
880 }
881
882 // release lock of user list
883 if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
884 {
885 log_error("user_list_rd_unlock() error\n");
886 ret = -1;
887 }
888
889 return ret;
890 }
891
892 int query_user_online_info(int32_t id, USER_ONLINE_INFO *p_user)
893 {
894 int ret = 0;
895
896 if (p_user == NULL)
897 {
898 log_error("NULL pointer error\n");
899 return -1;
900 }
901
902 // acquire lock of user list
903 if (user_list_rd_lock(p_user_list_pool->semid) < 0)
904 {
905 log_error("user_list_rd_lock() error\n");
906 return -2;
907 }
908
909 if (id >= 0 && id < p_user_list_pool->p_online_current->user_count) // Found
910 {
911 *p_user = p_user_list_pool->p_online_current->users[id];
912 ret = 1;
913 }
914
915 // release lock of user list
916 if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
917 {
918 log_error("user_list_rd_unlock() error\n");
919 ret = -1;
920 }
921
922 return ret;
923 }

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