/* * u-pong.c -- UDP通信で受信したメッセージを返すサーバ * * 0.0: Dec. 14, 2021 by Dai ISHIJIMA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define EOS '\0' #define PORT 43210 #define BYE "BYE" #define NDUMP 16 char *prog; #define shift --argc; ++argv /* strerrorを使ってエラー出力 */ void perrno() { fprintf(stderr, "%s: [%d] %s\n", prog, errno, strerror(errno)); } /* 時間切れまで待つ */ int waitfor(int d, int sec) { int nfds; fd_set readfds; struct timeval timeout; fcntl(d, F_SETFL, O_NONBLOCK); FD_ZERO(&readfds); FD_SET(d, &readfds); timeout.tv_sec = sec; timeout.tv_usec = 0; /* 時間切れになるか、入力があるまで待つ (定型文) */ nfds = select(d + 1, &readfds, NULL, NULL, &timeout); if ((nfds < 0) && (errno != EINTR)) { fprintf(stderr, "%s: select failed\n", prog); fprintf(stderr, "%s: %d %s\n", prog, errno, strerror(errno)); exit(1); } if ((nfds > 0) && (FD_ISSET(d, &readfds))) { /* 時間切れ前に入力があった */ return(0); } /* 時間切れ */ fprintf(stderr, "%s: connection timed out\n", prog); exit(1); } /* 16進でデータを表示する */ void dump(FILE *fp, int len, char *buf) { int i, j; for (j = 0; j < len; j += NDUMP) { fprintf(fp, "%04x ", j); for (i = 0; (i < NDUMP) && (i + j < len); i++) { if (i == NDUMP / 2) { fprintf(fp, " "); } fprintf(fp, "%02x ", buf[i + j]); } for (; i < NDUMP; i++) { if (i == NDUMP / 2) { fprintf(fp, " "); } fprintf(fp, " "); } fprintf(fp, " "); for (i = 0; (i < NDUMP) && (i + j < len); i++) { if (i == NDUMP / 2) { fprintf(fp, " "); } if ((' ' <= buf[i + j]) && (buf[i + j] < '~')) { /* isprint(3) 案件 */ fprintf(fp, "%c", buf[i + j]); } else { fprintf(fp, "."); } } fprintf(fp, "\n"); } } /* UDPでメッセージを受信して返送する */ void udpong(int d, char *bye, int sec) { int len; struct sockaddr_in caddr; int clen; char rbuf[BUFSIZ]; char sbuf[BUFSIZ]; struct timeval current; for (;;) { if (sec > 0) { waitfor(d, sec); } clen = sizeof(caddr); /* メッセージを受ける */ if ((len = recvfrom(d, rbuf, BUFSIZ - 1, 0, (struct sockaddr *)&caddr, (socklen_t *)&clen)) < 0) { fprintf(stderr, "%s: no message\n", prog); perrno(); exit(1); } gettimeofday(¤t, NULL); rbuf[len] = EOS; printf("[%s:%d] %d.%06d %s", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), (int)current.tv_sec, (int)current.tv_usec, ctime((time_t *)¤t.tv_sec)); dump(stdin, len, rbuf); sprintf(sbuf, "[%s:%d] %d.%6d, %s", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), (int)current.tv_sec, (int)current.tv_usec, rbuf); len = strlen(sbuf); /* メッセージを返信する */ if (sendto(d, sbuf, len, 0, (struct sockaddr *)&caddr, sizeof(caddr)) != len) { fprintf(stderr, "%s: ", prog); fprintf(stderr, "can't sendto() %d <- %s:%d\n", d, inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port)); perrno(); exit(1); } if (strcmp(bye, rbuf) == 0) { /* おしまいのメッセージならループを抜けて終了 */ break; } } } /* ソケットを初期化してディスクリプタ (記述子) を返す */ int initsocket(unsigned long a, unsigned short p) { int d; struct sockaddr_in saddr; /* UDP用のディスクリプタ (エンドポイント) を得る */ if ((d = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { fprintf(stderr, "%s: can't open socket\n", prog); perrno(); exit(1); } /* 相手 (クライアント) のIPv4アドレスとポート */ saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = a; saddr.sin_port = htons(p); if (bind(d, (struct sockaddr *)&saddr, sizeof(saddr)) != 0) { fprintf(stderr, "%s: can't bind socket, %d <- %s:%d\n", prog, d, inet_ntoa(saddr.sin_addr), p); perrno(); exit(1); } return(d); } /* UDPサーバ */ void userver(unsigned long a, int p, char *bye, int sec) { int d; d = initsocket(a, p); udpong(d, bye, sec); close(d); } void usage() { fprintf(stderr, "Usage: %s [-p #] [-a #.#.#.#] [-e BYE]\n", prog); } int main(int argc, char *argv[]) { int p; int a; char bye[BUFSIZ]; int sec; prog = *argv; shift; strcpy(bye, BYE); p = PORT; a = htonl(INADDR_ANY); sec = 0; while ((argc > 0) && (argv[0][0] == '-')) { if (argv[0][1] == 'p') { shift; p = atoi(*argv); } else if (argv[0][1] == 'a') { shift; a = inet_addr(*argv); } else if (argv[0][1] == 'e') { shift; strcpy(bye, *argv); } else if (argv[0][1] == 't') { shift; sec = atoi(*argv); } else { usage(); exit(1); } shift; } userver(a, p, bye, sec); exit(0); } /* Local Variables: */ /* compile-command:"cc -Wall -o u-pong u-pong.c" */ /* End: */