diff options
-rw-r--r-- | include/pttstruct.h | 116 | ||||
-rw-r--r-- | mbbsd/cache.c | 30 | ||||
-rw-r--r-- | mbbsd/cal.c | 13 | ||||
-rw-r--r-- | mbbsd/read.c | 1 | ||||
-rw-r--r-- | mbbsd/stuff.c | 8 | ||||
-rw-r--r-- | mbbsd/var.c | 1 | ||||
-rw-r--r-- | mbbsd/xyz.c | 14 | ||||
-rw-r--r-- | util/Makefile | 2 | ||||
-rw-r--r-- | util/shmctl.c | 31 | ||||
-rw-r--r-- | util/shmsweep.c | 38 | ||||
-rw-r--r-- | util/uhash_loader.c | 23 |
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] || |