📄 tftpd.c
字号:
char buf[TFTPHDRSIZE + SEGSIZE]; struct tftphdr *send_tftp = (struct tftphdr *)buf; char *ptr = send_tftp->th_msg; int retry; /* Deal with partial reads, and reblock in units of 512 bytes. */ count = 0; while (!ioerr && count < SEGSIZE) { int rc = read(src, ptr + count, SEGSIZE - count); if (rc < 0) { if (errno == EINTR) continue; ioerr = errno; break; } else if (rc == 0) { break; } count += rc; } /* Report any read errors back to the client. */ if (count == 0 && ioerr) { err = ENOTFOUND; *msg_buf = '\000'; msg = strerror_r(ioerr, msg_buf, sizeof(msg_buf)); goto error; } send_tftp->th_opcode = htons(DATA); send_tftp->th_block = htons(++block); /* Transmit a single packet. Retry if necessary. */ retry = 10; for (;;) { int rc; /* Terminate entire transfers after too many retries. */ if (--retry < 0) goto done; /* Send one 512 byte packet. */ DBG("send DATA <block=%d, 512 bytes>\n", block); if (sendto(fd, send_tftp, TFTPHDRSIZE + count, 0, (struct sockaddr *)&request->addr, request->len) < 0) { if (errno == EINTR) continue; goto done; } /* Wait for response from client. */ do { fd_set in_fds; struct timeval timeout; FD_ZERO(&in_fds); FD_SET(fd, &in_fds); timeout.tv_sec = 5; timeout.tv_usec = 0; rc = select(fd+1, &in_fds, NULL, NULL, &timeout); } while (rc < 0 && errno == EINTR); /* If no response received, try sending payload again. */ if (rc == 0) continue; /* Receive actual response. */ rc = recv(fd, tftp, TFTPHDRSIZE + SEGSIZE, MSG_TRUNC); /* If operation failed, terminate entire transfer. */ if (rc < 0) { if (errno == EINTR) continue; goto done; } /* Done transmitting this block, after receiving matching ACK */ if (rc >= TFTPHDRSIZE) { switch (ntohs(tftp->th_opcode)) { case ACK: DBG("received ACK <block=%d>\n", ntohs(tftp->th_block)); break; case RRQ: DBG("received RRQ\n"); break; case WRQ: DBG("received WRQ\n"); break; case DATA: DBG("received DATA\n"); break; case ERROR: DBG("received ERROR\n"); break; default: DBG("unexpected data, op=%d\n", ntohs(tftp->th_opcode)); break; } } if (rc >= TFTPHDRSIZE && ntohs(tftp->th_opcode) == ACK && tftp->th_block == send_tftp->th_block) break; } } while (count); #endif } else { #ifdef CAN_WRITE_FILES /* TODO: Add support for writing files */ #endif } done: /* Clean up, close all file handles, and release memory */ if (fd >= 0) close(fd); if (src >= 0) close(src); if (file_name) free(file_name); free(request); return 0;#undef debug}/* This is a very basic TFTP server implementing RFC 1350, but none of the * optional protocol extensions (e.g. no block size negotiation, and no * multicasting). */int main(int argc, char *argv[]) { static const struct option long_opts[] = { /* Set file name for "core" snapshot file of running process. */ { "core", 1, NULL, 'c' }, /* Enable debugging output. */ { "debug", 0, NULL, 'd' }, /* Print usage information for this server. */ { "help", 0, NULL, 'h' }, /* Suppress negative acknowledge for non-existant files. */ { "noack", 0, NULL, 'n' }, /* Set port number to listen on. */ { "port", 1, NULL, 'p' }, /* Sanitize requests for absolute filenames by prepending the name of the * first directory specified on the command line. If no directory is * given, prepend "/tftpboot/". */ { "sanitize", 0, NULL, 's' }, { NULL, 0, NULL, 0 } }; static const char *opt_string = "c:dhnp:s"; const char *core_name = "core"; int debug = 0; int no_ack = 0; int port = -1; int sanitize = 0; char **dirs = NULL; int server_fd = 0; int id = 0; /* Parse command line options. */ for (;;) { int idx = 0; int c = getopt_long(argc, argv, opt_string, long_opts, &idx); if (c == -1) break; switch (c) { case 'c': core_name = optarg; break; case 'd': debug = 1; break; case 'n': no_ack = 1; break; case 'p': port = atoi(optarg); if (port <= 0 || port > 65535) { fprintf(stderr, "Port out of range: %d\n", port); exit(1); } break; case 's': sanitize = 1; break; case 'h': default: fprintf(stderr, "Usage: %s --core <name> --debug --help --port <port> --noack " "--sanitize\n", argv[0]); exit(c != 'h'); } } /* All remaining command line arguments (if any) list the directories of * files that this server can access. If no directories are given, then * only files in "/tftpboot/..." are accessible. */ dirs = argv + optind; /* If a port is given on the command line, then listen on. Otherwise, * assume that stdin is already connected to a server port. This allows * us to run the server from inetd. */ if (port >= 0) { struct sockaddr_in addr; server_fd = socket(PF_INET, SOCK_DGRAM, 0); if (server_fd < 0) { perror("socket"); exit(1); } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; if (bind(server_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) <0){ perror("bind"); exit(1); } } /* Server mainloop. Accept incoming connections and spawn threads to * serve the requests. */ for (;;) { const char *msg; char buf[TFTPHDRSIZE + SEGSIZE]; struct tftphdr *tftp = (struct tftphdr *)buf; struct sockaddr_in addr; socklen_t len; int count, type; Request *request; #ifndef NO_THREADS pthread_t thread; #endif /* Receive next request. */ len = sizeof(addr); count = recvfrom(server_fd, tftp, sizeof(buf), MSG_TRUNC, (struct sockaddr *)&addr, &len); if (count < 0) { if (errno == EINTR) continue; perror("recvfrom"); exit(1); } /* If request arrived from unsupported address, just ignore it. */ if (len < sizeof(struct sockaddr_in)) continue; /* If request was truncated, report error back to client. */ if (count < sizeof(tftp)) { char *ptr; msg = "Truncated request"; send_error: /* Send error message to client. */ DBG("%s\n", msg); ptr = strrchr(strcpy(tftp->th_msg, msg), '\000') + 1; tftp->th_opcode = htons(ERROR); tftp->th_code = htons(EBADOP); sendto(server_fd, tftp, ptr-buf, 0, (struct sockaddr *)&addr, len); continue; } /* Determine whether this was a read or write request. */ type = ntohs(tftp->th_opcode); if (type != RRQ && type != WRQ) { msg = "Request must be RRQ or WRQ"; goto send_error; } /* Build "Request" data structure with parameters describing connection. */ request = calloc(sizeof(Request), 1); request->debug = debug; request->id = id++; request->fd = server_fd; request->tftp = (struct tftphdr *)&request->buf; request->count = count; request->len = len; request->core_name = core_name; request->dirs = dirs; request->no_ack = no_ack; request->sanitize = sanitize; memcpy(&request->buf, buf, count); memcpy(&request->addr, &addr, len); /* Hand request off to its own thread. */ #ifdef NO_THREADS tftp_thread(request); #else pthread_create(&thread, NULL, tftp_thread, request); #endif }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -