📄 tftplib.c
字号:
errno = ESPIPE; return (-1); } tfp->foffs = noffs; } return (tfp->foffs);}static inttftpioctl (fd, op, argp) int fd; int op; void *argp;{ errno = ENOTTY; return -1;}static inttftpclose (fd) int fd;{ NetFile *nfp; struct tftpfile *tfp; struct tftphdr *tp; nfp = (NetFile *)_file[fd].data; tfp = (struct tftpfile *)nfp->data; tp = (struct tftphdr *) tfp->buf; if ((tfp->flags & O_ACCMODE) == O_WRONLY) { int n = 0; /* flush last block */ tftpnxtblk (tfp); tp->th_opcode = htons((u_short)DATA); tp->th_block = htons((u_short)tfp->block); n = tftpwrq (tfp, tp, tfp->end); if (n >= 0 && tfp->end == SEGSIZE) { /* last block == SEGSIZE, so send empty one to terminate */ tftpnxtblk (tfp); tp->th_opcode = htons((u_short)DATA); tp->th_block = htons((u_short)tfp->block); (void) tftpwrq (tfp, tp, 0); } } else { if (tfp->foffs < tfp->end || !tfp->eof) { const char *msg; int length; /* didn't reach eof, so send a nak to terminate */ tp->th_opcode = htons((u_short)ERROR); tp->th_code = htons((u_short)EUNDEF); msg = "file closed"; strcpy(tp->th_msg, msg); length = strlen(msg) + 4;#ifdef TFTPDBG if (tftptrace) tpacket("sent", tp, length);#endif if (sendto(tfp->sock, tp, length, 0, (struct sockaddr *)&tfp->sin, sizeof (tfp->sin)) != length) perror("sendto(eof)"); } } close (tfp->sock); free (tfp); return (0);}static voidtftpnxtblk (tfp) struct tftpfile *tfp;{ tfp->block++; if (tfp->flags & O_NONBLOCK) dotik (20000, 0);}static int tftprrq (tfp, req, size) struct tftpfile *tfp; struct tftphdr *req; int size;{ struct tftphdr *rp; struct sockaddr_in from; fd_set ifds; int fromlen, n; struct timeval timo; int rexmt = 0; while (1) {#ifdef TFTPDBG if (tftptrace) tpacket("sent", req, size);#endif if (sendto(tfp->sock, req, size, 0, (struct sockaddr *)&tfp->sin, sizeof (tfp->sin)) != size) { perror("tftp: sendto"); return (-1); } if (tfp->eof) /* reached eof, no more to read */ return 0; FD_ZERO(&ifds); FD_SET(tfp->sock, &ifds); timo.tv_sec = TIMEOUT; timo.tv_usec = 0; switch (select (tfp->sock + 1, &ifds, 0, 0, &timo)) { case -1: perror("tftp: select"); return (-1); case 0: if (++rexmt > MAXREXMT) { errno = ETIMEDOUT; return (-1); } log (LOG_INFO, "tftp: timeout, retry %d\n", rexmt); continue; } fromlen = sizeof (from); rp = (struct tftphdr *) tfp->buf; n = recvfrom(tfp->sock, rp, PKTSIZE, 0, (struct sockaddr *)&from, &fromlen); if (n < 0) { perror("tftp: recvfrom"); return (-1); }#ifdef TFTPDBG if (tftptrace) tpacket("received", rp, n);#endif if (tfp->block <= 1) tfp->sin.sin_port = from.sin_port; else if (from.sin_port != tfp->sin.sin_port) continue; /* should verify client address completely? */ rp->th_opcode = ntohs(rp->th_opcode); rp->th_block = ntohs(rp->th_block); if (rp->th_opcode == ERROR) { if (rp->th_msg[0]) log(LOG_INFO, "tftp: %s\n", rp->th_msg); errno = tftperrmap[rp->th_code & 7]; return (-1); } if (rp->th_opcode == DATA) { int j; if (rp->th_block == tfp->block) { /* got the packet */ n -= 4; if (n < SEGSIZE) tfp->eof = 1; return (n); } /* On an error, try to synchronize * both sides. */ j = synchnet(tfp->sock); if (j) log (LOG_INFO, "tftp: discarded %d packets\n", j); if (rp->th_block != tfp->block - 1) return (-1); } }}static int tftpwrq (tfp, req, size) struct tftpfile *tfp;struct tftphdr *req;int size;{ char ackbuf[PKTSIZE]; struct tftphdr *rp; struct sockaddr_in from; fd_set ifds; int fromlen, n; struct timeval timo; int rexmt = 0; while (1) {#ifdef TFTPDBG if (tftptrace) tpacket("sent", req, size);#endif if (sendto(tfp->sock, req, size+4, 0, (struct sockaddr *)&tfp->sin, sizeof (tfp->sin)) != size+4) { perror("tftp: sendto"); return (-1); } FD_ZERO(&ifds); FD_SET(tfp->sock, &ifds); timo.tv_sec = TIMEOUT; timo.tv_usec = 0; switch (select (tfp->sock + 1, &ifds, 0, 0, &timo)) { case -1: perror("tftp: select"); return (-1); case 0: if (++rexmt > MAXREXMT) { errno = ETIMEDOUT; return (-1); } log (LOG_INFO, "tftp: timeout, retry %d\n", rexmt); continue; } fromlen = sizeof (from); rp = (struct tftphdr *) ackbuf; n = recvfrom(tfp->sock, rp, PKTSIZE, 0, (struct sockaddr *)&from, &fromlen); if (n < 0) { perror("tftp: recvfrom"); return (-1); }#ifdef TFTPDBG if (tftptrace) tpacket("received", rp, n);#endif if (tfp->block == 0) tfp->sin.sin_port = from.sin_port; else if (from.sin_port != tfp->sin.sin_port) continue; /* should verify client address completely? */ rp->th_opcode = ntohs(rp->th_opcode); rp->th_block = ntohs(rp->th_block); if (rp->th_opcode == ERROR) { if (rp->th_msg[0]) log(LOG_INFO, "tftp: %s\n", rp->th_msg); errno = tftperrmap[rp->th_code & 7]; return (-1); } if (rp->th_opcode == ACK) { int j; if (rp->th_block == tfp->block) /* acknowledged packet */ return (size); /* On an error, try to synchronize * both sides. */ j = synchnet(tfp->sock); if (j) log (LOG_INFO, "tftp: discarded %d packets\n", j); if (rp->th_block != tfp->block - 1) return (-1); } }}static int makerequest(request, name, tp, mode) int request;const char *name, *mode;struct tftphdr *tp;{ register char *cp; tp->th_opcode = htons((u_short)request); cp = tp->th_stuff; strcpy(cp, name); cp += strlen(name); *cp++ = '\0'; strcpy(cp, mode); cp += strlen(mode); *cp++ = '\0'; return (cp - (char *)tp);}#ifdef TFTPDBGstatic void tpacket(s, tp, n) char *s;struct tftphdr *tp;int n;{ static const char * const opcodes[] = { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; register char *cp, *file; u_short op = ntohs(tp->th_opcode); if (op < RRQ || op > ERROR) printf("%s opcode=%x ", s, op); else printf("%s %s ", s, opcodes[op]); switch (op) { case RRQ: case WRQ: n -= 2; file = cp = tp->th_stuff; cp += strlen(cp); printf("<file=%s, mode=%s>\n", file, cp + 1); break; case DATA: printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); break; case ACK: printf("<block=%d>\n", ntohs(tp->th_block)); break; case ERROR: printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); break; }}#endif/* When an error has occurred, it is possible that the two sides * are out of synch. Ie: that what I think is the other side's * response to packet N is really their response to packet N-1. * * So, to try to prevent that, we flush all the input queued up * for us on the network connection on our host. * * We return the number of packets we flushed (mostly for reporting * when trace is active). */static int synchnet(f) int f; /* socket to flush */{ int i, j = 0; char rbuf[PKTSIZE]; struct sockaddr_in from; int fromlen; while (1) { (void) ioctl(f, FIONREAD, &i); if (i) { j++; fromlen = sizeof from; (void) recvfrom(f, rbuf, sizeof (rbuf), 0, (struct sockaddr *)&from, &fromlen); } else { return(j); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -