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