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