/* * u-ping.c -- UDP通信でメッセージを送信・受信するクライアント * * 0.0: Dec. 14, 2021 by Dai ISHIJIMA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define EOS '\0' #define NDUMP 16 #define PORT 43210 #define TIMEOUT 5 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); perrno(); 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 udping(int d, unsigned long a, unsigned short p, int len, char *msg, int sec) { struct sockaddr_in saddr; struct in_addr in; int slen; char rbuf[BUFSIZ]; /* 宛先に (IPv4 addr:port = a:p) */ in.s_addr = (in_addr_t)a; saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = in.s_addr; saddr.sin_port = htons(p); /* メッセージを送る */ if (sendto(d, msg, len, 0, (struct sockaddr *)&saddr, sizeof(saddr)) != len) { /* 送れなかった */ fprintf(stderr, "%s: ", prog); fprintf(stderr, "can't sendto() %d <- %s:%d\n", d, inet_ntoa(saddr.sin_addr), p); perrno(); exit(1); } if (sec > 0) { /* 待ち時間指定があれば待つ */ waitfor(d, sec); } /* メッセージを受ける */ slen = sizeof(saddr); if ((len = recvfrom(d, rbuf, BUFSIZ - 1, 0, (struct sockaddr *)&saddr, (socklen_t *)&slen)) < 0) { /* 来なかった */ fprintf(stderr, "%s: empty message from ", prog); fprintf(stderr, "%d <- %s:%d\n", d, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); perrno(); exit(1); } if (saddr.sin_addr.s_addr != in.s_addr) { /* 想定外の返信 */ fprintf(stderr, "%s: unknown packet from %s != ", prog, inet_ntoa(saddr.sin_addr)); fprintf(stderr, "%s, len = %d\n", inet_ntoa(in), len); dump(stderr, len, rbuf); exit(1); } /* 想定した返信を表示 */ rbuf[len] = EOS; fwrite(rbuf, 1, len, stdout); } /* ソケットを初期化してディスクリプタ (記述子) を返す */ int initsocket(unsigned long a, unsigned short p) { int d; struct sockaddr_in caddr; /* UDP用のディスクリプタ (エンドポイント) を得る */ if ((d = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { fprintf(stderr, "%s: can't open socket\n", prog); perrno(); exit(1); } /* 自分のIPv4アドレスとポート */ caddr.sin_family = AF_INET; caddr.sin_addr.s_addr = a; caddr.sin_port = htons(p); /* ディスクリプタに紐付け */ if (bind(d, (struct sockaddr *)&caddr, sizeof(caddr)) != 0) { fprintf(stderr, "%s: can't bind socket, %d <- %s:%d\n", prog, d, inet_ntoa(caddr.sin_addr), p); perrno(); exit(1); } return(d); } /* UDPクライアント */ void uclient(unsigned long a, int p, unsigned long ha, int hp, int len, char *msg, int sec) { int d; d = initsocket(a, p); udping(d, ha, hp, len, msg, sec); close(d); } /* ファイルあるいは標準入力 (-) から (送出用) メッセージを読む */ int getmsg(char *file, char *msg) { FILE *fp; int len; if ((file[0] == '-') && (file[1] == EOS)) { len = fread(msg, 1, BUFSIZ - 1, stdin); } else { if ((fp = fopen(file, "r")) == NULL) { fprintf(stderr, "%s: can't open %s\n", prog, file); exit(1); } len = fread(msg, 1, BUFSIZ - 1, fp); fclose(fp); } if (len <= 0) { fprintf(stderr, "%s: input message length == 0\n", prog); exit(1); } msg[len] = EOS; return(len); } void usage() { fprintf(stderr, "Usage: %s ", prog); fprintf(stderr, "[-p #] [-a #.#.#.#] [-m message] -|file host [port]\n"); fprintf(stderr, " \t-p \n"); fprintf(stderr, " \t-a \n"); fprintf(stderr, " \t-t