/[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.14 - (hide annotations)
Wed Oct 22 16:12:50 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.13: +21 -6 lines
Content type: text/x-csrc
Add data fields of user

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

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