diff options
-rw-r--r-- | Makefile | 47 | ||||
-rw-r--r-- | bank.h | 19 | ||||
-rw-r--r-- | bankstuff.c | 51 | ||||
-rw-r--r-- | client.c | 56 | ||||
-rw-r--r-- | money.c | 37 | ||||
-rw-r--r-- | server.c | 144 | ||||
-rw-r--r-- | spec | 38 |
7 files changed, 392 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..c0050312 --- /dev/null +++ b/Makefile @@ -0,0 +1,47 @@ + +CFLAGS = -O2 -Os -fomit-frame-pointer -fstrength-reduce -fthread-jumps -fexpensive-optimizations -pipe -I../include -DLinux -DBANK_ONLY +#CFLAGS = -O2 -Os -fomit-frame-pointer -fstrength-reduce -fthread-jumps -fexpensive-optimizations -Wall -pipe -I../include -DLinux -DBANK_ONLY + +.if defined(DEBUG) +CFLAGS += -g +.endif + +.if !defined(NOTPTT) +CFLAGS += -DPTTBBS +.endif + +SERVEROBJ = server.o bankstuff.o money.o +CLIENTOBJ = client.o bankstuff.o +EXTFILE = cache passwd stuff +EXTOBJ = cache.o passwd.o stuff.o +PROG = client server + +.SUFFIXES: .c .o +.c.o: ; $(CC) $(CFLAGS) -c $*.c + +all: $(PROG) + +.if !defined(NOTPTT) + +cache: ../mbbsd/cache.c + $(CC) $(CFLAGS) -c ../mbbsd/cache.c + +passwd: ../mbbsd/passwd.c + $(CC) $(CFLAGS) -c ../mbbsd/passwd.c + +stuff: ../mbbsd/stuff.c + $(CC) $(CFLAGS) -c ../mbbsd/stuff.c + +.else +# define your rules here. + +.endif + +server: $(SERVEROBJ) $(EXTFILE) + $(CC) $(CFLAGS) -o server $(SERVEROBJ) $(EXTOBJ) + +client: $(CLIENTOBJ) + $(CC) $(CFLAGS) -o client $(CLIENTOBJ) + +clean: + rm -rf *.o $(PROG) @@ -0,0 +1,19 @@ +#include "../include/bbs.h" + +#define PORT 2003 + +#ifdef STRLEN + #undef STRLEN +#endif +#define STRLEN 128 + +#define ERROR 0x1 +#define SUCCESS 0x2 +#define TIMEOUT 0x4 + +typedef int response; + +typedef struct request{ + int money; + char userid[IDLEN]; +}request; diff --git a/bankstuff.c b/bankstuff.c new file mode 100644 index 00000000..c1e7bff6 --- /dev/null +++ b/bankstuff.c @@ -0,0 +1,51 @@ +#include "bank.h" + +int sockfd; + +char* readline(char *str, int timeout){ + int len; + struct timeval tv; + fd_set set; + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + FD_ZERO(&set); + FD_SET(sockfd, &set); + + if (select(sockfd + 1, &set, NULL, NULL,!timeout ? NULL : &tv) <= 0) { /// + perror("select"); + exit(-1); + } + + if ((len = read(sockfd, str, STRLEN * sizeof(char))) < 0){ + herror("readline"); + exit(-1); + } + if (len == 0) + return NULL; + str[len] = 0; + read(sockfd, &len, sizeof(char)); // chomp + return str; +} + +void writeln(char *str){ + char n = '\n'; + write(sockfd, str, strlen(str)); + write(sockfd, &n, sizeof(n)); +} + +void getcmd(char *buf, char *cmd, char *param){ + int i; + for(i = 0; buf[i] && buf[i] != ' ' && i < STRLEN; i++) + cmd[i] = buf[i]; + cmd[i] = 0; + if (!buf[i]){ + param = NULL; + return; + } + buf = &buf[i + 1]; + for(i = 0; buf[i] && i < STRLEN; i++) + param[i] = buf[i]; + param[i] = 0; +} diff --git a/client.c b/client.c new file mode 100644 index 00000000..926a324a --- /dev/null +++ b/client.c @@ -0,0 +1,56 @@ +#include "bank.h" + +extern int sockfd; + +char* chomp(char *str){ + int len; + len = strlen(str); + if(len > 0 && str[len - 1] == '\n') + str[len - 1] = 0; + return str; +} + +void client_work(FILE *fp){ + char buf[STRLEN]; + while(fgets(buf, sizeof(buf), stdin) != NULL){ + printf("before sending\n"); + chomp(buf); + writeln(buf); + if(!strcasecmp(buf, "quit")) + break; + printf("> %s\n", readline(buf, 0)); + } +} + +void init_net(char *addr){ + struct hostent *host = NULL; + struct sockaddr_in serv_addr; + + if((host = gethostbyname(addr)) == NULL){ + herror("gethostbyname"); + exit(-1); + } + bcopy(host->h_addr, &serv_addr.sin_addr, host->h_length); + + if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0){ + herror("socket"); + } + + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(PORT); + inet_pton(AF_INET, addr, &serv_addr.sin_addr); + + connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); +} + +int main(int argc, char **argv){ +// if(argc != 3) +// exit(-1); + + init_net(argv[1]); + client_work(stdin); + + return 0; +} diff --git a/money.c b/money.c new file mode 100644 index 00000000..6dd5b21e --- /dev/null +++ b/money.c @@ -0,0 +1,37 @@ +/* + * 若您使用的是 Current Ptt,則不必做任何的修正。 + * 若您使用的是其他版本的 bbs,請將 Makefile 中的 -DPTTBBS 那行取消掉, + * 並自行於下面的 #elseif 之後加入適當的程式碼。 + */ + +#define RATE 0.95 + +int bank_moneyof(int uid){ +#ifdef PTTBBS + printf("[server] : uid = %d\n", uid); + return moneyof(uid); +#else + // +#endif +} + +int bank_searchuser(char *userid){ + +#ifdef PTTBBS + return searchuser(userid); +#else + // +#endif +} + +int bank_deumoney(char *user, int money){ + +#ifdef PTTBBS + + money *= RATE; + printf("give user: %s money: %d add:%d\n", user, moneyof(bank_searchuser(user)), money); + deumoney(bank_searchuser(user), money); +#else + // +#endif +} diff --git a/server.c b/server.c new file mode 100644 index 00000000..ad9b9054 --- /dev/null +++ b/server.c @@ -0,0 +1,144 @@ +#include "bank.h" + +extern int sockfd; + +SHM_t *SHM; +char *fn_passwd = ".PASSWDS"; +char flag; + +typedef struct map_t { + char *key; + int (*fp)(char *); +} map_t; + +void sig_handler(int signo){ + pid_t pid; + while( (pid = waitpid(-1, NULL, WNOHANG)) > 0) + fprintf(stderr, "Child %d terminated\n", pid); + exit(0); +} + +int list(char *param){ + printf("list: %s\n", param); + writemsg(SUCCESS, "list success"); + return 1; +} + +int query(char *param){ + char buf[STRLEN]; + sprintf(buf, "%s's money is %d", param, bank_moneyof(bank_searchuser(param))); + writemsg(SUCCESS, buf); + return 1; +} + +int give(char param[STRLEN]){ + char user[STRLEN], money[STRLEN]; + char tmp[STRLEN]; + printf("give: %s\n", param); + getcmd(param, user, money); + bank_deumoney(user, atoi(money)); + sprintf(tmp, "give %s %s", user, money); + writemsg(SUCCESS, tmp); + return 1; +} + +int quit(char *param){ + printf("[server] client quit\n"); + exit(0); +} + +map_t map[] = { + {"list", list}, + {"query", query}, + {"give", give}, + {"quit", quit}, + {"", NULL}, +}; + +void writemsg(int status, char *str){ + //write(sockfd, &status. sizeof(status)); + writeln(str); +} + +void serv_work(void){ + int i, status = ERROR; + char buf[STRLEN], cmd[STRLEN], param[STRLEN]; + + fprintf(stderr, "new child\n"); + + attach_SHM(); + + while(readline(buf, 600) != NULL){ + printf("[server] read: "); + puts(buf); + getcmd(buf, cmd, param); + for (i = 0; map[i].fp; i++){ + if (!strcasecmp(map[i].key, cmd)){ + status = (*(map[i].fp))(param); + break; + } + } + if(!map[i].fp){ + writemsg(ERROR, "Wrong command"); + strcpy(param, "error"); + } + printf("[server] complete\n"); + } +} + +int check_perm(char *ip){ +} + +int main(int argc, char **argv){ + int listenfd; + pid_t pid; + socklen_t addr_len; + struct sockaddr_in serv_addr; + + listenfd = socket(PF_INET, SOCK_STREAM, 0); + + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(PORT); + + bind(listenfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)); + listen(listenfd, 5); + signal(SIGCHLD, sig_handler); + + while(1){ + addr_len = sizeof(serv_addr); + + if( (sockfd = accept(listenfd,(struct sockaddr *) &serv_addr, &addr_len)) < 0){ + if(errno == EINTR) + continue; + else + herror("accept"); + } +#define NOFORK 1 +#if NOFORK + if((pid = fork()) < 0) + perror("fork"); + + else if(pid == 0){ +#endif + int len; + struct sockaddr_in name; + close(listenfd); + + if(getpeername(sockfd,(struct sockaddr *) &name, &len) < 0){ + perror("getpeername"); + exit(-1); + } + else{ + printf("address: %s\n", inet_ntoa(((struct sockaddr_in *) &name)->sin_addr)); + } + serv_work(); + exit(0); +#if NOFORK + } +#endif + close(sockfd); + } + return 0; +} @@ -0,0 +1,38 @@ + +Use Case: + list: + 列出所有接受轉帳的站台。 + query site: + 列出 site 這個站的資訊,包括匯率等。 + quit: + 切斷連線離開。 + + + + + +-------+ +-------+ + +-------+ | +----------+ +----------+ +-------+ | + | client|-+ ---| bankd(1) | <--------> | bankd(2) |---| client|-+ + +-------+ +----------+ +----------+ +-------+ + + client: + +Note: + client 能夠改 source,所以請務必注意 server 一定要小心防止 client + 的惡搞 + +Protocol (between banks): + 1.假設 bankd(1) 為 Ptt 這端的 daemon,bankd(2) 為 Ptt2 這端的。 + 2.當 Ptt 上有人想匯錢給 Ptt2 上的人,Ptt user(mbbsd) 這邊會開啟與 + 指定機器上 bank 的連線。[1] + 3.Client 先扣除自己的錢[2],再跟 server 說他要轉帳的對象跟金額。 + 4.Server 進行確認動作 + 1) 確定對方紀錄的匯率與自己相同。不同則回應錯誤。 + 2) 確定此人是否存在。是,則將錢匯入,回應成功訊息;否,則回應錯 + 誤。 + 5.根據 server 的回應做出動作。成功則不做任何事,失敗就將自己的錢 + 加回來。 + + + [1] 不加密的原因是 ... 懶 :p 有需要的話直接拿 ssh tunnel 來用吧 :p + [2] 避免有人送錢之後惡意斷線,造成錢有增無減。 |