summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/pttstruct.h116
-rw-r--r--mbbsd/cache.c30
-rw-r--r--mbbsd/cal.c13
-rw-r--r--mbbsd/read.c1
-rw-r--r--mbbsd/stuff.c8
-rw-r--r--mbbsd/var.c1
-rw-r--r--mbbsd/xyz.c14
-rw-r--r--util/Makefile2
-rw-r--r--util/shmctl.c31
-rw-r--r--util/shmsweep.c38
-rw-r--r--util/uhash_loader.c23
11 files changed, 133 insertions, 144 deletions
diff --git a/include/pttstruct.h b/include/pttstruct.h
index d594ffff..26eacc51 100644
--- a/include/pttstruct.h
+++ b/include/pttstruct.h
@@ -160,6 +160,8 @@ typedef struct userec_t {
#define BTLEN 48 /* Length of board title */
+/* TODO 動態更新的欄位不應該跟要寫入檔案的混在一起,
+ * 至少用個 struct 包起來之類 */
typedef struct boardheader_t {
char brdname[IDLEN + 1]; /* bid */
char title[BTLEN + 1];
@@ -327,66 +329,82 @@ typedef struct msgque_t {
} msgque_t;
/* user data in shm */
+/* use GAP to detect and avoid data overflow and overriding */
typedef struct userinfo_t {
int uid; /* Used to find user name in passwd file */
pid_t pid; /* kill() to notify user of talk request */
int sockaddr; /* ... */
- int destuid; /* talk uses this to identify who called */
- int destuip; /* dest index in utmpshm->uinfo[] */
- unsigned char active; /* When allocated this field is true */
- unsigned char invisible; /* Used by cloaking function in Xyz menu */
- unsigned char sockactive; /* Used to coordinate talk requests */
- unsigned char angel;
+
+ /* user data */
unsigned int userlevel;
- unsigned char mode; /* UL/DL, Talk Mode, Chat Mode, ... */
- unsigned char pager; /* pager toggle, YEA, or NA */
- unsigned char in_chat; /* for in_chat commands */
- unsigned char sig; /* signal type */
char userid[IDLEN + 1];
- char chatid[11]; /* chat id, if in chat mode */
char username[24];
char from[27]; /* machine name the user called in from */
int from_alias;
- char birth; /* 是否是生日 Ptt*/
+ char sex;
+ unsigned char goodpost;
+ unsigned char badpost;
+ unsigned char goodsale;
+ unsigned char badsale;
+ unsigned char angel;
+
+ /* friends */
+ int friendtotal; /* 好友比較的cache 大小 */
short nFriends; /* 下面 friend[] 只用到前幾個,
用來 bsearch */
int friend[MAX_FRIEND];
+ char gap_1[4];
int friend_online[MAX_FRIEND];/* point到線上好友 utmpshm的位置 */
/* 好友比較的cache 前兩個bit是狀態 */
+ char gap_2[4];
int reject[MAX_REJECT];
- unsigned short int chess_elo_rating;
- int lock;
- int friendtotal; /* 好友比較的cache 大小 */
+ char gap_3[4];
+
+ /* messages */
char msgcount;
msgque_t msgs[MAX_MSGS];
- unsigned int withme;
+ char gap_4[sizeof(msgque_t)]; /* avoid msgs racing and overflow */
+
+ /* user status */
+ char birth; /* 是否是生日 Ptt*/
+ unsigned char active; /* When allocated this field is true */
+ unsigned char invisible; /* Used by cloaking function in Xyz menu */
+ unsigned char mode; /* UL/DL, Talk Mode, Chat Mode, ... */
+ unsigned char pager; /* pager toggle, YEA, or NA */
time4_t lastact; /* 上次使用者動的時間 */
- unsigned int brc_id;
+ char mailalert;
+ char mind[4];
+
+ /* chatroom/talk/games calling */
+ unsigned char sig; /* signal type */
+ int destuid; /* talk uses this to identify who called */
+ int destuip; /* dest index in utmpshm->uinfo[] */
+ unsigned char sockactive; /* Used to coordinate talk requests */
+
+ /* chat */
+ unsigned char in_chat; /* for in_chat commands */
+ char chatid[11]; /* chat id, if in chat mode */
+
+ /* games */
unsigned char lockmode; /* 不准 multi_login 玩的東西 */
- char turn; /* for gomo */
- char mateid[IDLEN + 1]; /* for gomo */
+ char turn; /* 遊戲的先後 */
+ char mateid[IDLEN + 1]; /* 遊戲對手的 id */
+ char color; /* 暗棋 顏色 */
- /* 為了 sync 回 .PASSWDS 時使用 */
+ /* game record */
unsigned short int five_win;
unsigned short int five_lose;
unsigned short int five_tie;
unsigned short int chc_win;
unsigned short int chc_lose;
unsigned short int chc_tie;
+ unsigned short int chess_elo_rating;
+
+ /* misc */
+ unsigned int withme;
+ unsigned int brc_id;
- unsigned char goodpost;
- char pad_1;
- unsigned char badpost;
- char pad_2;
- unsigned char goodsale;
- char pad_3;
- unsigned char badsale;
- char pad_4;
- char mailalert;
- char sex;
- char color;
- char mind[4];
#ifdef NOKILLWATERBALL
time4_t wbtime;
#endif
@@ -436,30 +454,36 @@ typedef struct keeploc_t {
} keeploc_t;
#define VALID_USHM_ENTRY(X) ((X) >= 0 && (X) < USHM_SIZE)
-#define USHM_SIZE (MAX_ACTIVE + 4)
+#define USHM_SIZE ((MAX_ACTIVE)*4/3)
/* USHM_SIZE 比 MAX_ACTIVE 大是為了防止檢查人數上限時, 又同時衝進來
* 會造成找 shm 空位的無窮迴圈.
- * -> 若是這樣, +4 夠嗎?
- * 又, 因 USHM 中用 hash, 空間稍大時效率較好.
- * -> 若是因為 hashing, slot 也許要更多, 譬如兩倍? */
+ * 又, 因 USHM 中用 hash, 空間稍大時效率較好. */
/* MAX_BMs is dirty hardcode 4 in mbbsd/cache.c:is_BM_cache() */
#define MAX_BMs 4 /* for BMcache, 一個看板最多幾板主 */
+#define SHM_VERSION 2549
typedef struct {
+ int version;
/* uhash */
char userid[MAX_USERS][IDLEN + 1];
+ char gap_1[IDLEN+1];
int next_in_hash[MAX_USERS];
+ char gap_2[sizeof(int)];
int money[MAX_USERS];
+ char gap_3[sizeof(int)];
int hash_head[1 << HASH_BITS];
+ char gap_4[sizeof(int)];
int number; /* # of users total */
int loaded; /* .PASSWD has been loaded? */
/* utmpshm */
userinfo_t uinfo[USHM_SIZE];
+ char gap_5[sizeof(userinfo_t)];
int sorted[2][8][USHM_SIZE];
/* 第一維double buffer 由currsorted指向目前使用的
第二維sort type */
+ char gap_6[sizeof(int)];
int currsorted;
time4_t UTMPuptime;
int UTMPnumber;
@@ -467,18 +491,28 @@ typedef struct {
char UTMPbusystate;
/* brdshm */
+ char gap_7[sizeof(int)];
int BMcache[MAX_BOARD][MAX_BMs];
+ char gap_8[sizeof(int)];
boardheader_t bcache[MAX_BOARD];
+ char gap_9[sizeof(int)];
int bsorted[2][MAX_BOARD]; /* 0: by name 1: by class */ /* 裡頭存的是 bid-1 */
+ char gap_10[sizeof(int)];
#if HOTBOARDCACHE
unsigned char nHOTs;
int HBcache[HOTBOARDCACHE];
#endif
+ char gap_11[sizeof(int)];
time4_t busystate_b[MAX_BOARD];
+ char gap_12[sizeof(int)];
int total[MAX_BOARD];
+ char gap_13[sizeof(int)];
unsigned char n_bottom[MAX_BOARD]; /* number of bottom */
+ char gap_14[sizeof(int)];
int hbfl[MAX_BOARD][MAX_FRIEND + 1]; /* hidden board friend list, 0: load time, 1-MAX_FRIEND: uid */
+ char gap_15[sizeof(int)];
time4_t lastposttime[MAX_BOARD];
+ char gap_16[sizeof(int)];
time4_t Buptime;
time4_t Btouchtime;
int Bnumber;
@@ -487,9 +521,12 @@ typedef struct {
/* pttcache */
char notes[MAX_MOVIE][200*11];
+ char gap_17[sizeof(int)];
char today_is[20];
int n_notes[MAX_MOVIE_SECTION]; /* 一節中有幾個 看板 */
+ char gap_18[sizeof(int)];
int next_refresh[MAX_MOVIE_SECTION]; /* 下一次要refresh的 看板 */
+ char gap_19[sizeof(int)];
msgque_t loginmsg; /* 進站水球 */
int max_film;
int max_history;
@@ -497,11 +534,9 @@ typedef struct {
time4_t Ptouchtime;
int Pbusystate;
- int GLOBALVAR[10]; /* mbbsd間的 global variable
- 用以做統計等資料 (非常態) */
-
+ /* SHM 中的全域變數, 可用 shmctl 設定或顯示. 供動態調整或測試使用 */
union {
- int v[256];
+ int v[1024];
struct {
int dymaxactive; /* 動態設定最大人數上限 */
int toomanyusers; /* 超過人數上限不給進的個數 */
@@ -510,6 +545,7 @@ typedef struct {
time4_t now;
#endif
int nWelcomes;
+ /* 注意, 應保持 align sizeof(int) */
} e;
} GV2;
diff --git a/mbbsd/cache.c b/mbbsd/cache.c
index 469acc46..4345e282 100644
--- a/mbbsd/cache.c
+++ b/mbbsd/cache.c
@@ -65,6 +65,12 @@ void
attach_SHM(void)
{
SHM = attach_shm(SHM_KEY, sizeof(SHM_t));
+ if(SHM->version != SHM_VERSION) {
+ fprintf(stderr, "Error: SHM->version(%d) != SHM_VERSION(%d)\n", SHM->version, SHM_VERSION);
+ fprintf(stderr, "Please use the source code version corresponding to SHM,\n"
+ "or use ipcrm(1) command to clean share memory.\n");
+ exit(1);
+ }
if (!SHM->loaded) /* (uhash) assume fresh shared memory is
* zeroed */
exit(1);
@@ -73,7 +79,6 @@ attach_SHM(void)
bcache = SHM->bcache;
numboards = SHM->Bnumber;
- GLOBALVAR = SHM->GLOBALVAR;
if (SHM->Ptouchtime == 0)
SHM->Ptouchtime = 1;
@@ -142,9 +147,12 @@ sem_lock(int op, int semid)
void
add_to_uhash(int n, char *id)
{
- int *p, h = StringHash(id);
+ int *p, h = StringHash(id)%(1<<HASH_BITS);
int times;
strlcpy(SHM->userid[n], id, sizeof(SHM->userid[n]));
+#if (1<<HASH_BITS)*2 < MAX_USERS
+#error "HASH_BITS too small"
+#endif
p = &(SHM->hash_head[h]);
@@ -164,7 +172,7 @@ remove_from_uhash(int n)
* note: after remove_from_uhash(), you should add_to_uhash() (likely with a
* different name)
*/
- int h = StringHash(SHM->userid[n]);
+ int h = StringHash(SHM->userid[n])%(1<<HASH_BITS);
int *p = &(SHM->hash_head[h]);
int times;
@@ -182,7 +190,7 @@ int
searchuser(char *userid)
{
int h, p, times;
- h = StringHash(userid);
+ h = StringHash(userid)%(1<<HASH_BITS);
p = SHM->hash_head[h];
for (times = 0; times < MAX_USERS && p != -1 && p < MAX_USERS ; ++times) {
@@ -265,9 +273,10 @@ void
getnewutmpent(userinfo_t * up)
{
/* Ptt:這裡加上 hash 觀念找空的 utmp */
- register int i, p;
+ register int i;
register userinfo_t *uentp;
- for (i = 0, p = StringHash(up->userid) % USHM_SIZE; i < USHM_SIZE; i++, p++) {
+ unsigned int p = StringHash(up->userid) % USHM_SIZE;
+ for (i = 0; i < USHM_SIZE; i++, p++) {
if (p == USHM_SIZE)
p = 0;
uentp = &(SHM->uinfo[p]);
@@ -1000,7 +1009,7 @@ hbflreload(int bid)
fclose(fp);
}
hbfl[0] = COMMON_TIME;
- memcpy(SHM->hbfl[bid], hbfl, sizeof(hbfl)); // FIXME bid-1 ?
+ memcpy(SHM->hbfl[bid-1], hbfl, sizeof(hbfl));
}
/* 是否"不"通過板友測試. 如果在板友名單中的話傳回 0, 否則為 1 */
@@ -1009,11 +1018,10 @@ hbflcheck(int bid, int uid)
{
int i;
- // FIXME bid-1?
- if (SHM->hbfl[bid][0] < login_start_time - HBFLexpire)
+ if (SHM->hbfl[bid-1][0] < login_start_time - HBFLexpire)
hbflreload(bid);
- for (i = 1; SHM->hbfl[bid][i] != 0 && i <= MAX_FRIEND; ++i) {
- if (SHM->hbfl[bid][i] == uid)
+ for (i = 1; SHM->hbfl[bid-1][i] != 0 && i <= MAX_FRIEND; ++i) {
+ if (SHM->hbfl[bid-1][i] == uid)
return 0;
}
return 1;
diff --git a/mbbsd/cal.c b/mbbsd/cal.c
index 1c997836..d0fb17b3 100644
--- a/mbbsd/cal.c
+++ b/mbbsd/cal.c
@@ -3,18 +3,21 @@
/* 防堵 Multi play */
static int
-count_multiplay(int unmode)
+is_playing(int unmode)
{
register int i, j;
register userinfo_t *uentp;
+ unsigned int p = StringHash(cuser.userid) % USHM_SIZE;
for (i = j = 0; i < USHM_SIZE; i++) { // XXX linear search
- uentp = &(SHM->uinfo[i]);
+ if (p == USHM_SIZE)
+ p = 0;
+ uentp = &(SHM->uinfo[p]);
if (uentp->uid == usernum)
if (uentp->lockmode == unmode)
- j++;
+ return 1;
}
- return j;
+ return 0;
}
int
@@ -24,7 +27,7 @@ lockutmpmode(int unmode, int state)
if (currutmp->lockmode)
errorno = 1;
- else if (count_multiplay(unmode))
+ else if (is_playing(unmode))
errorno = 2;
if (errorno && !(state == LOCK_THIS && errorno == LOCK_MULTI)) {
diff --git a/mbbsd/read.c b/mbbsd/read.c
index 58a8678f..cf471688 100644
--- a/mbbsd/read.c
+++ b/mbbsd/read.c
@@ -208,6 +208,7 @@ getkeep(char *s, int def_topline, int def_cursline)
* 一方面 size 小, malloc space overhead 就高, 因此改成 link block,
* 以 KEEPSLOT 為一個 block 的 link list.
* 只有第一個 block 可能沒滿. */
+ /* TODO LRU recycle? 麻煩在於別處可能把 keeploc_t pointer 記著... */
#define KEEPSLOT 10
struct keepsome {
unsigned char used;
diff --git a/mbbsd/stuff.c b/mbbsd/stuff.c
index 2ea16fec..3d3b90f8 100644
--- a/mbbsd/stuff.c
+++ b/mbbsd/stuff.c
@@ -1,5 +1,6 @@
/* $Id$ */
#include "bbs.h"
+#include "fnv_hash.h"
/* ----------------------------------------------------- */
/* set file path for boards/user home */
@@ -895,12 +896,7 @@ void FREE(void *ptr)
unsigned
StringHash(unsigned char *s)
{
- unsigned int v = 0;
- while (*s) {
- v = (v << 8) | (v >> 24);
- v ^= toupper(*s++); /* note this is case insensitive */
- }
- return (v * 2654435769U) >> (32 - HASH_BITS);
+ return fnv1a_32_strcase(s, FNV1_32_INIT);
}
inline int *intbsearch(int key, int *base0, int nmemb)
diff --git a/mbbsd/var.c b/mbbsd/var.c
index ff880155..95cdad2e 100644
--- a/mbbsd/var.c
+++ b/mbbsd/var.c
@@ -356,7 +356,6 @@ int wmofo = NOTREPLYING;
/* cache.c */
int numboards = -1;
-int *GLOBALVAR;
SHM_t *SHM;
boardheader_t *bcache;
userinfo_t *currutmp;
diff --git a/mbbsd/xyz.c b/mbbsd/xyz.c
index b757392d..003f5a51 100644
--- a/mbbsd/xyz.c
+++ b/mbbsd/xyz.c
@@ -335,19 +335,6 @@ m_sysop()
return 0;
}
-void
-log_memoryusage(void)
-{
-#ifdef IA32
- int use=((int)sbrk(0)-0x8048000)/1024;
- if(use<500)
- use=499;
- if(use>1000)
- use=1000;
- GLOBALVAR[use/100-4]++; // use [0]~[6]
-#endif
-}
-
int
Goodbye()
{
@@ -369,7 +356,6 @@ Goodbye()
else if (genbuf[0] == 'n')
note();
}
- log_memoryusage();
clear();
prints("\033[1;36m親愛的 \033[33m%s(%s)\033[36m,別忘了再度光臨\033[45;33m"
" %s \033[40;36m!\n以下是您在站內的註冊資料:\033[0m\n",
diff --git a/util/Makefile b/util/Makefile
index 6d5d1b6b..4fd284d0 100644
--- a/util/Makefile
+++ b/util/Makefile
@@ -30,7 +30,7 @@ CPROG_WITH_UTIL= \
# 下面這些程式, 會直接被 compile
CPROG_WITHOUT_UTIL= \
- shmsweep uhash_loader showboard \
+ uhash_loader showboard \
countalldice webgrep bbsrf initbbs \
userlist merge_passwd \
merge_board bbsmail
diff --git a/util/shmctl.c b/util/shmctl.c
index 2933006d..afe60293 100644
--- a/util/shmctl.c
+++ b/util/shmctl.c
@@ -551,10 +551,13 @@ char *GV2str[] = {"dymaxactive", "toomanyusers",
int showglobal(int argc, char **argv)
{
int i;
- for( i = 0 ; i < 10 ; ++i )
- printf("GLOBALVAR[%d] = %d\n", i, SHM->GLOBALVAR[i]);
for( i = 0 ; GV2str[i] != NULL ; ++i )
printf("GV2.%s = %d\n", GV2str[i], SHM->GV2.v[i]);
+ if(argv[1]) {
+ int n=atoi(argv[1]);
+ if(n>(sizeof(SHM->GV2.v)/sizeof(int)))
+ n=sizeof(SHM->GV2.v)/sizeof(int);
+ }
return 0;
}
@@ -562,26 +565,18 @@ int setglobal(int argc, char **argv)
{
int where, value;
if( argc != 3 ){
- puts("usage: shmctl setglobal ([0-9]|GV2) newvalue");
+ puts("usage: shmctl setglobal (GV2) newvalue");
return 1;
}
- where = argv[1][0] - '0';
value = atoi(argv[2]);
- if( 0 <= where && where <= 9 ){
- printf("GLOBALVAR[%d] = %d -> ", where, SHM->GLOBALVAR[where]);
- printf("%d\n", SHM->GLOBALVAR[where] = value);
- return 0;
- }
- else{
- for( where = 0 ; GV2str[where] != NULL ; ++where )
- if( strcmp(GV2str[where], argv[1]) == 0 ){
- printf("GV2.%s = %d -> ", GV2str[where], SHM->GV2.v[where]);
- printf("%d\n", SHM->GV2.v[where] = value);
- return 0;
- }
- }
- printf("GLOBALVAR %s not found\n", argv[1]);
+ for( where = 0 ; GV2str[where] != NULL ; ++where )
+ if( strcmp(GV2str[where], argv[1]) == 0 ){
+ printf("GV2.%s = %d -> ", GV2str[where], SHM->GV2.v[where]);
+ printf("%d\n", SHM->GV2.v[where] = value);
+ return 0;
+ }
+ printf("SHM global variable %s not found\n", argv[1]);
return 1;
}
diff --git a/util/shmsweep.c b/util/shmsweep.c
deleted file mode 100644
index b448270f..00000000
--- a/util/shmsweep.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "bbs.h"
-
-int main() {
-#if 0
- int i, shm, counter;
- struct utmpfile_t *utmpshm;
-
-
- shm = shmget(UTMPSHM_KEY, USHM_SIZE, SHM_R | SHM_W);
- if(shm == -1) {
- perror("shmget");
- exit(0);
- }
-
- utmpshm = shmat(shm, NULL, 0);
- if(utmpshm == (struct utmpfile_t *)-1) {
- perror("shmat");
- exit(0);
- }
-
- for(i = counter = 0; i < USHM_SIZE; i++)
- if(SHM->uinfo[i].pid) {
- char buf[256];
- userinfo_t *f;
- struct stat sb;
-
- f = &utmpshm->uinfo[i];
- sprintf(buf, "/proc/%d", f->pid);
- if(stat(buf, &sb)) {
- f->pid = 0;
- utmpshm->number--;
- counter++;
- }
- }
- printf("clear %d slots\n", counter);
-#endif
- return 0;
-}
diff --git a/util/uhash_loader.c b/util/uhash_loader.c
index e608701c..55301210 100644
--- a/util/uhash_loader.c
+++ b/util/uhash_loader.c
@@ -1,6 +1,7 @@
/* $Id$ */
/* standalone uhash loader -- jochang */
#include "bbs.h"
+#include "fnv_hash.h"
unsigned string_hash(unsigned char *s);
void userec_add_to_uhash(int n, userec_t *id, int onfly);
@@ -34,9 +35,17 @@ void load_uhash(void) {
perror("shmat");
exit(1);
}
- if( err != EEXIST)
+ if( err != EEXIST) {
SHM->number=SHM->loaded = 0;
+ SHM->version = SHM_VERSION;
+ }
+ if(SHM->version != SHM_VERSION) {
+ fprintf(stderr, "Error: SHM->version(%d) != SHM_VERSION(%d)\n", SHM->version, SHM_VERSION);
+ fprintf(stderr, "Please use the source code version corresponding to SHM,\n"
+ "or use ipcrm(1) command to clean share memory.\n");
+ exit(1);
+ }
// in case it's not assumed zero, this becomes a race...
if(SHM->number==0 && SHM->loaded == 0)
@@ -57,7 +66,7 @@ void checkhash(int h)
while(*p != -1)
{
if(*p <-1 || *p >= MAX_USERS) {*p=-1; return;}
- ch = string_hash( SHM->userid[*p]);
+ ch = string_hash( SHM->userid[*p])%(1<<HASH_BITS);
if(ch!=h)
{
printf("remove %d %d!=%d %d [%s] next:%d\n",
@@ -118,20 +127,14 @@ void fill_uhash(int onfly)
}
unsigned string_hash(unsigned char *s)
{
- unsigned int v = 0;
- while (*s)
- {
- v = (v << 8) | (v >> 24);
- v ^= toupper(*s++); /* note this is case insensitive */
- }
- return (v * 2654435769U) >> (32 - HASH_BITS);
+ return fnv1a_32_strcase(s, FNV1_32_INIT);
}
void userec_add_to_uhash(int n, userec_t *user, int onfly)
{
int *p, h, l=0;
- h = string_hash(user->userid);
+ h = string_hash(user->userid)%(1<<HASH_BITS);
p = &(SHM->hash_head[h]);
if(!onfly || SHM->userid[n][0] != user->userid[0] ||