/[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.40 - (hide annotations)
Thu Nov 20 02:56:46 2025 UTC (3 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.39: +5 -1 lines
Content type: text/x-csrc
Update

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.39 static char user_list_shm_name[FILE_PATH_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.39 int user_list_pool_cleanup(void)
511 sysadm 1.1 {
512 sysadm 1.6 if (p_user_list_pool == NULL)
513     {
514 sysadm 1.39 return -1;
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.39
538     return 0;
539 sysadm 1.1 }
540    
541     int set_user_list_pool_shm_readonly(void)
542     {
543 sysadm 1.39 if (p_user_list_pool != NULL && mprotect(p_user_list_pool, p_user_list_pool->shm_size, PROT_READ) < 0)
544 sysadm 1.6 {
545 sysadm 1.39 log_error("mprotect() error (%d)\n", errno);
546 sysadm 1.6 return -1;
547     }
548    
549     return 0;
550 sysadm 1.1 }
551    
552     int detach_user_list_pool_shm(void)
553     {
554 sysadm 1.39 if (p_user_list_pool != NULL && munmap(p_user_list_pool, p_user_list_pool->shm_size) < 0)
555 sysadm 1.6 {
556 sysadm 1.39 log_error("munmap() error (%d)\n", errno);
557 sysadm 1.6 return -1;
558     }
559    
560     p_user_list_pool = NULL;
561    
562     return 0;
563     }
564    
565     int user_list_pool_reload(int online_user)
566     {
567     MYSQL *db = NULL;
568 sysadm 1.37 int tmp;
569 sysadm 1.11 int ret = 0;
570 sysadm 1.6
571     if (p_user_list_pool == NULL)
572     {
573     log_error("p_user_list_pool not initialized\n");
574     return -1;
575     }
576    
577     db = db_open();
578     if (db == NULL)
579     {
580     log_error("db_open() error: %s\n", mysql_error(db));
581     return -1;
582     }
583    
584     if (online_user)
585     {
586 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)
587 sysadm 1.6 {
588     log_error("user_online_list_load() error\n");
589 sysadm 1.11 ret = -2;
590     goto cleanup;
591 sysadm 1.6 }
592 sysadm 1.24
593     if (user_login_count_load(db) < 0)
594     {
595     log_error("user_login_count_load() error\n");
596     ret = -2;
597     goto cleanup;
598     }
599 sysadm 1.6 }
600     else
601     {
602 sysadm 1.37 if (user_list_load(db, &(p_user_list_pool->user_list[p_user_list_pool->user_list_index_new])) < 0)
603 sysadm 1.6 {
604     log_error("user_list_load() error\n");
605 sysadm 1.11 ret = -2;
606     goto cleanup;
607 sysadm 1.6 }
608     }
609    
610     mysql_close(db);
611 sysadm 1.11 db = NULL;
612 sysadm 1.6
613 sysadm 1.39 if (user_list_rw_lock() < 0)
614 sysadm 1.6 {
615     log_error("user_list_rw_lock() error\n");
616 sysadm 1.11 ret = -3;
617     goto cleanup;
618 sysadm 1.6 }
619    
620     if (online_user)
621     {
622     // Swap p_online_current and p_online_new
623 sysadm 1.37 tmp = p_user_list_pool->user_online_list_index_current;
624     p_user_list_pool->user_online_list_index_current = p_user_list_pool->user_online_list_index_new;
625     p_user_list_pool->user_online_list_index_new = tmp;
626 sysadm 1.6 }
627     else
628     {
629 sysadm 1.37 // Swap index_current and index_new
630     tmp = p_user_list_pool->user_list_index_current;
631     p_user_list_pool->user_list_index_current = p_user_list_pool->user_list_index_new;
632     p_user_list_pool->user_list_index_new = tmp;
633 sysadm 1.6 }
634    
635 sysadm 1.39 if (user_list_rw_unlock() < 0)
636 sysadm 1.6 {
637     log_error("user_list_rw_unlock() error\n");
638 sysadm 1.11 ret = -3;
639     goto cleanup;
640 sysadm 1.6 }
641 sysadm 1.1
642 sysadm 1.11 cleanup:
643     mysql_close(db);
644    
645     return ret;
646 sysadm 1.1 }
647    
648 sysadm 1.39 int user_list_try_rd_lock(int wait_sec)
649 sysadm 1.1 {
650 sysadm 1.6 struct sembuf sops[2];
651 sysadm 1.38 #ifndef __CYGWIN__
652 sysadm 1.6 struct timespec timeout;
653 sysadm 1.34 #endif
654 sysadm 1.6 int ret;
655    
656 sysadm 1.39 if (p_user_list_pool == NULL)
657     {
658     log_error("p_user_list_pool not initialized\n");
659     return -1;
660     }
661    
662 sysadm 1.6 sops[0].sem_num = 1; // w_sem
663     sops[0].sem_op = 0; // wait until unlocked
664     sops[0].sem_flg = 0;
665    
666     sops[1].sem_num = 0; // r_sem
667     sops[1].sem_op = 1; // lock
668     sops[1].sem_flg = SEM_UNDO; // undo on terminate
669    
670 sysadm 1.38 #ifdef __CYGWIN__
671 sysadm 1.39 ret = semop(p_user_list_pool->semid, sops, 2);
672 sysadm 1.34 #else
673 sysadm 1.6 timeout.tv_sec = wait_sec;
674     timeout.tv_nsec = 0;
675    
676 sysadm 1.39 ret = semtimedop(p_user_list_pool->semid, sops, 2, &timeout);
677 sysadm 1.34 #endif
678 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
679     {
680 sysadm 1.34 log_error("semop(lock read) error %d\n", errno);
681 sysadm 1.6 }
682 sysadm 1.1
683 sysadm 1.6 return ret;
684 sysadm 1.1 }
685    
686 sysadm 1.39 int user_list_try_rw_lock(int wait_sec)
687 sysadm 1.1 {
688 sysadm 1.6 struct sembuf sops[3];
689 sysadm 1.38 #ifndef __CYGWIN__
690 sysadm 1.6 struct timespec timeout;
691 sysadm 1.34 #endif
692 sysadm 1.6 int ret;
693    
694 sysadm 1.39 if (p_user_list_pool == NULL)
695     {
696     log_error("p_user_list_pool not initialized\n");
697     return -1;
698     }
699    
700 sysadm 1.6 sops[0].sem_num = 1; // w_sem
701     sops[0].sem_op = 0; // wait until unlocked
702     sops[0].sem_flg = 0;
703    
704     sops[1].sem_num = 1; // w_sem
705     sops[1].sem_op = 1; // lock
706     sops[1].sem_flg = SEM_UNDO; // undo on terminate
707    
708     sops[2].sem_num = 0; // r_sem
709     sops[2].sem_op = 0; // wait until unlocked
710     sops[2].sem_flg = 0;
711    
712 sysadm 1.38 #ifdef __CYGWIN__
713 sysadm 1.39 ret = semop(p_user_list_pool->semid, sops, 3);
714 sysadm 1.34 #else
715 sysadm 1.6 timeout.tv_sec = wait_sec;
716     timeout.tv_nsec = 0;
717    
718 sysadm 1.39 ret = semtimedop(p_user_list_pool->semid, sops, 3, &timeout);
719 sysadm 1.34 #endif
720 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
721     {
722 sysadm 1.34 log_error("semop(lock write) error %d\n", errno);
723 sysadm 1.6 }
724 sysadm 1.1
725 sysadm 1.6 return ret;
726 sysadm 1.1 }
727    
728 sysadm 1.39 int user_list_rd_unlock(void)
729 sysadm 1.1 {
730 sysadm 1.6 struct sembuf sops[2];
731     int ret;
732 sysadm 1.1
733 sysadm 1.39 if (p_user_list_pool == NULL)
734     {
735     log_error("p_user_list_pool not initialized\n");
736     return -1;
737     }
738    
739 sysadm 1.6 sops[0].sem_num = 0; // r_sem
740     sops[0].sem_op = -1; // unlock
741     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
742    
743 sysadm 1.39 ret = semop(p_user_list_pool->semid, sops, 1);
744 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
745     {
746     log_error("semop(unlock read) error %d\n", errno);
747     }
748 sysadm 1.1
749 sysadm 1.6 return ret;
750 sysadm 1.1 }
751    
752 sysadm 1.39 int user_list_rw_unlock(void)
753 sysadm 1.1 {
754 sysadm 1.6 struct sembuf sops[1];
755     int ret;
756 sysadm 1.1
757 sysadm 1.39 if (p_user_list_pool == NULL)
758     {
759     log_error("p_user_list_pool not initialized\n");
760     return -1;
761     }
762    
763 sysadm 1.6 sops[0].sem_num = 1; // w_sem
764     sops[0].sem_op = -1; // unlock
765     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
766    
767 sysadm 1.39 ret = semop(p_user_list_pool->semid, sops, 1);
768 sysadm 1.6 if (ret == -1 && errno != EAGAIN && errno != EINTR)
769     {
770     log_error("semop(unlock write) error %d\n", errno);
771     }
772 sysadm 1.1
773 sysadm 1.6 return ret;
774 sysadm 1.1 }
775    
776 sysadm 1.39 int user_list_rd_lock(void)
777 sysadm 1.1 {
778 sysadm 1.6 int timer = 0;
779     int ret = -1;
780 sysadm 1.1
781 sysadm 1.39 if (p_user_list_pool == NULL)
782     {
783     log_error("p_user_list_pool not initialized\n");
784     return -1;
785     }
786    
787 sysadm 1.6 while (!SYS_server_exit)
788     {
789 sysadm 1.39 ret = user_list_try_rd_lock(USER_LIST_TRY_LOCK_WAIT_TIME);
790 sysadm 1.6 if (ret == 0) // success
791     {
792     break;
793     }
794     else if (errno == EAGAIN || errno == EINTR) // retry
795     {
796     timer++;
797     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
798     {
799     log_error("user_list_try_rd_lock() tried %d times\n", timer);
800     }
801     }
802     else // failed
803     {
804     log_error("user_list_try_rd_lock() failed\n");
805     break;
806     }
807     }
808 sysadm 1.1
809 sysadm 1.6 return ret;
810 sysadm 1.1 }
811    
812 sysadm 1.39 int user_list_rw_lock(void)
813 sysadm 1.1 {
814 sysadm 1.6 int timer = 0;
815     int ret = -1;
816 sysadm 1.1
817 sysadm 1.39 if (p_user_list_pool == NULL)
818     {
819     log_error("p_user_list_pool not initialized\n");
820     return -1;
821     }
822    
823 sysadm 1.6 while (!SYS_server_exit)
824     {
825 sysadm 1.39 ret = user_list_try_rw_lock(USER_LIST_TRY_LOCK_WAIT_TIME);
826 sysadm 1.6 if (ret == 0) // success
827     {
828     break;
829     }
830     else if (errno == EAGAIN || errno == EINTR) // retry
831     {
832     timer++;
833     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
834     {
835     log_error("user_list_try_rw_lock() tried %d times\n", timer);
836     }
837     }
838     else // failed
839     {
840     log_error("user_list_try_rw_lock() failed\n");
841     break;
842     }
843     }
844 sysadm 1.1
845 sysadm 1.6 return ret;
846 sysadm 1.1 }
847 sysadm 1.2
848     int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
849     {
850 sysadm 1.6 int ret = 0;
851 sysadm 1.2
852 sysadm 1.6 if (p_users == NULL || p_user_count == NULL || p_page_count == NULL)
853     {
854     log_error("NULL pointer error\n");
855     return -1;
856     }
857    
858 sysadm 1.12 *p_user_count = 0;
859     *p_page_count = 0;
860    
861 sysadm 1.6 // acquire lock of user list
862 sysadm 1.39 if (user_list_rd_lock() < 0)
863 sysadm 1.6 {
864     log_error("user_list_rd_lock() error\n");
865     return -2;
866     }
867    
868 sysadm 1.37 if (p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count == 0)
869 sysadm 1.6 {
870     // empty list
871     ret = 0;
872     goto cleanup;
873     }
874    
875 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) /
876 sysadm 1.33 BBS_user_limit_per_page;
877 sysadm 1.6
878     if (page_id < 0 || page_id >= *p_page_count)
879     {
880     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
881     ret = -3;
882     goto cleanup;
883     }
884    
885     *p_user_count = MIN(BBS_user_limit_per_page,
886 sysadm 1.37 p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count -
887 sysadm 1.6 page_id * BBS_user_limit_per_page);
888    
889     memcpy(p_users,
890 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,
891 sysadm 1.6 sizeof(USER_INFO) * (size_t)(*p_user_count));
892    
893     cleanup:
894     // release lock of user list
895 sysadm 1.39 if (user_list_rd_unlock() < 0)
896 sysadm 1.6 {
897     log_error("user_list_rd_unlock() error\n");
898     ret = -1;
899     }
900    
901     return ret;
902     }
903    
904     int query_user_online_list(int page_id, USER_ONLINE_INFO *p_online_users, int *p_user_count, int *p_page_count)
905     {
906     int ret = 0;
907    
908     if (p_online_users == NULL || p_user_count == NULL || p_page_count == NULL)
909     {
910     log_error("NULL pointer error\n");
911     return -1;
912     }
913    
914 sysadm 1.12 *p_user_count = 0;
915     *p_page_count = 0;
916    
917 sysadm 1.6 // acquire lock of user list
918 sysadm 1.39 if (user_list_rd_lock() < 0)
919 sysadm 1.6 {
920     log_error("user_list_rd_lock() error\n");
921     return -2;
922     }
923    
924 sysadm 1.37 if (p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count == 0)
925 sysadm 1.6 {
926     // empty list
927     ret = 0;
928     goto cleanup;
929     }
930    
931 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;
932 sysadm 1.6
933     if (page_id < 0 || page_id >= *p_page_count)
934     {
935     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
936     ret = -3;
937     goto cleanup;
938     }
939    
940     *p_user_count = MIN(BBS_user_limit_per_page,
941 sysadm 1.37 p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count -
942 sysadm 1.6 page_id * BBS_user_limit_per_page);
943    
944     memcpy(p_online_users,
945 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,
946 sysadm 1.6 sizeof(USER_ONLINE_INFO) * (size_t)(*p_user_count));
947 sysadm 1.2
948     cleanup:
949 sysadm 1.6 // release lock of user list
950 sysadm 1.39 if (user_list_rd_unlock() < 0)
951 sysadm 1.6 {
952     log_error("user_list_rd_unlock() error\n");
953     ret = -1;
954     }
955 sysadm 1.2
956 sysadm 1.6 return ret;
957 sysadm 1.2 }
958 sysadm 1.4
959 sysadm 1.23 int get_user_list_count(int *p_user_cnt)
960     {
961     if (p_user_cnt == NULL)
962     {
963     log_error("NULL pointer error\n");
964     return -1;
965     }
966    
967     // acquire lock of user list
968 sysadm 1.39 if (user_list_rd_lock() < 0)
969 sysadm 1.23 {
970     log_error("user_list_rd_lock() error\n");
971     return -2;
972     }
973    
974 sysadm 1.37 *p_user_cnt = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count;
975 sysadm 1.23
976     // release lock of user list
977 sysadm 1.39 if (user_list_rd_unlock() < 0)
978 sysadm 1.23 {
979     log_error("user_list_rd_unlock() error\n");
980     return -2;
981     }
982    
983     return 0;
984     }
985    
986     int get_user_online_list_count(int *p_user_cnt, int *p_guest_cnt)
987     {
988     if (p_user_cnt == NULL || p_guest_cnt == NULL)
989     {
990     log_error("NULL pointer error\n");
991     return -1;
992     }
993    
994     // acquire lock of user list
995 sysadm 1.39 if (user_list_rd_lock() < 0)
996 sysadm 1.23 {
997     log_error("user_list_rd_lock() error\n");
998     return -2;
999     }
1000    
1001 sysadm 1.37 *p_user_cnt = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count;
1002     *p_guest_cnt = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].guest_count;
1003 sysadm 1.23
1004     // release lock of user list
1005 sysadm 1.39 if (user_list_rd_unlock() < 0)
1006 sysadm 1.23 {
1007     log_error("user_list_rd_unlock() error\n");
1008     return -2;
1009     }
1010    
1011     return 0;
1012     }
1013    
1014 sysadm 1.24 int get_user_login_count(int *p_login_cnt)
1015     {
1016     if (p_login_cnt == NULL)
1017     {
1018     log_error("NULL pointer error\n");
1019     return -1;
1020     }
1021    
1022     *p_login_cnt = p_user_list_pool->user_login_count;
1023    
1024     return 0;
1025     }
1026    
1027 sysadm 1.8 int query_user_info(int32_t id, USER_INFO *p_user)
1028     {
1029     int ret = 0;
1030    
1031     if (p_user == NULL)
1032     {
1033     log_error("NULL pointer error\n");
1034     return -1;
1035     }
1036    
1037     // acquire lock of user list
1038 sysadm 1.39 if (user_list_rd_lock() < 0)
1039 sysadm 1.8 {
1040     log_error("user_list_rd_lock() error\n");
1041     return -2;
1042     }
1043    
1044 sysadm 1.37 if (id >= 0 && id < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count) // Found
1045 sysadm 1.8 {
1046 sysadm 1.37 *p_user = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[id];
1047 sysadm 1.8 ret = 1;
1048     }
1049    
1050     // release lock of user list
1051 sysadm 1.39 if (user_list_rd_unlock() < 0)
1052 sysadm 1.8 {
1053     log_error("user_list_rd_unlock() error\n");
1054     ret = -1;
1055     }
1056    
1057     return ret;
1058     }
1059    
1060 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)
1061 sysadm 1.4 {
1062 sysadm 1.6 int left;
1063     int right;
1064     int mid;
1065 sysadm 1.8 int32_t id;
1066 sysadm 1.6 int ret = 0;
1067    
1068     if (p_user == NULL)
1069     {
1070     log_error("NULL pointer error\n");
1071     return -1;
1072     }
1073    
1074     // acquire lock of user list
1075 sysadm 1.39 if (user_list_rd_lock() < 0)
1076 sysadm 1.6 {
1077     log_error("user_list_rd_lock() error\n");
1078     return -2;
1079     }
1080    
1081     left = 0;
1082 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1083 sysadm 1.6
1084     while (left < right)
1085     {
1086     mid = (left + right) / 2;
1087 sysadm 1.37 if (uid < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1088 sysadm 1.6 {
1089 sysadm 1.22 right = mid - 1;
1090 sysadm 1.6 }
1091 sysadm 1.37 else if (uid > p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1092 sysadm 1.6 {
1093     left = mid + 1;
1094     }
1095 sysadm 1.37 else // if (uid == p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1096 sysadm 1.6 {
1097     left = mid;
1098     break;
1099     }
1100     }
1101    
1102 sysadm 1.37 if (uid == p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[left].uid) // Found
1103 sysadm 1.8 {
1104 sysadm 1.37 id = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[left].id;
1105     *p_user = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[id];
1106 sysadm 1.12 ret = 1;
1107 sysadm 1.25
1108     if (p_intro_buf != NULL)
1109     {
1110 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);
1111 sysadm 1.25 p_intro_buf[intro_buf_len - 1] = '\0';
1112     p_user->intro = p_intro_buf;
1113     }
1114     }
1115    
1116     // release lock of user list
1117 sysadm 1.39 if (user_list_rd_unlock() < 0)
1118 sysadm 1.25 {
1119     log_error("user_list_rd_unlock() error\n");
1120     ret = -1;
1121 sysadm 1.8 }
1122    
1123 sysadm 1.25 return ret;
1124     }
1125    
1126     int query_user_info_by_username(const char *username_prefix, int max_user_cnt,
1127     int32_t uid_list[], char username_list[][BBS_username_max_len + 1])
1128     {
1129     int left;
1130     int right;
1131     int mid;
1132     int left_save;
1133     int ret = 0;
1134     size_t prefix_len;
1135     int comp;
1136     int i;
1137    
1138     if (username_prefix == NULL || uid_list == NULL || username_list == NULL)
1139     {
1140     log_error("NULL pointer error\n");
1141     return -1;
1142     }
1143    
1144     prefix_len = strlen(username_prefix);
1145    
1146     // acquire lock of user list
1147 sysadm 1.39 if (user_list_rd_lock() < 0)
1148 sysadm 1.25 {
1149     log_error("user_list_rd_lock() error\n");
1150     return -2;
1151     }
1152    
1153     left = 0;
1154 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1155 sysadm 1.25
1156     while (left < right)
1157     {
1158     mid = (left + right) / 2;
1159 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);
1160 sysadm 1.25 if (comp < 0)
1161     {
1162     right = mid - 1;
1163     }
1164     else if (comp > 0)
1165     {
1166     left = mid + 1;
1167     }
1168     else // if (comp == 0)
1169     {
1170     left = mid;
1171     break;
1172     }
1173     }
1174    
1175 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
1176 sysadm 1.25 {
1177     #ifdef _DEBUG
1178     log_error("Debug: match found, pos=%d\n", left);
1179     #endif
1180    
1181     left_save = left;
1182     right = left;
1183     left = 0;
1184    
1185     while (left < right)
1186     {
1187     mid = (left + right) / 2;
1188 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);
1189 sysadm 1.25 if (comp > 0)
1190     {
1191     left = mid + 1;
1192     }
1193     else if (comp == 0)
1194     {
1195     right = mid;
1196     }
1197     else // if (comp < 0)
1198     {
1199     log_error("Bug: left=%d right=%d mid=%d");
1200     ret = -2;
1201     goto cleanup;
1202     }
1203     }
1204    
1205     #ifdef _DEBUG
1206     log_error("Debug: first match found, pos=%d\n", right);
1207     #endif
1208    
1209     left = left_save;
1210     left_save = right;
1211 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1212 sysadm 1.25
1213     while (left < right)
1214     {
1215     mid = (left + right) / 2 + (left + right) % 2;
1216 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);
1217 sysadm 1.25 if (comp < 0)
1218     {
1219     right = mid - 1;
1220     }
1221     else if (comp == 0)
1222     {
1223     left = mid;
1224     }
1225     else // if (comp > 0)
1226     {
1227     log_error("Bug: left=%d right=%d mid=%d");
1228     ret = -2;
1229     goto cleanup;
1230     }
1231     }
1232    
1233     #ifdef _DEBUG
1234     log_error("Debug: last match found, pos=%d\n", left);
1235     #endif
1236    
1237     right = left;
1238     left = left_save;
1239    
1240     for (i = 0; i < max_user_cnt && left + i <= right; i++)
1241     {
1242 sysadm 1.37 uid_list[i] = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].users[left + i].uid;
1243     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);
1244 sysadm 1.25 username_list[i][sizeof(username_list[i]) - 1] = '\0';
1245     }
1246     ret = i;
1247     }
1248    
1249     cleanup:
1250 sysadm 1.8 // release lock of user list
1251 sysadm 1.39 if (user_list_rd_unlock() < 0)
1252 sysadm 1.8 {
1253     log_error("user_list_rd_unlock() error\n");
1254     ret = -1;
1255     }
1256    
1257     return ret;
1258     }
1259    
1260     int query_user_online_info(int32_t id, USER_ONLINE_INFO *p_user)
1261     {
1262     int ret = 0;
1263    
1264     if (p_user == NULL)
1265     {
1266     log_error("NULL pointer error\n");
1267     return -1;
1268     }
1269    
1270     // acquire lock of user list
1271 sysadm 1.39 if (user_list_rd_lock() < 0)
1272 sysadm 1.8 {
1273     log_error("user_list_rd_lock() error\n");
1274     return -2;
1275     }
1276    
1277 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
1278 sysadm 1.6 {
1279 sysadm 1.37 *p_user = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].users[id];
1280 sysadm 1.6 ret = 1;
1281     }
1282    
1283     // release lock of user list
1284 sysadm 1.39 if (user_list_rd_unlock() < 0)
1285 sysadm 1.6 {
1286     log_error("user_list_rd_unlock() error\n");
1287     ret = -1;
1288     }
1289 sysadm 1.4
1290 sysadm 1.6 return ret;
1291 sysadm 1.4 }
1292 sysadm 1.11
1293     int query_user_online_info_by_uid(int32_t uid, USER_ONLINE_INFO *p_users, int *p_user_cnt, int start_id)
1294     {
1295     int left;
1296     int right;
1297     int mid;
1298     int32_t id;
1299     int ret = 0;
1300     int i;
1301 sysadm 1.20 int user_cnt;
1302 sysadm 1.11
1303     if (p_users == NULL || p_user_cnt == NULL)
1304     {
1305     log_error("NULL pointer error\n");
1306     return -1;
1307     }
1308    
1309 sysadm 1.20 user_cnt = *p_user_cnt;
1310     *p_user_cnt = 0;
1311    
1312 sysadm 1.11 // acquire lock of user list
1313 sysadm 1.39 if (user_list_rd_lock() < 0)
1314 sysadm 1.11 {
1315     log_error("user_list_rd_lock() error\n");
1316     return -2;
1317     }
1318    
1319     left = start_id;
1320 sysadm 1.37 right = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].user_count - 1;
1321 sysadm 1.11
1322     while (left < right)
1323     {
1324     mid = (left + right) / 2;
1325 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)
1326 sysadm 1.11 {
1327 sysadm 1.22 right = mid - 1;
1328 sysadm 1.11 }
1329 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)
1330 sysadm 1.11 {
1331     left = mid + 1;
1332     }
1333 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)
1334 sysadm 1.11 {
1335     left = mid;
1336     break;
1337     }
1338     }
1339    
1340 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)
1341 sysadm 1.11 {
1342     right = left;
1343     left = start_id;
1344    
1345     while (left < right)
1346     {
1347     mid = (left + right) / 2;
1348 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)
1349 sysadm 1.11 {
1350     right = mid;
1351     }
1352 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)
1353 sysadm 1.11 {
1354     left = mid + 1;
1355     }
1356     }
1357    
1358 sysadm 1.13 for (i = 0;
1359 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 &&
1360     uid == p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[left].uid;
1361 sysadm 1.13 left++, i++)
1362 sysadm 1.11 {
1363 sysadm 1.37 id = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].index_uid[left].id;
1364     p_users[i] = p_user_list_pool->user_online_list[p_user_list_pool->user_online_list_index_current].users[id];
1365 sysadm 1.11 }
1366    
1367 sysadm 1.12 if (i > 0)
1368 sysadm 1.11 {
1369     *p_user_cnt = i;
1370     ret = 1;
1371     }
1372     }
1373    
1374     // release lock of user list
1375 sysadm 1.39 if (user_list_rd_unlock() < 0)
1376 sysadm 1.11 {
1377     log_error("user_list_rd_unlock() error\n");
1378     ret = -1;
1379     }
1380    
1381     return ret;
1382     }
1383 sysadm 1.18
1384     int get_user_id_list(int32_t *p_uid_list, int *p_user_cnt, int start_uid)
1385     {
1386     int left;
1387     int right;
1388     int mid;
1389     int ret = 0;
1390     int i;
1391    
1392     if (p_uid_list == NULL || p_user_cnt == NULL)
1393     {
1394     log_error("NULL pointer error\n");
1395     return -1;
1396     }
1397    
1398     // acquire lock of user list
1399 sysadm 1.39 if (user_list_rd_lock() < 0)
1400 sysadm 1.18 {
1401     log_error("user_list_rd_lock() error\n");
1402     return -2;
1403     }
1404    
1405     left = 0;
1406 sysadm 1.37 right = p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].user_count - 1;
1407 sysadm 1.18
1408     while (left < right)
1409     {
1410     mid = (left + right) / 2;
1411 sysadm 1.37 if (start_uid < p_user_list_pool->user_list[p_user_list_pool->user_list_index_current].index_uid[mid].uid)
1412 sysadm 1.18 {
1413 sysadm 1.22 right = mid - 1;
1414 sysadm 1.18 }
1415 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)
1416 sysadm 1.18 {
1417     left = mid + 1;
1418     }
1419 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)
1420 sysadm 1.18 {
1421     left = mid;
1422     break;
1423     }
1424     }
1425    
1426 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++)
1427 sysadm 1.18 {
1428 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;
1429 sysadm 1.18 }
1430     *p_user_cnt = i;
1431    
1432     // release lock of user list
1433 sysadm 1.39 if (user_list_rd_unlock() < 0)
1434 sysadm 1.18 {
1435     log_error("user_list_rd_unlock() error\n");
1436     ret = -1;
1437     }
1438    
1439     return ret;
1440     }
1441    
1442     int user_stat_update(void)
1443     {
1444     return user_stat_map_update(&(p_user_list_pool->user_stat_map));
1445     }
1446    
1447 sysadm 1.19 int user_article_cnt_inc(int32_t uid, int n)
1448     {
1449     return user_stat_article_cnt_inc(&(p_user_list_pool->user_stat_map), uid, n);
1450     }
1451    
1452     int get_user_article_cnt(int32_t uid)
1453 sysadm 1.18 {
1454     const USER_STAT *p_stat;
1455     int ret;
1456    
1457     ret = user_stat_get(&(p_user_list_pool->user_stat_map), uid, &p_stat);
1458     if (ret < 0)
1459     {
1460     log_error("user_stat_get(uid=%d) error: %d\n", uid, ret);
1461     return -1;
1462     }
1463     else if (ret == 0) // user not found
1464     {
1465     return -1;
1466     }
1467    
1468     return p_stat->article_count;
1469     }

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