📄 udpechoserverdemo.c
字号:
/* udp echo server demo */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>#include "tftpc.h"static inline char conv_char(char ch){ ch = ch & 0xff; if((ch < 0x20) || ((unsigned char)ch > 0x7f)) return '.'; return ch;}void dump_mem(const char *tip, void *base, int size){ unsigned char *p = base; int rows = size / 16; int rest = size % 16; int i, j; printf("[%s len = %d]\n", tip, size); for(i = 0; i < rows; i++) { printf("0x%p:", p); for(j = 0; j < 16; j++) printf("%02X ", p[j]); printf("|"); for(j = 0; j < 16; j++) printf("%c", conv_char(*p++)); printf("\n"); } printf("0x%p:", p); for(j = 0; j < rest; j++) printf("%02X ", p[j]); for(;j < 16; j++) printf(" "); printf("|"); for(j = 0; j < rest; j++) printf("%c", conv_char(p[j])); printf("\n");}size_t read_with_select(int fd, void *buffer, size_t size, int flags, struct sockaddr *addr, socklen_t *addrlen, int tout){ #include <sys/time.h> fd_set rd_fds; struct timeval timeout; timeout.tv_sec = tout; timeout.tv_usec = 0; FD_ZERO(&rd_fds); FD_SET(fd,&rd_fds); if(select(fd + 1, &rd_fds, NULL, NULL, &timeout) > 0) { return recvfrom(fd, buffer, size, flags, addr, addrlen); } return -1;}size_t send_to(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t addrlen){ dump_mem("SEND", buf, len); return sendto(sockfd, buf, len, flags, addr, addrlen);}size_t recv_from(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen, int tout){ if(tout == 0) tout = 20; *addrlen = sizeof(struct sockaddr); len = read_with_select(sockfd, buf, len, flags, addr, addrlen, tout); dump_mem("RECV", buf, len); return len;}int make_req(char *outbuf, int rw, char *filename, int blksize, int timeout){ char *p = &outbuf[2]; outbuf[0] = 0x00; outbuf[1] = rw; strcpy(p, filename); p += (strlen(filename) + 1); strcpy(p, "octet"); p += (strlen("octet") + 1); //-----------------------------------> strcpy(p, "tsize"); p += (strlen("tsize") + 1); strcpy(p, "0"); p += (strlen("0") + 1); //<----------------------------------- //-----------------------------------> if((blksize >= 8) && (blksize <= 65464)) { strcpy(p, "blksize"); p += (strlen("blksize") + 1); sprintf(p, "%d", blksize); p += (strlen(p) + 1); } //<----------------------------------- //-----------------------------------> if(timeout > 0) { strcpy(p, "timeout"); p += (strlen("timeout") + 1); sprintf(p, "%d", timeout); p += (strlen(p) + 1); } //<----------------------------------- return (int)p - (int)outbuf;}int parse_oack(char *oack, int len, int *tsize, int *blksize, int *timeout){ char *p = oack + 2; len -= 2; /* Reset to default value*/ *tsize = -1; *blksize = 512; *timeout = 2; while(len > 0) { switch(p[1]) { case 's': // tsize if(strcmp(p, "tsize") == 0) { len -= 6; p += 6; *tsize = atoi(p); len -= (strlen(p) + 1); p += (strlen(p) + 1); } else return -1; break; case 'l': // blksize if(strcmp(p, "blksize") == 0) { len -= 8; p += 8; *blksize = atoi(p); len -= (strlen(p) + 1); p += (strlen(p) + 1); } else return -1; break; case 'i': // timeout if(strcmp(p, "timeout") == 0) { len -= 8; p += 8; *timeout = atoi(p); len -= (strlen(p) + 1); p += (strlen(p) + 1); } else return -1; break; default: return -1; break; } } return 0;}int make_ack(char *outbuf, char *package, int *blknumber){ switch(package[1]) { case TFTP_OPC_DATA: memcpy(outbuf, package, 4); outbuf[1] = TFTP_OPC_ACK; *blknumber = ntohs(*((unsigned short*)&package[2])); break; case TFTP_OPC_OACK: memset(outbuf, 0, 4); outbuf[1] = TFTP_OPC_ACK; *blknumber = 0; break; case TFTP_OPC_ERROR: break; } return package[1];}int send_req(int sockfd, char *ip, unsigned short port, int rw, char *filename, int blksize, int timeout){ unsigned char buffer[512]; struct sockaddr_in srvAddr; socklen_t len; bzero(&srvAddr, sizeof(srvAddr)); srvAddr.sin_family = AF_INET; srvAddr.sin_port = htons(port); inet_pton(AF_INET, ip, &srvAddr.sin_addr.s_addr); len = make_req(buffer, rw, filename, blksize, timeout); if(send_to(sockfd, buffer, len, 0, (struct sockaddr*)&srvAddr, sizeof(srvAddr)) < 0) { close(sockfd); perror("send faild! maybe the server is down!"); exit(1); } return 0;}int send_err(int sockfd, int errno, struct sockaddr_in *srvAddr){ unsigned char errmsg[100]; errmsg[0] = 0x00; errmsg[1] = TFTP_OPC_ERROR; errmsg[2] = 0x00; errmsg[3] = errno; strcpy(&errmsg[4], errlist[errno].errmsg); return send_to(sockfd, errmsg, strlen(errlist[errno].errmsg) + 5, 0, (struct sockaddr*)srvAddr, sizeof(srvAddr));}void usage(const char *tip){ printf("%s", tip); printf( "Usage:\n" \ " tftpc ip file [/p:port] [/b:blksize] [/t:timeout]\n" \ );}void parse_param(int argc, char *argv[], unsigned short *port, int *timeout, int *blksize){ int port_is_set = 0; int tsize_is_set = 0; int blksize_is_set = 0; if(argc < 3) { usage("argument err!\n"); exit(1); } while(argc > 3) { argc--; if(argv[argc][0] != '/') { usage("argument err!\n"); exit(1); } switch(argv[argc][1]) { case 't': if(tsize_is_set) { usage("invalid timeout value!\n"); exit(1); } tsize_is_set = 1; *timeout = atoi(&argv[argc][3]); break; case 'b': if(blksize_is_set) { usage("invalid block size!\n"); exit(1); } blksize_is_set = 1; *blksize = atoi(&argv[argc][3]); break; case 'p': if(port_is_set) { usage("invalid port number!\n"); exit(1); } port_is_set = 1; *port = atoi(&argv[argc][3]); break; default: usage("unknown argument!\n"); exit(1); break; } }}int main(int argc, char *argv[]){ int sockfd; char *srvIP = argv[1]; unsigned short port = 69; char *filename = argv[2]; int tsize = 0; int blksize = 512; int timeout = 3; unsigned char recvBuf[2048]; int blknumber = 0; int start_data_transfer = 0; char ack[4]; int len; parse_param(argc, argv, &port, &timeout, &blksize); sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("Invalid socket"); exit(1); } send_req(sockfd, srvIP, port, TFTP_OPC_READ, filename, blksize, timeout); while(1) { struct sockaddr_in srvAddr; socklen_t remoteAddrLen; int blkn; len = recv_from(sockfd, recvBuf, 2048, 0, (struct sockaddr*)&srvAddr, &remoteAddrLen, timeout); if(len <= 0) { static int retry = 0; if(retry > 3) { printf("Retry %d times, give up!\n", retry); exit(1); } printf("block %d timeout, retry(%d)\n", blknumber, retry); if(start_data_transfer) { sendto(sockfd, ack, 4, 0, (struct sockaddr*)&srvAddr, sizeof(srvAddr)); } else { send_req(sockfd, srvIP, port, TFTP_OPC_READ, filename, blksize, timeout); } retry++; continue; } int op_code = make_ack(ack, recvBuf, &blkn); if(op_code == TFTP_OPC_OACK) { start_data_transfer = 1; parse_oack(recvBuf, len, &tsize, &blksize, &timeout); if(send_to(sockfd, ack, 4, 0, (struct sockaddr*)&srvAddr, sizeof(srvAddr)) < 0) { close(sockfd); perror("send faild! maybe the server is down!"); exit(1); } } else if(op_code == TFTP_OPC_DATA) { start_data_transfer = 1; len -= 4; if(++blknumber < blkn) { send_err(sockfd, TFTP_ERRC_UNKNOWNID, &srvAddr); break; } if(send_to(sockfd, ack, 4, 0, (struct sockaddr*)&srvAddr, sizeof(srvAddr)) < 0) { close(sockfd); perror("send faild! maybe the server is down!"); exit(1); } if(tsize > 0) { tsize -= len; } if(tsize == 0) break; if(len < blksize) break; } else if(recvBuf[1] == TFTP_OPC_ERROR) break; } close(sockfd); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -