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