/[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.16 - (show annotations)
Thu Oct 23 01:29:43 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.15: +0 -7 lines
Content type: text/x-csrc
Set user_list_[rd|rw]_(un)lock as public functions

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

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