1 #ifndef lint 2 static char sccsid[] = "@(#)tftp.c 4.7 (Berkeley) 08/11/83"; 3 #endif 4 5 /* 6 * TFTP User Program -- Protocol Machines 7 */ 8 #include <sys/types.h> 9 #include <sys/socket.h> 10 11 #include <netinet/in.h> 12 13 #include <arpa/tftp.h> 14 15 #include <signal.h> 16 #include <stdio.h> 17 #include <errno.h> 18 #include <setjmp.h> 19 20 extern int errno; 21 extern struct sockaddr_in sin; 22 extern char mode[]; 23 int f; 24 int trace; 25 int verbose; 26 int connected; 27 char buf[BUFSIZ]; 28 int rexmtval; 29 int maxtimeout; 30 int timeout; 31 jmp_buf toplevel; 32 jmp_buf timeoutbuf; 33 34 timer() 35 { 36 37 timeout += rexmtval; 38 if (timeout >= maxtimeout) { 39 printf("Transfer timed out.\n"); 40 longjmp(toplevel, -1); 41 } 42 longjmp(timeoutbuf, 1); 43 } 44 45 /* 46 * Send the requested file. 47 */ 48 sendfile(fd, name) 49 int fd; 50 char *name; 51 { 52 register struct tftphdr *tp = (struct tftphdr *)buf; 53 register int block = 0, size, n, amount = 0; 54 struct sockaddr_in from; 55 time_t start = time(0), delta; 56 int fromlen; 57 58 signal(SIGALRM, timer); 59 do { 60 if (block == 0) 61 size = makerequest(WRQ, name) - 4; 62 else { 63 size = read(fd, tp->th_data, SEGSIZE); 64 if (size < 0) { 65 nak(errno + 100); 66 break; 67 } 68 tp->th_opcode = htons((u_short)DATA); 69 tp->th_block = htons((u_short)block); 70 } 71 timeout = 0; 72 (void) setjmp(timeoutbuf); 73 if (trace) 74 tpacket("sent", tp, size + 4); 75 n = sendto(f, buf, size + 4, 0, (caddr_t)&sin, sizeof (sin)); 76 if (n != size + 4) { 77 perror("tftp: sendto"); 78 goto abort; 79 } 80 do { 81 alarm(rexmtval); 82 do { 83 fromlen = sizeof (from); 84 n = recvfrom(f, buf, sizeof (buf), 0, 85 (caddr_t)&from, &fromlen); 86 } while (n <= 0); 87 alarm(0); 88 if (n < 0) { 89 perror("tftp: recvfrom"); 90 goto abort; 91 } 92 if (trace) 93 tpacket("received", tp, n); 94 /* should verify packet came from server */ 95 tp->th_opcode = ntohs(tp->th_opcode); 96 tp->th_block = ntohs(tp->th_block); 97 if (tp->th_opcode == ERROR) { 98 printf("Error code %d: %s\n", tp->th_code, 99 tp->th_msg); 100 goto abort; 101 } 102 } while (tp->th_opcode != ACK && block != tp->th_block); 103 if (block > 0) 104 amount += size; 105 block++; 106 } while (size == SEGSIZE || block == 1); 107 abort: 108 (void) close(fd); 109 if (amount > 0) { 110 delta = time(0) - start; 111 printf("Sent %d bytes in %d seconds.\n", amount, delta); 112 } 113 } 114 115 /* 116 * Receive a file. 117 */ 118 recvfile(fd, name) 119 int fd; 120 char *name; 121 { 122 register struct tftphdr *tp = (struct tftphdr *)buf; 123 register int block = 1, n, size, amount = 0; 124 struct sockaddr_in from; 125 time_t start = time(0), delta; 126 int fromlen, firsttrip = 1; 127 128 signal(SIGALRM, timer); 129 do { 130 if (firsttrip) { 131 size = makerequest(RRQ, name); 132 firsttrip = 0; 133 } else { 134 tp->th_opcode = htons((u_short)ACK); 135 tp->th_block = htons((u_short)(block)); 136 size = 4; 137 block++; 138 } 139 timeout = 0; 140 (void) setjmp(timeoutbuf); 141 if (trace) 142 tpacket("sent", tp, size); 143 if (sendto(f, buf, size, 0, (caddr_t)&sin, 144 sizeof (sin)) != size) { 145 alarm(0); 146 perror("tftp: sendto"); 147 goto abort; 148 } 149 do { 150 alarm(rexmtval); 151 do 152 n = recvfrom(f, buf, sizeof (buf), 0, 153 (caddr_t)&from, &fromlen); 154 while (n <= 0); 155 alarm(0); 156 if (n < 0) { 157 perror("tftp: recvfrom"); 158 goto abort; 159 } 160 if (trace) 161 tpacket("received", tp, n); 162 /* should verify client address */ 163 tp->th_opcode = ntohs(tp->th_opcode); 164 tp->th_block = ntohs(tp->th_block); 165 if (tp->th_opcode == ERROR) { 166 printf("Error code %d: %s\n", tp->th_code, 167 tp->th_msg); 168 goto abort; 169 } 170 } while (tp->th_opcode != DATA && block != tp->th_block); 171 size = write(fd, tp->th_data, n - 4); 172 if (size < 0) { 173 nak(errno + 100); 174 break; 175 } 176 amount += size; 177 } while (size == SEGSIZE); 178 abort: 179 tp->th_opcode = htons((u_short)ACK); 180 tp->th_block = htons((u_short)block); 181 (void) sendto(f, buf, 4, 0, &sin, sizeof (sin)); 182 (void) close(fd); 183 if (amount > 0) { 184 delta = time(0) - start; 185 printf("Received %d bytes in %d seconds.\n", amount, delta); 186 } 187 } 188 189 makerequest(request, name) 190 int request; 191 char *name; 192 { 193 register struct tftphdr *tp; 194 int size; 195 register char *cp; 196 197 tp = (struct tftphdr *)buf; 198 tp->th_opcode = htons((u_short)request); 199 strcpy(tp->th_stuff, name); 200 size = strlen(name); 201 cp = tp->th_stuff + strlen(name); 202 *cp++ = '\0'; 203 strcpy(cp, mode); 204 cp += sizeof ("netascii") - 1; 205 *cp++ = '\0'; 206 return (cp - buf); 207 } 208 209 struct errmsg { 210 int e_code; 211 char *e_msg; 212 } errmsgs[] = { 213 { EUNDEF, "Undefined error code" }, 214 { ENOTFOUND, "File not found" }, 215 { EACCESS, "Access violation" }, 216 { ENOSPACE, "Disk full or allocation exceeded" }, 217 { EBADOP, "Illegal TFTP operation" }, 218 { EBADID, "Unknown transfer ID" }, 219 { EEXISTS, "File already exists" }, 220 { ENOUSER, "No such user" }, 221 { -1, 0 } 222 }; 223 224 /* 225 * Send a nak packet (error message). 226 * Error code passed in is one of the 227 * standard TFTP codes, or a UNIX errno 228 * offset by 100. 229 */ 230 nak(error) 231 int error; 232 { 233 register struct tftphdr *tp; 234 int length; 235 register struct errmsg *pe; 236 extern char *sys_errlist[]; 237 238 tp = (struct tftphdr *)buf; 239 tp->th_opcode = htons((u_short)ERROR); 240 tp->th_code = htons((u_short)error); 241 for (pe = errmsgs; pe->e_code >= 0; pe++) 242 if (pe->e_code == error) 243 break; 244 if (pe->e_code < 0) 245 pe->e_msg = sys_errlist[error - 100]; 246 strcpy(tp->th_msg, pe->e_msg); 247 length = strlen(pe->e_msg) + 4; 248 if (trace) 249 tpacket("sent", tp, length); 250 if (send(f, &sin, buf, length) != length) 251 perror("nak"); 252 } 253 254 tpacket(s, tp, n) 255 struct tftphdr *tp; 256 int n; 257 { 258 static char *opcodes[] = 259 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; 260 register char *cp, *file; 261 u_short op = ntohs(tp->th_opcode); 262 char *index(); 263 264 if (op < RRQ || op > ERROR) 265 printf("%s opcode=%x ", s, op); 266 else 267 printf("%s %s ", s, opcodes[op]); 268 switch (op) { 269 270 case RRQ: 271 case WRQ: 272 n -= 2; 273 file = cp = tp->th_stuff; 274 cp = index(cp, '\0'); 275 printf("<file=%s, mode=%s>\n", file, cp + 1); 276 break; 277 278 case DATA: 279 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 280 break; 281 282 case ACK: 283 printf("<block=%d>\n", ntohs(tp->th_block)); 284 break; 285 286 case ERROR: 287 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 288 break; 289 } 290 } 291