/[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.41 - (hide annotations)
Thu Nov 20 03:22:35 2025 UTC (3 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.40: +3 -5 lines
Content type: text/x-csrc
Refine

1 sysadm 1.26 /* SPDX-License-Identifier: GPL-3.0-or-later */
2     /*
3     * user_list
4     * - data model and basic operations of (online) user list
5     *
6 sysadm 1.28 * Copyright (C) 2004-2025 Leaflet <leaflet@leafok.com>
7 sysadm 1.26 */
8 sysadm 1.1
9 sysadm 1.32 #ifdef HAVE_CONFIG_H
10     #include "config.h"
11     #endif
12    
13 sysadm 1.1 #include "common.h"
14     #include "database.h"
15     #include "log.h"
16 sysadm 1.6 #include "trie_dict.h"
17 sysadm 1.1 #include "user_list.h"
18 sysadm 1.18 #include "user_stat.h"
19 sysadm 1.1 #include <errno.h>
20 sysadm 1.39 #include <fcntl.h>
21 sysadm 1.1 #include <stdlib.h>
22     #include <string.h>
23     #include <time.h>
24     #include <sys/mman.h>
25 sysadm 1.2 #include <sys/param.h>
26 sysadm 1.1 #include <sys/sem.h>
27 sysadm 1.39 #include <sys/stat.h>
28 sysadm 1.1
29 sysadm 1.36 #if defined(_SEM_SEMUN_UNDEFINED) || defined(__CYGWIN__)
30 sysadm 1.1 union semun
31     {
32 sysadm 1.6 int val; /* Value for SETVAL */
33     struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
34     unsigned short *array; /* Array for GETALL, SETALL */
35     struct seminfo *__buf; /* Buffer for IPC_INFO
36     (Linux-specific) */
37 sysadm 1.1 };
38 sysadm 1.34 #endif // #if defined(_SEM_SEMUN_UNDEFINED)
39 sysadm 1.1
40 sysadm 1.29 enum _user_list_constant_t
41     {
42     USER_LIST_TRY_LOCK_WAIT_TIME = 1, // second
43     USER_LIST_TRY_LOCK_TIMES = 10,
44     };
45 sysadm 1.1
46     struct user_list_pool_t
47     {
48 sysadm 1.39 size_t shm_size;
49 sysadm 1.6 int semid;
50     USER_LIST user_list[2];
51 sysadm 1.37 int user_list_index_current;
52     int user_list_index_new;
53 sysadm 1.6 USER_ONLINE_LIST user_online_list[2];
54 sysadm 1.37 int user_online_list_index_current;
55     int user_online_list_index_new;
56 sysadm 1.18 USER_STAT_MAP user_stat_map;
57 sysadm 1.24 int user_login_count;
58 sysadm 1.1 };
59     typedef struct user_list_pool_t USER_LIST_POOL;
60    
61 sysadm 1.41 static char user_list_shm_name[FILE_NAME_LEN];
62 sysadm 1.1 static USER_LIST_POOL *p_user_list_pool = NULL;
63 sysadm 1.6 static TRIE_NODE *p_trie_action_dict = NULL;
64    
65     typedef struct user_action_map_t
66     {
67     char name[BBS_current_action_max_len + 1];
68     char title[BBS_current_action_max_len + 1];
69     } USER_ACTION_MAP;
70    
71     const USER_ACTION_MAP user_action_map[] =
72     {
73     {"ARTICLE_FAVOR", "浏览收藏"},
74     {"BBS_NET", "站点穿梭"},
75     {"CHICKEN", "电子小鸡"},
76     {"EDIT_ARTICLE", "修改文章"},
77 sysadm 1.7 {"LOGIN", "进入大厅"},
78 sysadm 1.6 {"MENU", "菜单选择"},
79     {"POST_ARTICLE", "撰写文章"},
80     {"REPLY_ARTICLE", "回复文章"},
81     {"USER_LIST", "查花名册"},
82     {"USER_ONLINE", "环顾四周"},
83     {"VIEW_ARTICLE", "阅读文章"},
84 sysadm 1.7 {"VIEW_FILE", "查看文档"},
85     {"WWW", "Web浏览"}};
86 sysadm 1.6
87 sysadm 1.7 const int user_action_map_size = sizeof(user_action_map) / sizeof(USER_ACTION_MAP);
88 sysadm 1.1
89 sysadm 1.39 static int user_list_try_rd_lock(int wait_sec);
90     static int user_list_try_rw_lock(int wait_sec);
91     static int user_list_rd_unlock(void);
92     static int user_list_rw_unlock(void);
93     static int user_list_rd_lock(void);
94     static int user_list_rw_lock(void);
95 sysadm 1.17
96 sysadm 1.6 static int user_list_load(MYSQL *db, USER_LIST *p_list);
97 sysadm 1.25 static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_online_list);
98 sysadm 1.24 static int user_login_count_load(MYSQL *db);
99 sysadm 1.6
100 sysadm 1.8 static int user_info_index_uid_comp(const void *ptr1, const void *ptr2)
101     {
102     const USER_INFO_INDEX_UID *p1 = ptr1;
103     const USER_INFO_INDEX_UID *p2 = ptr2;
104    
105     if (p1->uid < p2->uid)
106     {
107     return -1;
108     }
109     else if (p1->uid > p2->uid)
110     {
111     return 1;
112     }
113 sysadm 1.10 else if (p1->id < p2->id)
114     {
115     return -1;
116     }
117     else if (p1->id > p2->id)
118     {
119     return 1;
120     }
121 sysadm 1.8 return 0;
122     }
123    
124 sysadm 1.1 int user_list_load(MYSQL *db, USER_LIST *p_list)
125     {
126 sysadm 1.6 MYSQL_RES *rs = NULL;
127     MYSQL_ROW row;
128     char sql[SQL_BUFFER_LEN];
129     int ret = 0;
130 sysadm 1.15 int i;
131     int j;
132     int32_t last_uid;
133     size_t intro_buf_offset;
134 sysadm 1.14 size_t intro_len;
135 sysadm 1.6
136     if (db == NULL || p_list == NULL)
137     {
138     log_error("NULL pointer error\n");
139     return -1;
140     }
141    
142 sysadm 1.10 if (p_list->user_count > 0)
143     {
144     last_uid = p_list->users[p_list->user_count - 1].uid;
145     }
146 sysadm 1.15 else
147     {
148     last_uid = -1;
149     }
150 sysadm 1.10
151 sysadm 1.6 snprintf(sql, sizeof(sql),
152 sysadm 1.14 "SELECT user_list.UID AS UID, username, nickname, gender, gender_pub, life, exp, visit_count, "
153 sysadm 1.21 "UNIX_TIMESTAMP(signup_dt), UNIX_TIMESTAMP(last_login_dt), UNIX_TIMESTAMP(last_logout_dt), "
154     "UNIX_TIMESTAMP(birthday), `introduction` "
155 sysadm 1.6 "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "
156     "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "
157 sysadm 1.8 "WHERE enable ORDER BY username");
158 sysadm 1.6
159     if (mysql_query(db, sql) != 0)
160     {
161     log_error("Query user info error: %s\n", mysql_error(db));
162     ret = -1;
163     goto cleanup;
164     }
165    
166     if ((rs = mysql_use_result(db)) == NULL)
167     {
168     log_error("Get user info data failed\n");
169     ret = -1;
170     goto cleanup;
171     }
172    
173 sysadm 1.14 intro_buf_offset = 0;
174 sysadm 1.6 i = 0;
175     while ((row = mysql_fetch_row(rs)))
176     {
177 sysadm 1.8 // record
178     p_list->users[i].id = i;
179 sysadm 1.6 p_list->users[i].uid = atoi(row[0]);
180     strncpy(p_list->users[i].username, row[1], sizeof(p_list->users[i].username) - 1);
181     p_list->users[i].username[sizeof(p_list->users[i].username) - 1] = '\0';
182     strncpy(p_list->users[i].nickname, row[2], sizeof(p_list->users[i].nickname) - 1);
183     p_list->users[i].nickname[sizeof(p_list->users[i].nickname) - 1] = '\0';
184     p_list->users[i].gender = row[3][0];
185     p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));
186     p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));
187     p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));
188 sysadm 1.14 p_list->users[i].visit_count = (row[7] == NULL ? 0 : atoi(row[7]));
189     p_list->users[i].signup_dt = (row[8] == NULL ? 0 : atol(row[8]));
190     p_list->users[i].last_login_dt = (row[9] == NULL ? 0 : atol(row[9]));
191 sysadm 1.21 p_list->users[i].last_logout_dt = (row[10] == NULL ? 0 : atol(row[10]));
192 sysadm 1.31 p_list->users[i].birthday = (row[11] == NULL ? 0 : atol(row[11]));
193 sysadm 1.21 intro_len = strlen((row[12] == NULL ? "" : row[12]));
194 sysadm 1.14 if (intro_len >= sizeof(p_list->user_intro_buf) - 1 - intro_buf_offset)
195     {
196     log_error("OOM for user introduction: len=%d, i=%d\n", intro_len, i);
197     break;
198     }
199     memcpy(p_list->user_intro_buf + intro_buf_offset,
200 sysadm 1.21 (row[12] == NULL ? "" : row[12]),
201 sysadm 1.14 intro_len + 1);
202     p_list->users[i].intro = p_list->user_intro_buf + intro_buf_offset;
203     intro_buf_offset += (intro_len + 1);
204 sysadm 1.6
205     i++;
206     if (i >= BBS_max_user_count)
207     {
208     log_error("Too many users, exceed limit %d\n", BBS_max_user_count);
209     break;
210     }
211     }
212     mysql_free_result(rs);
213     rs = NULL;
214 sysadm 1.1
215 sysadm 1.10 if (i != p_list->user_count || p_list->users[i - 1].uid != last_uid) // Count of users changed
216     {
217 sysadm 1.15 // Rebuild index
218     for (j = 0; j < i; j++)
219     {
220     p_list->index_uid[j].uid = p_list->users[j].uid;
221     p_list->index_uid[j].id = j;
222     }
223    
224     qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
225 sysadm 1.12
226 sysadm 1.10 #ifdef _DEBUG
227     log_error("Rebuild index of %d users, last_uid=%d\n", i, p_list->users[i - 1].uid);
228     #endif
229     }
230    
231 sysadm 1.6 p_list->user_count = i;
232 sysadm 1.1
233     #ifdef _DEBUG
234 sysadm 1.6 log_error("Loaded %d users\n", p_list->user_count);
235 sysadm 1.1 #endif
236    
237     cleanup:
238 sysadm 1.6 mysql_free_result(rs);
239 sysadm 1.1
240 sysadm 1.6 return ret;
241     }
242    
243 sysadm 1.25 int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_online_list)
244 sysadm 1.6 {
245     MYSQL_RES *rs = NULL;
246     MYSQL_ROW row;
247     char sql[SQL_BUFFER_LEN];
248     int ret = 0;
249     int i;
250 sysadm 1.15 int j;
251 sysadm 1.23 int user_cnt;
252     int guest_cnt;
253 sysadm 1.6
254 sysadm 1.25 if (db == NULL || p_online_list == NULL)
255 sysadm 1.6 {
256     log_error("NULL pointer error\n");
257     return -1;
258     }
259    
260     snprintf(sql, sizeof(sql),
261     "SELECT SID, UID, ip, current_action, UNIX_TIMESTAMP(login_tm), "
262     "UNIX_TIMESTAMP(last_tm) FROM user_online "
263 sysadm 1.23 "WHERE last_tm >= SUBDATE(NOW(), INTERVAL %d SECOND) "
264 sysadm 1.6 "ORDER BY last_tm DESC",
265     BBS_user_off_line);
266    
267     if (mysql_query(db, sql) != 0)
268     {
269     log_error("Query user online error: %s\n", mysql_error(db));
270     ret = -1;
271     goto cleanup;
272     }
273    
274     if ((rs = mysql_use_result(db)) == NULL)
275     {
276     log_error("Get user online data failed\n");
277     ret = -1;
278     goto cleanup;
279     }
280    
281     i = 0;
282 sysadm 1.23 user_cnt = 0;
283     guest_cnt = 0;
284 sysadm 1.6 while ((row = mysql_fetch_row(rs)))
285     {
286 sysadm 1.23 if (atoi(row[1]) == 0) // guest
287     {
288     guest_cnt++;
289     continue;
290     }
291     else
292     {
293     user_cnt++;
294     }
295    
296 sysadm 1.25 p_online_list->users[i].id = i;
297     strncpy(p_online_list->users[i].session_id, row[0], sizeof(p_online_list->users[i].session_id) - 1);
298     p_online_list->users[i].session_id[sizeof(p_online_list->users[i].session_id) - 1] = '\0';
299 sysadm 1.6
300 sysadm 1.25 if ((ret = query_user_info_by_uid(atoi(row[1]), &(p_online_list->users[i].user_info), NULL, 0)) <= 0)
301 sysadm 1.7 {
302 sysadm 1.12 log_error("query_user_info_by_uid(%d) error\n", atoi(row[1]));
303 sysadm 1.9 continue;
304 sysadm 1.7 }
305 sysadm 1.6
306 sysadm 1.25 strncpy(p_online_list->users[i].ip, row[2], sizeof(p_online_list->users[i].ip) - 1);
307     p_online_list->users[i].ip[sizeof(p_online_list->users[i].ip) - 1] = '\0';
308 sysadm 1.6
309 sysadm 1.25 strncpy(p_online_list->users[i].current_action, row[3], sizeof(p_online_list->users[i].current_action) - 1);
310     p_online_list->users[i].current_action[sizeof(p_online_list->users[i].current_action) - 1] = '\0';
311     p_online_list->users[i].current_action_title = NULL;
312     if (p_online_list->users[i].current_action[0] == '\0')
313 sysadm 1.6 {
314 sysadm 1.25 p_online_list->users[i].current_action_title = "";
315 sysadm 1.6 }
316 sysadm 1.25 else if (trie_dict_get(p_trie_action_dict, p_online_list->users[i].current_action, (int64_t *)(&(p_online_list->users[i].current_action_title))) < 0)
317 sysadm 1.6 {
318     log_error("trie_dict_get(p_trie_action_dict, %s) error on session_id=%s\n",
319 sysadm 1.25 p_online_list->users[i].current_action, p_online_list->users[i].session_id);
320 sysadm 1.6 continue;
321     }
322    
323 sysadm 1.25 p_online_list->users[i].login_tm = (row[4] == NULL ? 0 : atol(row[4]));
324     p_online_list->users[i].last_tm = (row[5] == NULL ? 0 : atol(row[5]));
325 sysadm 1.6
326     i++;
327     if (i >= BBS_max_user_online_count)
328     {
329     log_error("Too many online users, exceed limit %d\n", BBS_max_user_online_count);
330     break;
331     }
332     }
333     mysql_free_result(rs);
334     rs = NULL;
335    
336 sysadm 1.23 if (user_cnt > 0)
337 sysadm 1.10 {
338 sysadm 1.15 // Rebuild index
339 sysadm 1.23 for (j = 0; j < user_cnt; j++)
340 sysadm 1.15 {
341 sysadm 1.25 p_online_list->index_uid[j].uid = p_online_list->users[j].user_info.uid;
342     p_online_list->index_uid[j].id = j;
343 sysadm 1.15 }
344    
345 sysadm 1.25 qsort(p_online_list->index_uid, (size_t)user_cnt, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
346 sysadm 1.10 }
347    
348 sysadm 1.25 p_online_list->user_count = user_cnt;
349     p_online_list->guest_count = guest_cnt;
350 sysadm 1.6
351     cleanup:
352     mysql_free_result(rs);
353    
354     return ret;
355 sysadm 1.1 }
356    
357 sysadm 1.24 int user_login_count_load(MYSQL *db)
358     {
359     MYSQL_RES *rs = NULL;
360     MYSQL_ROW row;
361     char sql[SQL_BUFFER_LEN];
362    
363     if (db == NULL)
364     {
365     log_error("NULL pointer error\n");
366     return -1;
367     }
368    
369     snprintf(sql, sizeof(sql),
370     "SELECT ID FROM user_login_log ORDER BY ID DESC LIMIT 1");
371     if (mysql_query(db, sql) != 0)
372     {
373     log_error("Query user_login_log error: %s\n", mysql_error(db));
374     return -2;
375     }
376     if ((rs = mysql_store_result(db)) == NULL)
377     {
378     log_error("Get user_login_log data failed\n");
379     return -2;
380     }
381     if ((row = mysql_fetch_row(rs)))
382     {
383     p_user_list_pool->user_login_count = atoi(row[0]);
384     }
385     mysql_free_result(rs);
386    
387     return 0;
388     }
389    
390 sysadm 1.22 int user_list_pool_init(const char *filename)
391 sysadm 1.1 {
392 sysadm 1.39 char filepath[FILE_PATH_LEN];
393     int fd;
394     size_t size;
395     void *p_shm;
396 sysadm 1.6 int proj_id;
397     key_t key;
398 sysadm 1.39 int semid;
399 sysadm 1.6 union semun arg;
400     int i;
401    
402     if (p_user_list_pool != NULL || p_trie_action_dict != NULL)
403     {
404     log_error("p_user_list_pool already initialized\n");
405     return -1;
406     }
407    
408     p_trie_action_dict = trie_dict_create();
409     if (p_trie_action_dict == NULL)
410     {
411     log_error("trie_dict_create() error\n");
412     return -1;
413     }
414    
415     for (i = 0; i < user_action_map_size; i++)
416     {
417     if (trie_dict_set(p_trie_action_dict, user_action_map[i].name, (int64_t)(user_action_map[i].title)) < 0)
418     {
419     log_error("trie_dict_set(p_trie_action_dict, %s) error\n", user_action_map[i].name);
420     }
421     }
422    
423     // Allocate shared memory
424 sysadm 1.39 size = sizeof(USER_LIST_POOL);
425    
426     strncpy(filepath, filename, sizeof(filepath) - 1);
427     filepath[sizeof(filepath) - 1] = '\0';
428     snprintf(user_list_shm_name, sizeof(user_list_shm_name), "/USER_LIST_SHM_%s", basename(filepath));
429    
430     if (shm_unlink(user_list_shm_name) == -1 && errno != ENOENT)
431     {
432     log_error("shm_unlink(%s) error (%d)\n", user_list_shm_name, errno);
433     return -2;
434     }
435    
436     if ((fd = shm_open(user_list_shm_name, O_CREAT | O_EXCL | O_RDWR, 0600)) == -1)
437     {
438     log_error("shm_open(%s) error (%d)\n", user_list_shm_name, errno);
439     return -2;
440     }
441     if (ftruncate(fd, (off_t)size) == -1)
442 sysadm 1.6 {
443 sysadm 1.39 log_error("ftruncate(size=%d) error (%d)\n", size, errno);
444     close(fd);
445 sysadm 1.6 return -2;
446     }
447    
448 sysadm 1.39 p_shm = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0L);
449     if (p_shm == MAP_FAILED)
450 sysadm 1.6 {
451 sysadm 1.39 log_error("mmap() error (%d)\n", errno);
452     close(fd);
453     return -2;
454 sysadm 1.6 }
455 sysadm 1.39
456     if (close(fd) < 0)
457 sysadm 1.6 {
458 sysadm 1.39 log_error("close(fd) error (%d)\n", errno);
459     return -1;
460 sysadm 1.6 }
461    
462     p_user_list_pool = p_shm;
463 sysadm 1.39 p_user_list_pool->shm_size = size;
464 sysadm 1.6
465     // Allocate semaphore as user list pool lock
466 sysadm 1.39 proj_id = (int)(time(NULL) % getpid());
467     key = ftok(filename, proj_id);
468     if (key == -1)
469     {
470     log_error("ftok(%s %d) error (%d)\n", filename, proj_id, errno);
471     return -2;
472     }
473    
474 sysadm 1.6 size = 2; // r_sem and w_sem
475     semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
476     if (semid == -1)
477     {
478     log_error("semget(user_list_pool_sem, size = %d) error (%d)\n", size, errno);
479     return -3;
480     }
481    
482     // Initialize sem value to 0
483     arg.val = 0;
484     for (i = 0; i < size; i++)
485     {
486     if (semctl(semid, i, SETVAL, arg) == -1)
487     {
488     log_error("semctl(user_list_pool_sem, SETVAL) error (%d)\n", errno);
489     return -3;
490     }
491     }
492    
493     p_user_list_pool->semid = semid;
494    
495     // Set user counts to 0
496     p_user_list_pool->user_list[0].user_count = 0;
497     p_user_list_pool->user_list[1].user_count = 0;
498    
499 sysadm 1.37 p_user_list_pool->user_list_index_current = 0;
500     p_user_list_pool->user_list_index_new = 1;
501 sysadm 1.1
502 sysadm 1.37 p_user_list_pool->user_online_list_index_current = 0;
503     p_user_list_pool->user_online_list_index_new = 1;
504 sysadm 1.1
505 sysadm 1.18 user_stat_map_init(&(p_user_list_pool->user_stat_map));
506    
507 sysadm 1.6 return 0;
508 sysadm 1.1 }
509    
510 sysadm 1.41 void user_list_pool_cleanup(void)
511 sysadm 1.1 {
512 sysadm 1.6 if (p_user_list_pool == NULL)
513     {
514 sysadm 1.41 return;
515 sysadm 1.6 }
516    
517 sysadm 1.40 if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)
518     {
519     log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);
520     }
521    
522 sysadm 1.39 detach_user_list_pool_shm();
523 sysadm 1.6
524 sysadm 1.39 if (shm_unlink(user_list_shm_name) == -1 && errno != ENOENT)
525 sysadm 1.6 {
526 sysadm 1.39 log_error("shm_unlink(%s) error (%d)\n", user_list_shm_name, errno);
527 sysadm 1.6 }
528    
529 sysadm 1.39 user_list_shm_name[0] = '\0';
530 sysadm 1.6
531     if (p_trie_action_dict != NULL)
532     {
533     trie_dict_destroy(p_trie_action_dict);
534 sysadm 1.1
535 sysadm 1.6 p_trie_action_dict = NULL;
536     }
537 sysadm 1.1 }
538    
539     int set_user_list_pool_shm_readonly(void)
540     {
541 sysadm 1.39 if (p_user_list_pool != NULL && mprotect(p_user_list_pool, p_user_list_pool->shm_size, PROT_READ) < 0)
542 sysadm 1.6 {
543 sysadm 1.39 log_error("mprotect() error (%d)\n", errno);
544 sysadm 1.6 return -1;
545     }
546    
547     return 0;
548 sysadm 1.1 }
549    
550     int detach_user_list_pool_shm(void)
551     {
552 sysadm 1.39 if (p_user_list_pool != NULL && munmap(p_user_list_pool, p_user_list_pool->shm_size) < 0)
553 sysadm 1.6 {
554 sysadm 1.39 log_error("munmap() error (%d)\n", errno);
555 sysadm 1.6 return -1;
556     }
557    
558     p_user_list_pool = NULL;
559    
560     return 0;
561     }
562    
563     int user_list_pool_reload(int online_user)
564     {
565     MYSQL *db = NULL;
566 sysadm 1.37 int tmp;
567 sysadm 1.11 int ret = 0;
568 sysadm 1.6
569     if (p_user_list_pool == NULL)
570     {
571     log_error("p_user_list_pool not initialized\n");
572     return -1;
573     }
574    
575     db = db_open();
576     if (db == NULL)
577     {
578     log_error("db_open() error: %s\n", mysql_error(db));
579     return -1;
580     }
581    
582     if (online_user)
583     {
584 sysadm 1.37 if (user_online_list_load(db, &(p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_new])) < 0)
585 sysadm 1.6 {
586     log_error("user_online_list_load() error\n");
587 sysadm 1.11 ret = -2;
588     goto cleanup;
589 sysadm 1.6 }
590 sysadm 1.24
591     if (user_login_count_load(db) < 0)
592     {
593     log_error("user_login_count_load() error\n");
594     ret = -2;
595     goto cleanup;
596     }
597 sysadm 1.6 }
598     else
599     {
600 sysadm 1.37 if (user_list_load(db, &(p_user_list_pool->user_list[p_user_list_pool->user_list_index_new])) < 0)
601 sysadm 1.6 {
602     log_error("user_list_load() error\n");
603 sysadm 1.11 ret = -2;
604     goto cleanup;
605 sysadm 1.6 }
606     }
607    
608     mysql_close(db);
609 sysadm 1.11 db = NULL;
610 sysadm 1.6
611 sysadm 1.39 if (user_list_rw_lock() < 0)
612 sysadm 1.6 {
613     log_error("user_list_rw_lock() error\n");
614 sysadm 1.11 ret = -3;
615     goto cleanup;
616 sysadm 1.6 }
617    
618     if (online_user)
619     {
620     // Swap p_online_current and p_online_new
621 sysadm 1.37 tmp = p_user_list_pool->user_online_list_index_current;
622     p_user_list_pool->user_online_list_index_current = p_user_list_pool->user_online_list_index_new;
623     p_user_list_pool->user_online_list_index_new = tmp;
624 sysadm 1.6 }
625     else
626     {
627 sysadm 1.37 // Swap index_current and index_new
628     tmp = p_user_list_pool->user_list_index_current;
629     p_user_list_pool->user_list_index_current = p_user_list_pool->user_list_index_new;
630     p_user_list_pool->user_list_index_new = tmp;
631 sysadm 1.6 }
632    
633 sysadm 1.39 if (user_list_rw_unlock() < 0)
634 sysadm 1.6 {
635     log_error("user_list_rw_unlock() error\n");
636 sysadm 1.11 ret = -3;
637     goto cleanup;
638 sysadm 1.6 }
639 sysadm 1.1
640 sysadm 1.11 cleanup:
641     mysql_close(db);
642    
643     return ret;
644 sysadm 1.1 }
645    
646 sysadm 1.39 int user_list_try_rd_lock(int wait_sec)
647 sysadm 1.1 {
648 sysadm 1.6 struct sembuf sops[2];
649 sysadm 1.38 #ifndef __CYGWIN__
650 sysadm 1.6 struct timespec timeout;
651 sysadm 1.34 #endif
652 sysadm 1.6 int ret;
653    
654 sysadm 1.39 if (p_user_list_pool == NULL)
655     {
656     log_error("p_user_list_pool not initialized\n");
657     return -1;
658     }
659    
660 sysadm 1.6 sops[0].sem_num = 1; // w_sem
661     sops[0].sem_op = 0; // wait until unlocked
662     sops[0].sem_flg = 0;
663    
664     sops[1].sem_num = 0; // r_sem
665     sops[1].sem_op = 1; // lock
666     sops[1].sem_flg = SEM_UNDO; // undo on terminate
667    
668 sysadm 1.38 #ifdef __CYGWIN__
669 sysadm 1.39 ret = semop(p_user_list_pool->semid, sops, 2);
670 sysadm 1.34 #else
671 sysadm 1.6 timeout.tv_sec = wait_sec;
672     timeout.tv_nsec = 0;
673    
674 sysadm 1.39 ret = semtimedop(p_user_list_pool->semid, sops, 2, &timeout);
675 sysadm 1.34 #endif
676 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
677     {
678 sysadm 1.34 log_error("semop(lock read) error %d\n", errno);
679 sysadm 1.6 }
680 sysadm 1.1
681 sysadm 1.6 return ret;
682 sysadm 1.1 }
683    
684 sysadm 1.39 int user_list_try_rw_lock(int wait_sec)
685 sysadm 1.1 {
686 sysadm 1.6 struct sembuf sops[3];
687 sysadm 1.38 #ifndef __CYGWIN__
688 sysadm 1.6 struct timespec timeout;
689 sysadm 1.34 #endif
690 sysadm 1.6 int ret;
691    
692 sysadm 1.39 if (p_user_list_pool == NULL)
693     {
694     log_error("p_user_list_pool not initialized\n");
695     return -1;
696     }
697    
698 sysadm 1.6 sops[0].sem_num = 1; // w_sem
699     sops[0].sem_op = 0; // wait until unlocked
700     sops[0].sem_flg = 0;
701    
702     sops[1].sem_num = 1; // w_sem
703     sops[1].sem_op = 1; // lock
704     sops[1].sem_flg = SEM_UNDO; // undo on terminate
705    
706     sops[2].sem_num = 0; // r_sem
707     sops[2].sem_op = 0; // wait until unlocked
708     sops[2].sem_flg = 0;
709    
710 sysadm 1.38 #ifdef __CYGWIN__
711 sysadm 1.39 ret = semop(p_user_list_pool->semid, sops, 3);
712 sysadm 1.34 #else
713 sysadm 1.6 timeout.tv_sec = wait_sec;
714     timeout.tv_nsec = 0;
715    
716 sysadm 1.39 ret = semtimedop(p_user_list_pool->semid, sops, 3, &timeout);
717 sysadm 1.34 #endif
718 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
719     {
720 sysadm 1.34 log_error("semop(lock write) error %d\n", errno);
721 sysadm 1.6 }
722 sysadm 1.1
723 sysadm 1.6 return ret;
724 sysadm 1.1 }
725    
726 sysadm 1.39 int user_list_rd_unlock(void)
727 sysadm 1.1 {
728 sysadm 1.6 struct sembuf sops[2];
729     int ret;
730 sysadm 1.1
731 sysadm 1.39 if (p_user_list_pool == NULL)
732     {
733     log_error("p_user_list_pool not initialized\n");
734     return -1;
735     }
736    
737 sysadm 1.6 sops[0].sem_num = 0; // r_sem
738     sops[0].sem_op = -1; // unlock
739     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
740    
741 sysadm 1.39 ret = semop(p_user_list_pool->semid, sops, 1);
742 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
743     {
744     log_error("semop(unlock read) error %d\n", errno);
745     }
746 sysadm 1.1
747 sysadm 1.6 return ret;
748 sysadm 1.1 }
749    
750 sysadm 1.39 int user_list_rw_unlock(void)
751 sysadm 1.1 {
752 sysadm 1.6 struct sembuf sops[1];
753     int ret;
754 sysadm 1.1
755 sysadm 1.39 if (p_user_list_pool == NULL)
756     {
757     log_error("p_user_list_pool not initialized\n");
758     return -1;
759     }
760    
761 sysadm 1.6 sops[0].sem_num = 1; // w_sem
762     sops[0].sem_op = -1; // unlock
763     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
764    
765 sysadm 1.39 ret = semop(p_user_list_pool->semid, sops, 1);
766 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
767     {
768     log_error("semop(unlock write) error %d\n", errno);
769     }
770 sysadm 1.1
771 sysadm 1.6 return ret;
772 sysadm 1.1 }
773    
774 sysadm 1.39 int user_list_rd_lock(void)
775 sysadm 1.1 {
776 sysadm 1.6 int timer = 0;
777     int ret = -1;
778 sysadm 1.1
779 sysadm 1.39 if (p_user_list_pool == NULL)
780     {
781     log_error("p_user_list_pool not initialized\n");
782     return -1;
783     }
784    
785 sysadm 1.6 while (!SYS_server_exit)
786     {
787 sysadm 1.39 ret = user_list_try_rd_lock(USER_LIST_TRY_LOCK_WAIT_TIME);
788 sysadm 1.6 if (ret == 0) // success
789     {
790     break;
791     }
792     else if (errno == EAGAIN || errno == EINTR) // retry
793     {
794     timer++;
795     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
796     {
797     log_error("user_list_try_rd_lock() tried %d times\n", timer);
798     }
799     }
800     else // failed
801     {
802     log_error("user_list_try_rd_lock() failed\n");
803     break;
804     }
805     }
806 sysadm 1.1
807 sysadm 1.6 return ret;
808 sysadm 1.1 }
809    
810 sysadm 1.39 int user_list_rw_lock(void)
811 sysadm 1.1 {
812 sysadm 1.6 int timer = 0;
813     int ret = -1;
814 sysadm 1.1
815 sysadm 1.39 if (p_user_list_pool == NULL)
816     {
817     log_error("p_user_list_pool not initialized\n");
818     return -1;
819     }
820    
821 sysadm 1.6 while (!SYS_server_exit)
822     {
823 sysadm 1.39 ret = user_list_try_rw_lock(USER_LIST_TRY_LOCK_WAIT_TIME);
824 sysadm 1.6 if (ret == 0) // success
825     {
826     break;
827     }
828     else if (errno == EAGAIN || errno == EINTR) // retry
829     {
830     timer++;
831     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
832     {
833     log_error("user_list_try_rw_lock() tried %d times\n", timer);
834     }
835     }
836     else // failed
837     {
838     log_error("user_list_try_rw_lock() failed\n");
839     break;
840     }
841     }
842 sysadm 1.1
843 sysadm 1.6 return ret;
844 sysadm 1.1 }
845 sysadm 1.2
846     int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
847     {
848 sysadm 1.6 int ret = 0;
849 sysadm 1.2
850 sysadm 1.6 if (p_users == NULL || p_user_count == NULL || p_page_count == NULL)
851     {
852     log_error("NULL pointer error\n");
853     return -1;
854     }
855    
856 sysadm 1.12 *p_user_count = 0;
857     *p_page_count = 0;
858    
859 sysadm 1.6 // acquire lock of user list
860 sysadm 1.39 if (user_list_rd_lock() < 0)
861 sysadm 1.6 {
862     log_error("user_list_rd_lock() error\n");
863     return -2;
864     }
865    
866 sysadm 1.37 if (p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count == 0)
867 sysadm 1.6 {
868     // empty list
869     ret = 0;
870     goto cleanup;
871     }
872    
873 sysadm 1.37 *p_page_count = (p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count + BBS_user_limit_per_page - 1) /
874 sysadm 1.33 BBS_user_limit_per_page;
875 sysadm 1.6
876     if (page_id < 0 || page_id >= *p_page_count)
877     {
878     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
879     ret = -3;
880     goto cleanup;
881     }
882    
883     *p_user_count = MIN(BBS_user_limit_per_page,
884 sysadm 1.37 p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count -
885 sysadm 1.6 page_id * BBS_user_limit_per_page);
886    
887     memcpy(p_users,
888 sysadm 1.37 p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users + page_id * BBS_user_limit_per_page,
889 sysadm 1.6 sizeof(USER_INFO) * (size_t)(*p_user_count));
890    
891     cleanup:
892     // release lock of user list
893 sysadm 1.39 if (user_list_rd_unlock() < 0)
894 sysadm 1.6 {
895     log_error("user_list_rd_unlock() error\n");
896     ret = -1;
897     }
898    
899     return ret;
900     }
901    
902     int query_user_online_list(int page_id, USER_ONLINE_INFO *p_online_users, int *p_user_count, int *p_page_count)
903     {
904     int ret = 0;
905    
906     if (p_online_users == NULL || p_user_count == NULL || p_page_count == NULL)
907     {
908     log_error("NULL pointer error\n");
909     return -1;
910     }
911    
912 sysadm 1.12 *p_user_count = 0;
913     *p_page_count = 0;
914    
915 sysadm 1.6 // acquire lock of user list
916 sysadm 1.39 if (user_list_rd_lock() < 0)
917 sysadm 1.6 {
918     log_error("user_list_rd_lock() error\n");
919     return -2;
920     }
921    
922 sysadm 1.37 if (p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count == 0)
923 sysadm 1.6 {
924     // empty list
925     ret = 0;
926     goto cleanup;
927     }
928    
929 sysadm 1.37 *p_page_count = (p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count + BBS_user_limit_per_page - 1) / BBS_user_limit_per_page;
930 sysadm 1.6
931     if (page_id < 0 || page_id >= *p_page_count)
932     {
933     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
934     ret = -3;
935     goto cleanup;
936     }
937    
938     *p_user_count = MIN(BBS_user_limit_per_page,
939 sysadm 1.37 p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count -
940 sysadm 1.6 page_id * BBS_user_limit_per_page);
941    
942     memcpy(p_online_users,
943 sysadm 1.37 p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].users + page_id * BBS_user_limit_per_page,
944 sysadm 1.6 sizeof(USER_ONLINE_INFO) * (size_t)(*p_user_count));
945 sysadm 1.2
946     cleanup:
947 sysadm 1.6 // release lock of user list
948 sysadm 1.39 if (user_list_rd_unlock() < 0)
949 sysadm 1.6 {
950     log_error("user_list_rd_unlock() error\n");
951     ret = -1;
952     }
953 sysadm 1.2
954 sysadm 1.6 return ret;
955 sysadm 1.2 }
956 sysadm 1.4
957 sysadm 1.23 int get_user_list_count(int *p_user_cnt)
958     {
959     if (p_user_cnt == NULL)
960     {
961     log_error("NULL pointer error\n");
962     return -1;
963     }
964    
965     // acquire lock of user list
966 sysadm 1.39 if (user_list_rd_lock() < 0)
967 sysadm 1.23 {
968     log_error("user_list_rd_lock() error\n");
969     return -2;
970     }
971    
972 sysadm 1.37 *p_user_cnt = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count;
973 sysadm 1.23
974     // release lock of user list
975 sysadm 1.39 if (user_list_rd_unlock() < 0)
976 sysadm 1.23 {
977     log_error("user_list_rd_unlock() error\n");
978     return -2;
979     }
980    
981     return 0;
982     }
983    
984     int get_user_online_list_count(int *p_user_cnt, int *p_guest_cnt)
985     {
986     if (p_user_cnt == NULL || p_guest_cnt == NULL)
987     {
988     log_error("NULL pointer error\n");
989     return -1;
990     }
991    
992     // acquire lock of user list
993 sysadm 1.39 if (user_list_rd_lock() < 0)
994 sysadm 1.23 {
995     log_error("user_list_rd_lock() error\n");
996     return -2;
997     }
998    
999 sysadm 1.37 *p_user_cnt = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count;
1000     *p_guest_cnt = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].guest_count;
1001 sysadm 1.23
1002     // release lock of user list
1003 sysadm 1.39 if (user_list_rd_unlock() < 0)
1004 sysadm 1.23 {
1005     log_error("user_list_rd_unlock() error\n");
1006     return -2;
1007     }
1008    
1009     return 0;
1010     }
1011    
1012 sysadm 1.24 int get_user_login_count(int *p_login_cnt)
1013     {
1014     if (p_login_cnt == NULL)
1015     {
1016     log_error("NULL pointer error\n");
1017     return -1;
1018     }
1019    
1020     *p_login_cnt = p_user_list_pool->user_login_count;
1021    
1022     return 0;
1023     }
1024    
1025 sysadm 1.8 int query_user_info(int32_t id, USER_INFO *p_user)
1026     {
1027     int ret = 0;
1028    
1029     if (p_user == NULL)
1030     {
1031     log_error("NULL pointer error\n");
1032     return -1;
1033     }
1034    
1035     // acquire lock of user list
1036 sysadm 1.39 if (user_list_rd_lock() < 0)
1037 sysadm 1.8 {
1038     log_error("user_list_rd_lock() error\n");
1039     return -2;
1040     }
1041    
1042 sysadm 1.37 if (id >= 0 && id < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count) // Found
1043 sysadm 1.8 {
1044 sysadm 1.37 *p_user = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[id];
1045 sysadm 1.8 ret = 1;
1046     }
1047    
1048     // release lock of user list
1049 sysadm 1.39 if (user_list_rd_unlock() < 0)
1050 sysadm 1.8 {
1051     log_error("user_list_rd_unlock() error\n");
1052     ret = -1;
1053     }
1054    
1055     return ret;
1056     }
1057    
1058 sysadm 1.25 int query_user_info_by_uid(int32_t uid, USER_INFO *p_user, char *p_intro_buf, size_t intro_buf_len)
1059 sysadm 1.4 {
1060 sysadm 1.6 int left;
1061     int right;
1062     int mid;
1063 sysadm 1.8 int32_t id;
1064 sysadm 1.6 int ret = 0;
1065    
1066     if (p_user == NULL)
1067     {
1068     log_error("NULL pointer error\n");
1069     return -1;
1070     }
1071    
1072     // acquire lock of user list
1073 sysadm 1.39 if (user_list_rd_lock() < 0)
1074 sysadm 1.6 {
1075     log_error("user_list_rd_lock() error\n");
1076     return -2;
1077     }
1078    
1079     left = 0;
1080 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1081 sysadm 1.6
1082     while (left < right)
1083     {
1084     mid = (left + right) / 2;
1085 sysadm 1.37 if (uid < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1086 sysadm 1.6 {
1087 sysadm 1.22 right = mid - 1;
1088 sysadm 1.6 }
1089 sysadm 1.37 else if (uid > p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1090 sysadm 1.6 {
1091     left = mid + 1;
1092     }
1093 sysadm 1.37 else // if (uid == p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1094 sysadm 1.6 {
1095     left = mid;
1096     break;
1097     }
1098     }
1099    
1100 sysadm 1.37 if (uid == p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[left].uid) // Found
1101 sysadm 1.8 {
1102 sysadm 1.37 id = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[left].id;
1103     *p_user = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[id];
1104 sysadm 1.12 ret = 1;
1105 sysadm 1.25
1106     if (p_intro_buf != NULL)
1107     {
1108 sysadm 1.37 strncpy(p_intro_buf, p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[id].intro, intro_buf_len - 1);
1109 sysadm 1.25 p_intro_buf[intro_buf_len - 1] = '\0';
1110     p_user->intro = p_intro_buf;
1111     }
1112     }
1113    
1114     // release lock of user list
1115 sysadm 1.39 if (user_list_rd_unlock() < 0)
1116 sysadm 1.25 {
1117     log_error("user_list_rd_unlock() error\n");
1118     ret = -1;
1119 sysadm 1.8 }
1120    
1121 sysadm 1.25 return ret;
1122     }
1123    
1124     int query_user_info_by_username(const char *username_prefix, int max_user_cnt,
1125     int32_t uid_list[], char username_list[][BBS_username_max_len + 1])
1126     {
1127     int left;
1128     int right;
1129     int mid;
1130     int left_save;
1131     int ret = 0;
1132     size_t prefix_len;
1133     int comp;
1134     int i;
1135    
1136     if (username_prefix == NULL || uid_list == NULL || username_list == NULL)
1137     {
1138     log_error("NULL pointer error\n");
1139     return -1;
1140     }
1141    
1142     prefix_len = strlen(username_prefix);
1143    
1144     // acquire lock of user list
1145 sysadm 1.39 if (user_list_rd_lock() < 0)
1146 sysadm 1.25 {
1147     log_error("user_list_rd_lock() error\n");
1148     return -2;
1149     }
1150    
1151     left = 0;
1152 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1153 sysadm 1.25
1154     while (left < right)
1155     {
1156     mid = (left + right) / 2;
1157 sysadm 1.37 comp = strncasecmp(username_prefix, p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[mid].username, prefix_len);
1158 sysadm 1.25 if (comp < 0)
1159     {
1160     right = mid - 1;
1161     }
1162     else if (comp > 0)
1163     {
1164     left = mid + 1;
1165     }
1166     else // if (comp == 0)
1167     {
1168     left = mid;
1169     break;
1170     }
1171     }
1172    
1173 sysadm 1.37 if (strncasecmp(username_prefix, p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[left].username, prefix_len) == 0) // Found
1174 sysadm 1.25 {
1175     #ifdef _DEBUG
1176     log_error("Debug: match found, pos=%d\n", left);
1177     #endif
1178    
1179     left_save = left;
1180     right = left;
1181     left = 0;
1182    
1183     while (left < right)
1184     {
1185     mid = (left + right) / 2;
1186 sysadm 1.37 comp = strncasecmp(username_prefix, p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[mid].username, prefix_len);
1187 sysadm 1.25 if (comp > 0)
1188     {
1189     left = mid + 1;
1190     }
1191     else if (comp == 0)
1192     {
1193     right = mid;
1194     }
1195     else // if (comp < 0)
1196     {
1197     log_error("Bug: left=%d right=%d mid=%d");
1198     ret = -2;
1199     goto cleanup;
1200     }
1201     }
1202    
1203     #ifdef _DEBUG
1204     log_error("Debug: first match found, pos=%d\n", right);
1205     #endif
1206    
1207     left = left_save;
1208     left_save = right;
1209 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1210 sysadm 1.25
1211     while (left < right)
1212     {
1213     mid = (left + right) / 2 + (left + right) % 2;
1214 sysadm 1.37 comp = strncasecmp(username_prefix, p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[mid].username, prefix_len);
1215 sysadm 1.25 if (comp < 0)
1216     {
1217     right = mid - 1;
1218     }
1219     else if (comp == 0)
1220     {
1221     left = mid;
1222     }
1223     else // if (comp > 0)
1224     {
1225     log_error("Bug: left=%d right=%d mid=%d");
1226     ret = -2;
1227     goto cleanup;
1228     }
1229     }
1230    
1231     #ifdef _DEBUG
1232     log_error("Debug: last match found, pos=%d\n", left);
1233     #endif
1234    
1235     right = left;
1236     left = left_save;
1237    
1238     for (i = 0; i < max_user_cnt && left + i <= right; i++)
1239     {
1240 sysadm 1.37 uid_list[i] = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[left + i].uid;
1241     strncpy(username_list[i], p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[left + i].username, sizeof(username_list[i]) - 1);
1242 sysadm 1.25 username_list[i][sizeof(username_list[i]) - 1] = '\0';
1243     }
1244     ret = i;
1245     }
1246    
1247     cleanup:
1248 sysadm 1.8 // release lock of user list
1249 sysadm 1.39 if (user_list_rd_unlock() < 0)
1250 sysadm 1.8 {
1251     log_error("user_list_rd_unlock() error\n");
1252     ret = -1;
1253     }
1254    
1255     return ret;
1256     }
1257    
1258     int query_user_online_info(int32_t id, USER_ONLINE_INFO *p_user)
1259     {
1260     int ret = 0;
1261    
1262     if (p_user == NULL)
1263     {
1264     log_error("NULL pointer error\n");
1265     return -1;
1266     }
1267    
1268     // acquire lock of user list
1269 sysadm 1.39 if (user_list_rd_lock() < 0)
1270 sysadm 1.8 {
1271     log_error("user_list_rd_lock() error\n");
1272     return -2;
1273     }
1274    
1275 sysadm 1.37 if (id >= 0 && id < p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count) // Found
1276 sysadm 1.6 {
1277 sysadm 1.37 *p_user = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].users[id];
1278 sysadm 1.6 ret = 1;
1279     }
1280    
1281     // release lock of user list
1282 sysadm 1.39 if (user_list_rd_unlock() < 0)
1283 sysadm 1.6 {
1284     log_error("user_list_rd_unlock() error\n");
1285     ret = -1;
1286     }
1287 sysadm 1.4
1288 sysadm 1.6 return ret;
1289 sysadm 1.4 }
1290 sysadm 1.11
1291     int query_user_online_info_by_uid(int32_t uid, USER_ONLINE_INFO *p_users, int *p_user_cnt, int start_id)
1292     {
1293     int left;
1294     int right;
1295     int mid;
1296     int32_t id;
1297     int ret = 0;
1298     int i;
1299 sysadm 1.20 int user_cnt;
1300 sysadm 1.11
1301     if (p_users == NULL || p_user_cnt == NULL)
1302     {
1303     log_error("NULL pointer error\n");
1304     return -1;
1305     }
1306    
1307 sysadm 1.20 user_cnt = *p_user_cnt;
1308     *p_user_cnt = 0;
1309    
1310 sysadm 1.11 // acquire lock of user list
1311 sysadm 1.39 if (user_list_rd_lock() < 0)
1312 sysadm 1.11 {
1313     log_error("user_list_rd_lock() error\n");
1314     return -2;
1315     }
1316    
1317     left = start_id;
1318 sysadm 1.37 right = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count - 1;
1319 sysadm 1.11
1320     while (left < right)
1321     {
1322     mid = (left + right) / 2;
1323 sysadm 1.37 if (uid < p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[mid].uid)
1324 sysadm 1.11 {
1325 sysadm 1.22 right = mid - 1;
1326 sysadm 1.11 }
1327 sysadm 1.37 else if (uid > p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[mid].uid)
1328 sysadm 1.11 {
1329     left = mid + 1;
1330     }
1331 sysadm 1.37 else // if (uid == p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[mid].uid)
1332 sysadm 1.11 {
1333     left = mid;
1334     break;
1335     }
1336     }
1337    
1338 sysadm 1.37 if (uid == p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[left].uid)
1339 sysadm 1.11 {
1340     right = left;
1341     left = start_id;
1342    
1343     while (left < right)
1344     {
1345     mid = (left + right) / 2;
1346 sysadm 1.37 if (uid - 1 < p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[mid].uid)
1347 sysadm 1.11 {
1348     right = mid;
1349     }
1350 sysadm 1.37 else // if (uid - 1 >= p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[mid].uid)
1351 sysadm 1.11 {
1352     left = mid + 1;
1353     }
1354     }
1355    
1356 sysadm 1.13 for (i = 0;
1357 sysadm 1.37 left < p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count && i < user_cnt &&
1358     uid == p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[left].uid;
1359 sysadm 1.13 left++, i++)
1360 sysadm 1.11 {
1361 sysadm 1.37 id = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[left].id;
1362     p_users[i] = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].users[id];
1363 sysadm 1.11 }
1364    
1365 sysadm 1.12 if (i > 0)
1366 sysadm 1.11 {
1367     *p_user_cnt = i;
1368     ret = 1;
1369     }
1370     }
1371    
1372     // release lock of user list
1373 sysadm 1.39 if (user_list_rd_unlock() < 0)
1374 sysadm 1.11 {
1375     log_error("user_list_rd_unlock() error\n");
1376     ret = -1;
1377     }
1378    
1379     return ret;
1380     }
1381 sysadm 1.18
1382     int get_user_id_list(int32_t *p_uid_list, int *p_user_cnt, int start_uid)
1383     {
1384     int left;
1385     int right;
1386     int mid;
1387     int ret = 0;
1388     int i;
1389    
1390     if (p_uid_list == NULL || p_user_cnt == NULL)
1391     {
1392     log_error("NULL pointer error\n");
1393     return -1;
1394     }
1395    
1396     // acquire lock of user list
1397 sysadm 1.39 if (user_list_rd_lock() < 0)
1398 sysadm 1.18 {
1399     log_error("user_list_rd_lock() error\n");
1400     return -2;
1401     }
1402    
1403     left = 0;
1404 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1405 sysadm 1.18
1406     while (left < right)
1407     {
1408     mid = (left + right) / 2;
1409 sysadm 1.37 if (start_uid < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1410 sysadm 1.18 {
1411 sysadm 1.22 right = mid - 1;
1412 sysadm 1.18 }
1413 sysadm 1.37 else if (start_uid > p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1414 sysadm 1.18 {
1415     left = mid + 1;
1416     }
1417 sysadm 1.37 else // if (start_uid == p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1418 sysadm 1.18 {
1419     left = mid;
1420     break;
1421     }
1422     }
1423    
1424 sysadm 1.37 for (i = 0; i < *p_user_cnt && left + i < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count; i++)
1425 sysadm 1.18 {
1426 sysadm 1.37 p_uid_list[i] = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[left + i].uid;
1427 sysadm 1.18 }
1428     *p_user_cnt = i;
1429    
1430     // release lock of user list
1431 sysadm 1.39 if (user_list_rd_unlock() < 0)
1432 sysadm 1.18 {
1433     log_error("user_list_rd_unlock() error\n");
1434     ret = -1;
1435     }
1436    
1437     return ret;
1438     }
1439    
1440     int user_stat_update(void)
1441     {
1442     return user_stat_map_update(&(p_user_list_pool->user_stat_map));
1443     }
1444    
1445 sysadm 1.19 int user_article_cnt_inc(int32_t uid, int n)
1446     {
1447     return user_stat_article_cnt_inc(&(p_user_list_pool->user_stat_map), uid, n);
1448     }
1449    
1450     int get_user_article_cnt(int32_t uid)
1451 sysadm 1.18 {
1452     const USER_STAT *p_stat;
1453     int ret;
1454    
1455     ret = user_stat_get(&(p_user_list_pool->user_stat_map), uid, &p_stat);
1456     if (ret < 0)
1457     {
1458     log_error("user_stat_get(uid=%d) error: %d\n", uid, ret);
1459     return -1;
1460     }
1461     else if (ret == 0) // user not found
1462     {
1463     return -1;
1464     }
1465    
1466     return p_stat->article_count;
1467     }

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