/[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.13 - (hide annotations)
Wed Oct 22 14:42:08 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.12: +5 -10 lines
Content type: text/x-csrc
Fix bug
Add testing code

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

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