/[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.8 - (hide 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 sysadm 1.1 /***************************************************************************
2 sysadm 1.6 user_list.c - description
3     -------------------
4     Copyright : (C) 2004-2025 by Leaflet
5     Email : leaflet@leafok.com
6 sysadm 1.1 ***************************************************************************/
7    
8     /***************************************************************************
9     * *
10     * This program is free software; you can redistribute it and/or modify *
11     * it under the terms of the GNU General Public License as published by *
12     * the Free Software Foundation; either version 3 of the License, or *
13     * (at your option) any later version. *
14     * *
15     ***************************************************************************/
16    
17     #include "common.h"
18     #include "database.h"
19     #include "log.h"
20 sysadm 1.6 #include "trie_dict.h"
21 sysadm 1.1 #include "user_list.h"
22     #include <errno.h>
23     #include <stdlib.h>
24     #include <string.h>
25     #include <time.h>
26     #include <sys/ipc.h>
27     #include <sys/mman.h>
28 sysadm 1.2 #include <sys/param.h>
29 sysadm 1.1 #include <sys/sem.h>
30     #include <sys/shm.h>
31    
32     #ifdef _SEM_SEMUN_UNDEFINED
33     union semun
34     {
35 sysadm 1.6 int val; /* Value for SETVAL */
36     struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
37     unsigned short *array; /* Array for GETALL, SETALL */
38     struct seminfo *__buf; /* Buffer for IPC_INFO
39     (Linux-specific) */
40 sysadm 1.1 };
41     #endif // #ifdef _SEM_SEMUN_UNDEFINED
42    
43     #define USER_LIST_TRY_LOCK_WAIT_TIME 1 // second
44     #define USER_LIST_TRY_LOCK_TIMES 10
45    
46     struct user_list_pool_t
47     {
48 sysadm 1.6 int shmid;
49     int semid;
50     USER_LIST user_list[2];
51     USER_LIST *p_current;
52     USER_LIST *p_new;
53     USER_ONLINE_LIST user_online_list[2];
54     USER_ONLINE_LIST *p_online_current;
55     USER_ONLINE_LIST *p_online_new;
56 sysadm 1.1 };
57     typedef struct user_list_pool_t USER_LIST_POOL;
58    
59     static USER_LIST_POOL *p_user_list_pool = NULL;
60 sysadm 1.6 static TRIE_NODE *p_trie_action_dict = NULL;
61    
62     typedef struct user_action_map_t
63     {
64     char name[BBS_current_action_max_len + 1];
65     char title[BBS_current_action_max_len + 1];
66     } USER_ACTION_MAP;
67    
68     const USER_ACTION_MAP user_action_map[] =
69     {
70     {"ARTICLE_FAVOR", "浏览收藏"},
71     {"BBS_NET", "站点穿梭"},
72     {"CHICKEN", "电子小鸡"},
73     {"EDIT_ARTICLE", "修改文章"},
74 sysadm 1.7 {"LOGIN", "进入大厅"},
75 sysadm 1.6 {"MENU", "菜单选择"},
76     {"POST_ARTICLE", "撰写文章"},
77     {"REPLY_ARTICLE", "回复文章"},
78     {"USER_LIST", "查花名册"},
79     {"USER_ONLINE", "环顾四周"},
80     {"VIEW_ARTICLE", "阅读文章"},
81 sysadm 1.7 {"VIEW_FILE", "查看文档"},
82     {"WWW", "Web浏览"}};
83 sysadm 1.6
84 sysadm 1.7 const int user_action_map_size = sizeof(user_action_map) / sizeof(USER_ACTION_MAP);
85 sysadm 1.1
86 sysadm 1.5 static int user_list_try_rd_lock(int semid, int wait_sec);
87     static int user_list_try_rw_lock(int semid, int wait_sec);
88     static int user_list_rd_unlock(int semid);
89     static int user_list_rw_unlock(int semid);
90     static int user_list_rd_lock(int semid);
91     static int user_list_rw_lock(int semid);
92    
93 sysadm 1.6 static int user_list_load(MYSQL *db, USER_LIST *p_list);
94     static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list);
95    
96 sysadm 1.8 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 sysadm 1.1 int user_list_load(MYSQL *db, USER_LIST *p_list)
113     {
114 sysadm 1.6 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 sysadm 1.8 "WHERE enable ORDER BY username");
132 sysadm 1.6
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 sysadm 1.8 // record
151     p_list->users[i].id = i;
152 sysadm 1.6 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 sysadm 1.8 // index
166     p_list->index_uid[i].uid = p_list->users[i].uid;
167     p_list->index_uid[i].id = i;
168    
169 sysadm 1.6 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 sysadm 1.1
179 sysadm 1.6 p_list->user_count = i;
180 sysadm 1.1
181 sysadm 1.8 // Sort index
182     qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
183    
184 sysadm 1.1 #ifdef _DEBUG
185 sysadm 1.6 log_error("Loaded %d users\n", p_list->user_count);
186 sysadm 1.1 #endif
187    
188     cleanup:
189 sysadm 1.6 mysql_free_result(rs);
190 sysadm 1.1
191 sysadm 1.6 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 sysadm 1.8 p_list->users[i].id = i;
233 sysadm 1.6 strncpy(p_list->users[i].session_id, row[0], sizeof(p_list->users[i].session_id) - 1);
234 sysadm 1.8 p_list->users[i].session_id[sizeof(p_list->users[i].session_id) - 1] = '\0';
235 sysadm 1.6
236 sysadm 1.8 if ((ret = query_user_info_by_uid(atoi(row[1]), &(p_list->users[i].user_info))) < 0)
237 sysadm 1.6 {
238     log_error("query_user_info(%d) error\n", atoi(row[1]));
239     continue;
240     }
241 sysadm 1.7 else if (ret == 0) // Guest
242     {
243 sysadm 1.8 p_list->users[i].user_info.id = -1;
244 sysadm 1.7 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 sysadm 1.6
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 sysadm 1.7 p_list->users[i].current_action_title = "";
267 sysadm 1.6 }
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 sysadm 1.1 }
299    
300     int user_list_pool_init(void)
301     {
302 sysadm 1.6 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 sysadm 1.1
387 sysadm 1.6 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 sysadm 1.1
390 sysadm 1.6 return 0;
391 sysadm 1.1 }
392    
393     void user_list_pool_cleanup(void)
394     {
395 sysadm 1.6 int shmid;
396 sysadm 1.1
397 sysadm 1.6 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 sysadm 1.1
425 sysadm 1.6 p_trie_action_dict = NULL;
426     }
427 sysadm 1.1 }
428    
429     int set_user_list_pool_shm_readonly(void)
430     {
431 sysadm 1.6 int shmid;
432     void *p_shm;
433 sysadm 1.1
434 sysadm 1.6 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 sysadm 1.1
450 sysadm 1.6 p_user_list_pool = p_shm;
451 sysadm 1.1
452 sysadm 1.6 return 0;
453 sysadm 1.1 }
454    
455     int detach_user_list_pool_shm(void)
456     {
457 sysadm 1.6 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 sysadm 1.1
533 sysadm 1.6 return 0;
534 sysadm 1.1 }
535    
536 sysadm 1.5 int user_list_try_rd_lock(int semid, int wait_sec)
537 sysadm 1.1 {
538 sysadm 1.6 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 sysadm 1.1
559 sysadm 1.6 return ret;
560 sysadm 1.1 }
561    
562 sysadm 1.5 int user_list_try_rw_lock(int semid, int wait_sec)
563 sysadm 1.1 {
564 sysadm 1.6 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 sysadm 1.1
589 sysadm 1.6 return ret;
590 sysadm 1.1 }
591    
592 sysadm 1.5 int user_list_rd_unlock(int semid)
593 sysadm 1.1 {
594 sysadm 1.6 struct sembuf sops[2];
595     int ret;
596 sysadm 1.1
597 sysadm 1.6 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 sysadm 1.1
607 sysadm 1.6 return ret;
608 sysadm 1.1 }
609    
610 sysadm 1.5 int user_list_rw_unlock(int semid)
611 sysadm 1.1 {
612 sysadm 1.6 struct sembuf sops[1];
613     int ret;
614 sysadm 1.1
615 sysadm 1.6 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 sysadm 1.1
625 sysadm 1.6 return ret;
626 sysadm 1.1 }
627    
628 sysadm 1.5 int user_list_rd_lock(int semid)
629 sysadm 1.1 {
630 sysadm 1.6 int timer = 0;
631     int ret = -1;
632 sysadm 1.1
633 sysadm 1.6 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 sysadm 1.1
655 sysadm 1.6 return ret;
656 sysadm 1.1 }
657    
658 sysadm 1.5 int user_list_rw_lock(int semid)
659 sysadm 1.1 {
660 sysadm 1.6 int timer = 0;
661     int ret = -1;
662 sysadm 1.1
663 sysadm 1.6 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 sysadm 1.1
685 sysadm 1.6 return ret;
686 sysadm 1.1 }
687 sysadm 1.2
688     int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
689     {
690 sysadm 1.6 int ret = 0;
691 sysadm 1.2
692 sysadm 1.6 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 sysadm 1.2
783     cleanup:
784 sysadm 1.6 // 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 sysadm 1.2
791 sysadm 1.6 return ret;
792 sysadm 1.2 }
793 sysadm 1.4
794 sysadm 1.8 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 sysadm 1.4 {
829 sysadm 1.6 int left;
830     int right;
831     int mid;
832 sysadm 1.8 int32_t id;
833 sysadm 1.6 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 sysadm 1.8 if (uid < p_user_list_pool->p_current->index_uid[mid].uid)
855 sysadm 1.6 {
856     right = mid;
857     }
858 sysadm 1.8 else if (uid > p_user_list_pool->p_current->index_uid[mid].uid)
859 sysadm 1.6 {
860     left = mid + 1;
861     }
862 sysadm 1.8 else // if (uid == p_user_list_pool->p_current->index_uid[mid].uid)
863 sysadm 1.6 {
864     left = mid;
865     break;
866     }
867     }
868    
869 sysadm 1.8 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 sysadm 1.6 {
911 sysadm 1.8 *p_user = p_user_list_pool->p_online_current->users[id];
912 sysadm 1.6 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 sysadm 1.4
922 sysadm 1.6 return ret;
923 sysadm 1.4 }

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