/* * gnyognyo server * (c)1994,1995 by HIROSE Yuuji [pcs39334@asciinet.or.jp] */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/signal.h> #include <sys/param.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <fcntl.h> #include <memory.h> /* ちょっとうまく動かないかも知れないです。直して下さい ^^; */ #define error(x) {fprintf(stderr, "gnyoserv: "); perror(x); exit(1);} #define GNYOPORT 9969 #define BUFLEN 256 #define MAXCL 3 static int sofd, clisofd[MAXCL+1], clients; static char *clinames[MAXCL], start=0; /* $Id$ */ char* savestr(char* str) { char *p; if (NULL == (p=(char*)malloc(strlen(str)+1))) error("Virtual memory exhausted."); strcpy(p, str); return p; } int mypoint(int me, int score[][MAXCL]) { int i, j, point=0; for (i=0; i<MAXCL; i++) { if (i != me) { point += score[i][me]; } } return point; } int sendstr(int fd, char* str, int mode) { return send(fd, str, strlen(str), mode); } /* 番号clientのクライアントから受け取った buffer を処理する */ int gnyoquery(int client, int fd, char* buffer) { /* 以下のコマンドを受け付ける: * * '!' 接続者が全員(2人以上)から ! が来たら go! を返す * '?' 接続者がのIDを返す * 'a' 続けて得点を書いてそれを加算 (例. a500) * 'b' 後続するメッセージを自分以外の全員に送る(例. baka) * blose! を受け取ると敗戦処理 * 'i' 全てのクライアントの得点をリセット * 'n' お名前を更新する (例. n太武郎); * 'r' 全ての敵のスコアの合計を受け取って清算する * 'v' 接続クライアントの表示 * 'q' 抜ける */ int i, j, point; static int score[MAXCL][MAXCL], ready[MAXCL], nentry=0; /* score[X][Y] は クライアントX の クライアントY に対する得点 */ static char sendbuf[BUFLEN]; switch (buffer[0]) { case '!': if (ready[client] == 0) { if (start) { sendstr(fd, "AHO-! おめーはげーむおーばーだろーが!\n", 0); } else { nentry++; ready[client] = 1; } } #ifdef DEBUG fprintf(stderr, "Client %d ready - c=%d, n=%d\n", client, clients, nentry); #endif j = 1; if (clients==nentry && clients!=1) { /* all are ready */ sprintf(sendbuf, "Go! %d clients exist.\n", clients); for (i=0; i<MAXCL; i++) { if (clisofd[i]) { /* gnyoquery(i, clisofd[i], "v\n"); */ sendstr(clisofd[i], sendbuf, 0); start = 1; /* set start-flag */ } } } break; case '?': sprintf(sendbuf, "Your id is %d.", client); sendstr(fd, sendbuf, 0); break; case 'a': for (j=0; j<MAXCL; j++) score[client][j] += atoi(buffer+1); #ifdef DEBUG fprintf(stderr, "Client %d's score=%d\n", client, score[client][j-1]); #endif break; case 'b': if ((0==strncmp(buffer+1, "lose!", 5)) && ready[client]) { ready[client] = 0; nentry--; sprintf(sendbuf, "Lost=%s\n", clinames[client]); j=strlen(sendbuf); for (i=0; i<MAXCL; i++) { if (i!=client && clisofd[i]) send(clisofd[i], sendbuf, j, 0); } if (nentry == 1) { /* Won! */ start = 0; /* clear start-flag */ for (j=0; ready[j]==0 && j<MAXCL; j++); if (j==MAXCL) break; ready[j] = nentry = 0; sendstr(clisofd[j], "You won!!\n", 0); } } else { sprintf(sendbuf, "m%d%s\r\n", client, 1+buffer); j=strlen(sendbuf); for (i=0; i<MAXCL; i++) { if (i!=client && clisofd[i]) { send(clisofd[i], sendbuf, j, 0); } } } break; case 'i': for (i=0; i<MAXCL; i++) { for (j=0; j<MAXCL; j++) score[i][j] = 0; } break; case 'n': if (clinames[client]) free(clinames[client]); if (strpbrk(buffer, "\r\n")) *((char*)strpbrk(buffer, "\r\n")) = '\0'; clinames[client] = savestr(1+buffer); break; case 'r': point = mypoint(client, score); for (i=0; i<MAXCL; i++) { score[i][client] = 0; } sprintf(sendbuf, "r=%d\n", point); sendstr(fd, sendbuf, 0); break; case 'v': for (i=0; i<MAXCL; i++) { if (clisofd[i]) { sprintf(sendbuf, "Client%d=%-40s (ready=%d)\n", i, clinames[i], /*mypoint(i, score),*/ ready[i]); sendstr(fd, sendbuf, 0); } } break; case 'q': ready[client] = 0; for (j=0; j<MAXCL; j++) score[client][j] = 0; sprintf(sendbuf, "またのお越しをお待ちしております.\n"); sendstr(fd, sendbuf, 0); return 1; } return 0; } void gnyoserv() { int done=0, readable, c, rfd, i; fd_set fds; char buffer[BUFLEN], tmpbuf[BUFLEN], *p; static struct sockaddr_in cliaddr; int cliaddrlen = sizeof(cliaddr); #define SAD struct sockaddr while (!done) { FD_ZERO(&fds); FD_SET(sofd, &fds); for (i=0; i<MAXCL; i++) FD_SET(clisofd[i], &fds); readable = select(32, &fds, 0, 0, 0); /* accept a new client */ if (FD_ISSET(sofd, &fds)) { for (i=0; i<MAXCL && clisofd[i]; i++); if ((clisofd[i] = accept(sofd, (SAD*)&cliaddr, &cliaddrlen)) < 0) error("Couldn't accept"); if (i==MAXCL) { sprintf(buffer, "There are over %d users. Connect later.\n", MAXCL); sendstr(clisofd[i], buffer, 0); shutdown(clisofd[i], 2); close(clisofd[i]); } else { struct hostent *host; sprintf(buffer, "Welcome to gnyoserver. Your id is %d.\n", i); sendstr(clisofd[i], buffer, 0); host = gethostbyaddr((char*)&cliaddr.sin_addr, sizeof(cliaddr.sin_addr), AF_INET); #ifdef DEBUG fprintf(stderr, "Connection from %s\n", host->h_name); #endif sprintf(buffer, "%s", host->h_name); clinames[i] = savestr(buffer); clients++; } readable--; } for (c=0; readable>0 && c<MAXCL; readable--) { while (c<MAXCL && !FD_ISSET(clisofd[c], &fds)) c++; rfd = clisofd[c]; /* is the desc. of sender */ memset(buffer, '\0', BUFLEN); if (recv(rfd, buffer, BUFLEN, 0) < 0) error("Receive failed"); if (buffer[0] == '.') { sprintf(buffer, "Bye bye!\n"); done = 1; rfd = 0; } #ifdef WRITE for (i=0; i<MAXCL; i++) { if (clisofd[i]!=rfd) send(clisofd[i], buffer, strlen(buffer), 0); } if ((p=strchr(buffer, '\r'))) /* chop */ *p = '\0'; if ((p=strchr(buffer, '\n'))) *p = '\0'; #else p = buffer; while (*p) { /* 一行ごとにちぎって処理 */ register int len; if (strpbrk(p, "\r\n")) { len = (1+(char*)strpbrk(p, "\n") - p); } else { len = strlen(p); } strncpy(tmpbuf, p, len); p += len; tmpbuf[len] = '\0'; switch (gnyoquery(c, rfd, tmpbuf)) { case 1: shutdown(rfd, 2); close(rfd, 2); clisofd[c] = 0; if (clinames[c]) free(clinames[c]); if (--clients == 0) done=1; break; case 99: done = 1; } } #endif /* WRITE */ } } } void trap() { int i; for (i=0; i<MAXCL; i++) { shutdown(clisofd[i], 2); close(clisofd[i]); } shutdown(sofd, 2); close(sofd); fputs("Terminated by user\n", stderr); exit(0); } main(int argc, char* argv[]) { char hostname[MAXHOSTNAMELEN]; static struct hostent *host; static struct sockaddr_in servaddr; int pid, clients=0, port=GNYOPORT; fd_set readfds; sofd = socket(AF_INET, SOCK_STREAM, 0); if (sofd < 0) error("Failed to open socket"); if (gethostname(hostname, MAXHOSTNAMELEN) < 0) error("Couldn't get hostname"); if (0 == (host = gethostbyname(hostname))) error("Couldn't get host id"); if (argc>1 && strpbrk(argv[1], "0123456789")) { port = atoi(argv[1]); fprintf(stderr, "Port number set to %d\n", port); } memset((char*)&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = INADDR_ANY; servaddr.sin_port = htons(port); memcpy((char*)&servaddr.sin_addr, (char*)host->h_addr, host->h_length); if (bind(sofd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) error("Failed to bind"); if (listen(sofd, 5) == -1) error("Failed to listen"); /* connection request */ signal(SIGINT, trap); /* begin communication */ FD_ZERO(&readfds); FD_SET(sofd, &readfds); gnyoserv(); fputs("Session ended\n", stderr); for (clients=0; clients<MAXCL; clients++) { shutdown(clisofd[clients], 2); close(clisofd[clients]); } shutdown(sofd, 2); close(sofd); exit(0); }