diff options
author | piaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2008-03-26 13:47:01 +0800 |
---|---|---|
committer | piaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2008-03-26 13:47:01 +0800 |
commit | 2a2078146f1e079732cd1a471e064d34a4399890 (patch) | |
tree | 79317a4ab4ed6a610033ed914a2c8782c3a37790 /daemon/utmpd/utmpserver.c | |
parent | b860b474520a4f30b20c829d507d60a90338aadc (diff) | |
download | pttbbs-2a2078146f1e079732cd1a471e064d34a4399890.tar pttbbs-2a2078146f1e079732cd1a471e064d34a4399890.tar.gz pttbbs-2a2078146f1e079732cd1a471e064d34a4399890.tar.bz2 pttbbs-2a2078146f1e079732cd1a471e064d34a4399890.tar.lz pttbbs-2a2078146f1e079732cd1a471e064d34a4399890.tar.xz pttbbs-2a2078146f1e079732cd1a471e064d34a4399890.tar.zst pttbbs-2a2078146f1e079732cd1a471e064d34a4399890.zip |
- (internal) directory layout structure finetune
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@4022 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'daemon/utmpd/utmpserver.c')
-rw-r--r-- | daemon/utmpd/utmpserver.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/daemon/utmpd/utmpserver.c b/daemon/utmpd/utmpserver.c new file mode 100644 index 00000000..85adf8c3 --- /dev/null +++ b/daemon/utmpd/utmpserver.c @@ -0,0 +1,222 @@ +/* $Id$ */ +#include "bbs.h" +#include <err.h> + +struct { + int uid; + int nFriends, nRejects; + int friend[MAX_FRIEND]; + int reject[MAX_REJECT]; +} utmp[USHM_SIZE]; + +#ifdef NOFLOODING +#define MAXWAIT 1024 +#define FLUSHTIME (3600*6) + +struct { + time_t lasttime; + int count; +} flooding[MAX_USERS]; + +int nWaits, lastflushtime; +struct { + int uid; + int fd; + int index; +} waitqueue[MAXWAIT]; +#endif /* NOFLOODING */ + +inline int countarray(int *s, int max) +{ + int i; + for( i = 0 ; i < max && s[i] ; ++i ) + ; + return i; +} + +int +reverse_friend_stat(int stat) +{ + int stat1 = 0; + if (stat & IFH) + stat1 |= HFM; + if (stat & IRH) + stat1 |= HRM; + if (stat & HFM) + stat1 |= IFH; + if (stat & HRM) + stat1 |= IRH; + if (stat & IBH) + stat1 |= IBH; + return stat1; +} + +int set_friend_bit(int me, int ui) +{ + int hit = 0; + /* 判斷對方是否為我的朋友 ? */ + if( intbsearch(utmp[ui].uid, utmp[me].friend, utmp[me].nFriends) ) + hit = IFH; + + /* 判斷我是否為對方的朋友 ? */ + if( intbsearch(utmp[me].uid, utmp[ui].friend, utmp[ui].nFriends) ) + hit |= HFM; + + /* 判斷對方是否為我的仇人 ? */ + if( intbsearch(utmp[ui].uid, utmp[me].reject, utmp[me].nRejects) ) + hit |= IRH; + + /* 判斷我是否為對方的仇人 ? */ + if( intbsearch(utmp[me].uid, utmp[ui].reject, utmp[ui].nRejects) ) + hit |= HRM; + + return hit; +} + +void initdata(int index) +{ + utmp[index].nFriends = countarray(utmp[index].friend, MAX_FRIEND); + utmp[index].nRejects = countarray(utmp[index].reject, MAX_REJECT); + if( utmp[index].nFriends > 0 ) + qsort(utmp[index].friend, utmp[index].nFriends, + sizeof(int), qsort_intcompar); + if( utmp[index].nRejects > 0 ) + qsort(utmp[index].reject, utmp[index].nRejects, + sizeof(int), qsort_intcompar); +} + +inline void syncutmp(int cfd) +{ + int nSynced = 0, i; + for( i = 0 ; i < USHM_SIZE ; ++i, ++nSynced ) + if( toread(cfd, &utmp[i].uid, sizeof(utmp[i].uid)) > 0 && + toread(cfd, utmp[i].friend, sizeof(utmp[i].friend)) > 0 && + toread(cfd, utmp[i].reject, sizeof(utmp[i].reject)) > 0 ){ + if( utmp[i].uid ) + initdata(i); + } + else + for( ; i < USHM_SIZE ; ++i ) + utmp[i].uid = 0; + close(cfd); + fprintf(stderr, "%d users synced\n", nSynced); +} + +void processlogin(int cfd, int uid, int index) +{ + if( toread(cfd, utmp[index].friend, sizeof(utmp[index].friend)) > 0 && + toread(cfd, utmp[index].reject, sizeof(utmp[index].reject)) > 0 ){ + /* 因為 logout 的時候並不會通知 utmpserver , 可能會查到一些 + 已經 logout 的帳號。所以不能只取 MAX_FRIEND 而要多取一些 */ +#define MAX_FS (2 * MAX_FRIEND) + int iu, nFrs, stat, rstat; + ocfs_t fs[MAX_FS]; + + utmp[index].uid = uid; + initdata(index); + + for( nFrs = iu = 0 ; iu < USHM_SIZE && nFrs < MAX_FS ; ++iu ) + if( iu != index && utmp[iu].uid ){ + if( (stat = set_friend_bit(index, iu)) ){ + rstat = reverse_friend_stat(stat); + fs[nFrs].index = iu; + fs[nFrs].uid = utmp[iu].uid; + fs[nFrs].friendstat = (stat << 24) + iu; + fs[nFrs].rfriendstat = (rstat << 24) + index; + ++nFrs; + } + } + + towrite(cfd, &fs, sizeof(ocfs_t) * nFrs); + } + close(cfd); +} + +#ifdef NOFLOODING +void flushwaitqueue(void) +{ + int i; + for( i = 0 ; i < nWaits ; ++i ) + processlogin(waitqueue[i].fd, waitqueue[i].uid, waitqueue[i].index); + lastflushtime = time(NULL); + nWaits = 0; + memset(flooding, 0, sizeof(flooding)); +} +#endif + +/* XXX 具有被 DoS 的可能, 請用 firewall 之類擋起來 */ +int main(int argc, char **argv) +{ + struct sockaddr_in clientaddr; + int ch, port = 5120, sfd, cfd, len, index, uid; + char *iface_ip = NULL; + + Signal(SIGPIPE, SIG_IGN); + while( (ch = getopt(argc, argv, "p:i:h")) != -1 ) + switch( ch ){ + case 'p': + port = atoi(optarg); + break; + case 'i': + iface_ip = optarg; + break; + case 'h': + default: + fprintf(stderr, "usage: utmpserver [-i interface_ip] [-p port]\n"); + return 1; + } + + if( (sfd = tobind(iface_ip, port)) < 0 ) + return 1; + +#ifdef NOFLOODING + lastflushtime = time(NULL); +#endif + while( 1 ){ +#ifdef NOFLOODING + if( lastflushtime < (time(NULL) - 1800) ) + flushwaitqueue(); +#endif + + len = sizeof(clientaddr); + if( (cfd = accept(sfd, (struct sockaddr *)&clientaddr, &len)) < 0 ){ + if( errno != EINTR ) + sleep(1); + continue; + } + toread(cfd, &index, sizeof(index)); + if( index == -1 ){ + syncutmp(cfd); + continue; + } + + if( toread(cfd, &uid, sizeof(uid)) > 0 ){ + if( !(0 < uid || uid > MAX_USERS) ){ /* for safety */ + close(cfd); + continue; + } + +#ifdef NOFLOODING + if( (time(NULL) - flooding[uid].lasttime) < 20 ) + ++flooding[uid].count; + if( flooding[uid].count > 10 ){ + if( nWaits == MAXWAIT ) + flushwaitqueue(); + waitqueue[nWaits].uid = uid; + waitqueue[nWaits].index = index; + waitqueue[nWaits].fd = cfd; + ++nWaits; + + continue; + } + flooding[uid].lasttime = time(NULL); +#endif + + /* cfd will be closed in processlogin() */ + processlogin(cfd, uid, index); + } else { + close(cfd); + } + } + return 0; +} |