├── .gitignore ├── checksum.h ├── Makefile ├── header.h ├── Readme.md ├── checksum.c ├── header.c ├── server.c └── client.c /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | recvfile.txt 3 | -------------------------------------------------------------------------------- /checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef CHECKSUM_HEADER 2 | #define CHECKSUM_HEADER 3 | #include "header.h" 4 | /* Add up checksum, return value will be filled in checksum filed in header */ 5 | u_short add_checksum(u_short len_udp, int padding, const u_short *temp); 6 | #endif 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | 3 | all: client server 4 | 5 | again: clean client server 6 | 7 | client: checksum.o header.o 8 | $(CC) client.c checksum.o header.o -o client 9 | 10 | server: checksum.o header.o 11 | $(CC) server.c checksum.o header.o -o server 12 | 13 | clean: 14 | rm -f *.o client server 15 | -------------------------------------------------------------------------------- /header.h: -------------------------------------------------------------------------------- 1 | #ifndef HEADER_HEADER 2 | #define HEADER_HEADER 3 | #include 4 | #define ACK 1 5 | #define FIN 2 6 | #define HEADER_SIZE 8 7 | #define PACKET_SIZE 1024 8 | #define PAYLOAD_SIZE (PACKET_SIZE-HEADER_SIZE) 9 | 10 | typedef struct _header_ { 11 | u_short seq; 12 | u_short ack; 13 | u_short checksum; 14 | u_short offset:10; 15 | u_short flag:6; 16 | } header_t; 17 | 18 | typedef struct _packet_ { 19 | header_t header; 20 | u_char payload[PAYLOAD_SIZE]; 21 | } packet_t; 22 | 23 | int fill_header(u_short seq, u_short ack, u_short offset, u_short flag, packet_t* packet); 24 | 25 | int fill_packet(u_char* src, packet_t* packet,u_short size); 26 | 27 | int read_header(header_t * p, packet_t* packet); 28 | 29 | int read_packet(u_char* dest, packet_t* packet, u_short size); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 |

tftp

3 |

This is a simple tftp server/client that can be used to transfer a file. It also displays information as the transfer takes place, showing you the packet sizes being sent, the ACK receiving, etc. Heavily inspired by Beej's guide to network programming.

4 |

Both the client and server are set on port 69 by default, but this may not be accessible to you, so you can change the port (and host) if you need to.

5 |

The received file is named "recvfile.txt" so you can see what was sent and it won't replace the file (in case you choose to do it in the same folder, which you can. It's pretty full featured and will try to resend failed packets a certain number of times before it gives up.

6 |
7 |

Installation

8 |
make
9 |

Uninstallation

10 |
make clean
11 |
12 |

Usage

13 |

Server

14 |
./server [-p port]
15 |

Client

16 |
./client [-p port] [-h hostname] -f filename
17 | 18 | -------------------------------------------------------------------------------- /checksum.c: -------------------------------------------------------------------------------- 1 | #include "checksum.h" 2 | #include 3 | 4 | 5 | /* Add up checksum, return value will be filled in checksum filed in header */ 6 | u_short add_checksum(u_short len_udp, 7 | int padding, const u_short *temp) 8 | { 9 | u_short prot_udp = 17; 10 | u_short padd = 0; 11 | u_short word16; 12 | u_long sum; 13 | static u_char buff[1600]; 14 | int i; 15 | memset(buff, 0, 1600); 16 | memcpy(buff, temp, len_udp); 17 | 18 | // take padding into account 19 | if ((padding & 1) == 1) 20 | { 21 | padd = 1; 22 | buff[len_udp] = 0; 23 | } 24 | 25 | //initialize sum to zero 26 | sum = 0; 27 | 28 | // make 16 bit words out of every two adjacent 8 bit words and 29 | // calculate the sum of all 16 vit words 30 | for (i = 0; i < len_udp + padd; i = i + 2) 31 | { 32 | word16 = ((buff[i] << 8) & 0xFF00) + (buff[i + 1] & 0xFF); 33 | //cout << hex << (int) buff[i] << " " << (int) buff[i + 1] << " "; 34 | sum = sum + (unsigned long) word16; 35 | } 36 | while (sum >> 16) 37 | sum = (sum & 0xFFFF) + (sum >> 16); 38 | sum = ~sum; 39 | 40 | return ((u_short) sum); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /header.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include 3 | #include 4 | 5 | /* fill header without checksum */ 6 | int fill_header(u_short seq, u_short ack, u_short offset, u_short flag, packet_t* packet) 7 | { 8 | assert(offset<=1024); 9 | assert(flag==ACK||flag==FIN||flag==(ACK|FIN)); 10 | assert(packet!=0); 11 | packet->header.seq=seq; 12 | packet->header.ack=ack; 13 | packet->header.checksum=0; 14 | packet->header.offset=offset; 15 | packet->header.flag=flag; 16 | return 0; 17 | } 18 | 19 | int fill_packet(u_char* src, packet_t* packet, u_short size) 20 | { 21 | assert(size<=PAYLOAD_SIZE); 22 | memcpy(packet->payload,src,size); 23 | return 0; 24 | } 25 | 26 | int read_header(header_t * p, packet_t* packet) 27 | { 28 | header_t * tmp= (header_t*)packet; 29 | p->seq=tmp->seq; 30 | p->ack=tmp->ack; 31 | p->offset=tmp->offset; 32 | p->flag=tmp->flag; 33 | return 0; 34 | } 35 | 36 | int read_packet(u_char* dest, packet_t* packet, u_short size) 37 | { 38 | assert(size<=PAYLOAD_SIZE); 39 | memcpy(dest,packet->payload,size); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * project: tftp server program 3 | * author: Oscar Sanchez (oms1005@gmail.com) 4 | * description: a small tftp (trivial ftp) server program 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "header.h" 23 | #include "checksum.h" 24 | 25 | #define BACKLOG 10 // how many pending connections queue will hold 26 | 27 | 28 | void sigchld_handler(int s) 29 | { 30 | while(waitpid(-1, NULL, WNOHANG) > 0); 31 | } 32 | 33 | // get sockaddr, IPv4 or IPv6: 34 | void *get_in_addr(struct sockaddr *sa) 35 | { 36 | if (sa->sa_family == AF_INET) { 37 | return &(((struct sockaddr_in*)sa)->sin_addr); 38 | } 39 | 40 | return &(((struct sockaddr_in6*)sa)->sin6_addr); 41 | } 42 | 43 | int main(int argc, char**argv) 44 | { 45 | 46 | int port = 69; 47 | char ch; 48 | /* Read command line options */ 49 | while ((ch = getopt(argc, argv, "p:")) != -1) { 50 | switch (ch) { 51 | case 'p': 52 | port = atoi(optarg); 53 | break; 54 | case '?': 55 | printf("Usage: ./server [-p port]\n"); 56 | exit(1); 57 | } 58 | } 59 | char PORT[10]; 60 | sprintf(PORT,"%d",port); 61 | 62 | int sockfd, new_fd; // listen on sock_fd, new connection on new_fd 63 | struct addrinfo hints, *servinfo, *p; 64 | struct sockaddr_storage their_addr; // connector's address information 65 | socklen_t sin_size; 66 | struct sigaction sa; 67 | int yes=1; 68 | char s[INET6_ADDRSTRLEN]; 69 | int rv; 70 | 71 | memset(&hints, 0, sizeof hints); 72 | hints.ai_family = AF_UNSPEC; 73 | hints.ai_socktype = SOCK_STREAM; 74 | hints.ai_flags = AI_PASSIVE; // use my IP 75 | 76 | if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { 77 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 78 | return 1; 79 | } 80 | 81 | // loop through all the results and bind to the first we can 82 | for(p = servinfo; p != NULL; p = p->ai_next) { 83 | if ((sockfd = socket(p->ai_family, p->ai_socktype, 84 | p->ai_protocol)) == -1) { 85 | perror("server: socket"); 86 | continue; 87 | } 88 | 89 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, 90 | sizeof(int)) == -1) { 91 | perror("setsockopt"); 92 | exit(1); 93 | } 94 | 95 | if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 96 | close(sockfd); 97 | perror("server: bind"); 98 | continue; 99 | } 100 | 101 | break; 102 | } 103 | 104 | if (p == NULL) { 105 | fprintf(stderr, "server: failed to bind\n"); 106 | return 2; 107 | } 108 | 109 | freeaddrinfo(servinfo); // all done with this structure 110 | 111 | if (listen(sockfd, BACKLOG) == -1) { 112 | perror("listen"); 113 | exit(1); 114 | } 115 | 116 | sa.sa_handler = sigchld_handler; // reap all dead processes 117 | sigemptyset(&sa.sa_mask); 118 | sa.sa_flags = SA_RESTART; 119 | if (sigaction(SIGCHLD, &sa, NULL) == -1) { 120 | perror("sigaction"); 121 | exit(1); 122 | } 123 | 124 | printf("server: waiting for connections...\n"); 125 | 126 | while(1) { // main accept() loop 127 | sin_size = sizeof their_addr; 128 | new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); 129 | if (new_fd == -1) { 130 | perror("accept"); 131 | continue; 132 | } 133 | 134 | inet_ntop(their_addr.ss_family, 135 | get_in_addr((struct sockaddr *)&their_addr), 136 | s, sizeof s); 137 | printf("server: got connection from %s\n", s); 138 | 139 | if (!fork()) { // this is the child process 140 | close(sockfd); // child doesn't need the listener 141 | 142 | /* Set Socket to non blocking */ 143 | //fcntl(new_fd, F_SETFL, O_NONBLOCK); 144 | char buf[PACKET_SIZE]; 145 | char databuf[PAYLOAD_SIZE]; 146 | int numbytes, ack_bytes; 147 | header_t head; 148 | packet_t packet; 149 | packet_t ackr; 150 | //char recved[PACKET_SIZE]; 151 | int getfilename = 1; 152 | char *filename = (char*) "recvfile.txt"; 153 | 154 | FILE * filefd; 155 | 156 | /* Zero the arrays */ 157 | bzero(buf, PACKET_SIZE); 158 | bzero(databuf, PAYLOAD_SIZE); 159 | 160 | while(getfilename) { 161 | if ((numbytes = recv(new_fd, buf, PACKET_SIZE, 0)) == -1) { 162 | perror("recv"); 163 | exit(1); 164 | } 165 | /* We have a packet with filename! */ 166 | if(numbytes > 0) 167 | { 168 | read_header(&head, (packet_t *)buf); 169 | read_packet((u_char*) databuf, (packet_t *)buf, (u_short) (numbytes - HEADER_SIZE)); 170 | printf("Packet '%d' received\n", (int)(head.seq)); 171 | 172 | if(add_checksum(numbytes, numbytes%2, (u_short *)buf) == 0) { 173 | printf("Checksum OK\n"); 174 | /* Create ACK to send back with sequence number */ 175 | fill_header((int)(head.seq), 0, HEADER_SIZE, ACK, &ackr); 176 | 177 | printf("Filename: '%s' bytes '%d'\n", databuf, numbytes); 178 | 179 | if((ack_bytes = send(new_fd, &ackr, HEADER_SIZE, 0)) == -1) { 180 | perror("send: ack"); 181 | exit(1); 182 | } else { 183 | printf("ACK '%d' sent\n", (int)(head.seq)); 184 | getfilename = 0; 185 | } 186 | 187 | } else { 188 | printf("Checksum failed, discarding packet...\n"); 189 | } 190 | } 191 | } /* END first while for filename */ 192 | 193 | 194 | //filefd = open(argv[3], O_WRONLY | O_CREAT | O_APPEND); 195 | 196 | if ( (filefd = fopen(filename, "w")) == NULL) 197 | { 198 | fprintf(stderr, "Could not open destination file, using stdout.\n"); 199 | } else { 200 | printf("Preparing to start writing file '%s'\n", filename ); 201 | } 202 | 203 | 204 | int recvFIN = 0; 205 | /* re-zero array */ 206 | bzero(buf, PACKET_SIZE); 207 | bzero(databuf, PAYLOAD_SIZE); 208 | 209 | /* read the file from the socket as long as there is data */ 210 | 211 | do { 212 | 213 | if ((numbytes = recv(new_fd, buf, PACKET_SIZE, 0)) == -1) { 214 | perror("recv"); 215 | fclose(filefd); 216 | close(new_fd); 217 | exit(1); 218 | } 219 | 220 | read_header(&head, (packet_t *)buf); 221 | 222 | if((int)head.flag == ACK) 223 | { 224 | read_packet((u_char*) databuf, (packet_t *)buf, (u_short) (numbytes - HEADER_SIZE)); 225 | 226 | printf("Packet '%d' received with '%d' bytes with an offset of '%d'\n", (int)(head.seq), numbytes, (int)(head.offset)); 227 | 228 | if(add_checksum(numbytes, numbytes%2, (u_short *)buf) == 0) { 229 | printf("Checksum OK\n"); 230 | /* Create ACK to send back with sequence number */ 231 | fill_header((int)(head.seq), 0, HEADER_SIZE, ACK, &ackr); 232 | 233 | 234 | if((ack_bytes = send(new_fd, &ackr, HEADER_SIZE, 0)) == -1) { 235 | perror("send: ack"); 236 | exit(1); 237 | } else { 238 | printf("ACK '%d' sent\n", (int)(head.seq)); 239 | /* write to file */ 240 | fwrite(databuf,1 , (int)(head.offset) ,filefd ); 241 | } 242 | 243 | } else { 244 | printf("Checksum failed, discarding packet...\n"); 245 | } 246 | } else if ((int)head.flag == FIN) { 247 | printf("FIN received...\n"); 248 | /* Create FIN to send back with sequence number */ 249 | fill_header((int)(head.seq), 0, HEADER_SIZE, FIN, &ackr); 250 | if((ack_bytes = send(new_fd, &ackr, HEADER_SIZE, 0)) == -1) { 251 | perror("send: ack"); 252 | exit(1); 253 | } else { 254 | printf("FIN '%d' sent\n", (int)(head.seq)); 255 | recvFIN = 1; 256 | } 257 | } 258 | //else if ((int)head.flag == FIN) { 259 | /* re-zero */ 260 | bzero(buf, PACKET_SIZE); 261 | bzero(databuf, PAYLOAD_SIZE); 262 | } while (!recvFIN ); 263 | printf("Done...\n"); 264 | 265 | fclose(filefd); 266 | close(new_fd); 267 | exit(0); 268 | } 269 | close(new_fd); // parent doesn't need this 270 | } 271 | return 0; 272 | } 273 | -------------------------------------------------------------------------------- /client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * project: tftp client program 3 | * author: Oscar Sanchez (oms1005@gmail.com) 4 | * description: a small tftp (trivial ftp) client program 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "header.h" 25 | #include "checksum.h" 26 | 27 | #define RETRY 10 28 | 29 | int recvfromTimeOut(int socket, long sec, long usec) 30 | { 31 | // Setup timeval variable 32 | struct timeval timeout; 33 | timeout.tv_sec = sec; 34 | timeout.tv_usec = usec; 35 | // Setup fd_set structure 36 | fd_set fds; 37 | FD_ZERO(&fds); 38 | FD_SET(socket, &fds); 39 | // >0: data ready to be read 40 | return select(FD_SETSIZE, &fds, NULL, NULL, &timeout); 41 | } 42 | 43 | /* Returns the recv message */ 44 | int tftp(int sockfd, const void * packet, int expected_seqnum, int timeout, int flag ) { 45 | int numbytes = 0, ret = 0, retry = RETRY; 46 | int is_retransmit = 0; 47 | char ackbuf[HEADER_SIZE]; 48 | header_t head; 49 | int res = 0; /* Timer/Select Variable */ 50 | 51 | do { 52 | 53 | /* Try to send the packet */ 54 | if ((numbytes = send(sockfd, packet, PACKET_SIZE, 0)) == -1) { 55 | perror("Error in tftp"); 56 | exit(1); 57 | } else if (numbytes >0) { 58 | if (flag == ACK){ 59 | printf("Packet "); 60 | if(is_retransmit) 61 | printf("'%d' Re-transmitted.\n", expected_seqnum); 62 | else 63 | printf("'%d' sent\n", expected_seqnum); 64 | } else { 65 | printf("FIN "); 66 | if(is_retransmit) 67 | printf("'%d' Re-transmitted.\n", expected_seqnum); 68 | else 69 | printf("'%d' sent\n", expected_seqnum); 70 | } 71 | 72 | } 73 | 74 | //sleep(1); 75 | 76 | /* Start the timeout */ 77 | res = recvfromTimeOut(sockfd, 0, timeout); 78 | 79 | switch (res) 80 | { 81 | case 0: 82 | // Timed out, do whatever you want to handle this situation 83 | printf("Packet '%d' ******Timed Out*****, %d retries left\n", expected_seqnum, retry-1); 84 | is_retransmit = 1; 85 | ret = -2; 86 | break; 87 | 88 | case -1: 89 | // Error occured, maybe we should display an error message? 90 | printf("ERROR with timer recvfromTimeOut()\n"); 91 | exit(-1); 92 | break; 93 | 94 | default: 95 | // Ok the data is ready, call recvfrom() to get it then 96 | //printf("We are trying to received something\n"); 97 | //ret = recv(sockfd,ackbuf,HEADER_SIZE,0); 98 | ret = recv(sockfd,ackbuf,HEADER_SIZE,0); 99 | if( ret == -1) { 100 | perror("Error in tftp"); 101 | exit(1); 102 | } 103 | if (ret > 0) { 104 | //printf("We received something\n"); 105 | read_header(&head, (packet_t *)ackbuf); 106 | //read_packet((u_char*) recved, (packet_t *)buf, (u_short) (numbytes - HEADER_SIZE)); 107 | if ( (int) head.flag == ACK && (int) head.seq == expected_seqnum ) { 108 | printf("ACK '%d' received\n", expected_seqnum); 109 | return ret; 110 | } else if ( (int) head.flag == FIN && (int) head.seq == expected_seqnum ){ 111 | ret -10; 112 | return ret; 113 | } 114 | } 115 | return ret; 116 | } 117 | 118 | } while(--retry); 119 | 120 | if (!retry && ret == -2) { 121 | printf("Packet '%d' failed with '%d' retries. \n", expected_seqnum, RETRY); 122 | ret = -1; 123 | } 124 | 125 | return ret; 126 | } 127 | 128 | 129 | // get sockaddr, IPv4 or IPv6: 130 | void *get_in_addr(struct sockaddr *sa) 131 | { 132 | if (sa->sa_family == AF_INET) { 133 | return &(((struct sockaddr_in*)sa)->sin_addr); 134 | } 135 | 136 | return &(((struct sockaddr_in6*)sa)->sin6_addr); 137 | } 138 | 139 | int main(int argc, char *argv[]) 140 | { 141 | int sockfd; 142 | struct addrinfo hints, *servinfo, *p; 143 | int rv; 144 | char s[INET6_ADDRSTRLEN]; 145 | 146 | // used for inputs 147 | char ch, *filename = (char*) "sendfile.txt", *address = (char *) "127.0.0.1"; 148 | int port = 69; 149 | 150 | 151 | /* Read command line options */ 152 | while ((ch = getopt(argc, argv, "h:p:f:")) != -1) { 153 | switch (ch) { 154 | case 'h': 155 | address = optarg; 156 | break; 157 | case 'p': 158 | port = atoi(optarg); 159 | break; 160 | case 'f': 161 | filename = optarg; 162 | break; 163 | case '?': 164 | if (optopt == 'f') { 165 | fprintf(stderr, "Option -%c requires an argument\n", optopt); 166 | } else { 167 | fprintf(stderr, "Unknown option\n"); 168 | } 169 | exit(1); 170 | } 171 | } 172 | char PORT[10]; 173 | sprintf(PORT,"%d",port); 174 | printf("Starting client connecting to host: %s on port: %d with filename: %s\n", address, port, filename ); 175 | 176 | memset(&hints, 0, sizeof hints); 177 | hints.ai_family = AF_UNSPEC; 178 | hints.ai_socktype = SOCK_STREAM; 179 | 180 | if ((rv = getaddrinfo(address, PORT, &hints, &servinfo)) != 0) { 181 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 182 | return 1; 183 | } 184 | 185 | // loop through all the results and connect to the first we can 186 | for(p = servinfo; p != NULL; p = p->ai_next) { 187 | if ((sockfd = socket(p->ai_family, p->ai_socktype, 188 | p->ai_protocol)) == -1) { 189 | perror("client: socket"); 190 | continue; 191 | } 192 | 193 | if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 194 | close(sockfd); 195 | perror("client: connect"); 196 | continue; 197 | } 198 | 199 | break; 200 | } 201 | 202 | if (p == NULL) { 203 | fprintf(stderr, "client: failed to connect\n"); 204 | return 2; 205 | } 206 | 207 | inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), 208 | s, sizeof s); 209 | printf("client: connecting to %s\n", s); 210 | 211 | //freeaddrinfo(servinfo); // all done with this structure 212 | 213 | /* Set Socket to non blocking */ 214 | fcntl(sockfd, F_SETFL, O_NONBLOCK); 215 | 216 | /* Initialize data*/ 217 | char databuf[PAYLOAD_SIZE]; 218 | char packetbuf[PACKET_SIZE]; 219 | int seqnum = 0; 220 | packet_t packet; 221 | u_short checksum; 222 | int retry = RETRY; 223 | int numbytes = 0, ret = 0; 224 | FILE * filefd; 225 | 226 | struct stat finfo; 227 | int filesize=0; 228 | int send_results = 0; 229 | 230 | /* Initialize the arrays to zeros */ 231 | bzero(databuf, PAYLOAD_SIZE); 232 | bzero(packetbuf, PACKET_SIZE); 233 | 234 | /* open the file for reading */ 235 | if ((filefd = fopen(filename, "r")) == NULL) 236 | { 237 | fprintf(stderr, "Could not open file for reading!\n"); 238 | close(sockfd); 239 | return 2; 240 | } else { 241 | // if (-1 == stat(argv[3], &finfo)) 242 | // fprintf(stderr,"error stating file!\n"); 243 | printf("File '%s' of size '%d' bytes opened and ready to send filename\n", filename, (int)finfo.st_size ); 244 | } 245 | 246 | /* Copy the filename to the buffer */ 247 | strcpy(databuf, filename); 248 | databuf[PAYLOAD_SIZE] = '\0'; 249 | 250 | /* create a packet */ 251 | fill_header(seqnum, 0, PAYLOAD_SIZE, ACK, &packet); 252 | fill_packet((u_char*) &databuf[0], &packet, PAYLOAD_SIZE); 253 | /* calculate checksum */ 254 | checksum = add_checksum(PACKET_SIZE, 0, (u_short*) &packet); 255 | packet.header.checksum = htons(checksum); 256 | //assert(add_checksum(PACKET_SIZE, 0, (u_short *)&packet) == 0); 257 | 258 | /* Send the filename... */ 259 | send_results = tftp(sockfd, &packet, seqnum, 900000, ACK ); 260 | if (send_results == -1) { 261 | fprintf(stderr, "Time out..\n"); 262 | close(sockfd); 263 | return 2; 264 | } else if (send_results == -10) { 265 | printf("Received the final FIN.. Closing up shop."); 266 | fclose(filefd); 267 | close(sockfd); 268 | return 0; 269 | } 270 | seqnum++; 271 | 272 | /* File Sending Section*/ 273 | /* Re-Initialize the arrays to zeros */ 274 | bzero(databuf, PAYLOAD_SIZE); 275 | bzero(packetbuf, PACKET_SIZE); 276 | 277 | int readCounter = 0; 278 | int writeCounter = 0; 279 | char* readbufptr = NULL; 280 | 281 | /* read the file, and send it to the client in chunks of size PAYLOAD_SIZ */ 282 | while((readCounter = fread(databuf,1, PAYLOAD_SIZE, filefd)) > 0) 283 | { 284 | writeCounter = 0; 285 | readbufptr = databuf; 286 | 287 | databuf[readCounter] = '\0'; 288 | 289 | fill_header(seqnum, 0, readCounter, ACK, &packet); 290 | fill_packet((u_char*) &databuf[0], &packet, readCounter); 291 | /* calculate checksum */ 292 | checksum = add_checksum(PACKET_SIZE, 0, (u_short*) &packet); 293 | packet.header.checksum = htons(checksum); 294 | 295 | //printf("Bytes sent: '%d' while readCounter '%d'\n", sizeof(packet), readCounter); 296 | 297 | /* Send the filecontents... */ 298 | /* Send the filename... */ 299 | send_results = tftp(sockfd, &packet, seqnum, 900000, ACK ); 300 | if (send_results == -1) { 301 | fprintf(stderr, "Time out..\n"); 302 | close(sockfd); 303 | return 2; 304 | } else if (send_results == -10) { 305 | printf("Received the final FIN.. Closing up shop."); 306 | fclose(filefd); 307 | close(sockfd); 308 | return 0; 309 | } 310 | seqnum++; 311 | 312 | /* Re-Initialize the arrays to zeros */ 313 | bzero(databuf, PAYLOAD_SIZE); 314 | bzero(packetbuf, PACKET_SIZE); 315 | } 316 | 317 | /* Re-Initialize the arrays to zeros */ 318 | bzero(databuf, PAYLOAD_SIZE); 319 | bzero(packetbuf, PACKET_SIZE); 320 | 321 | /* Send the FIN */ 322 | fill_header(seqnum, 0, readCounter, FIN, &packet); 323 | /* calculate checksum */ 324 | checksum = add_checksum(PACKET_SIZE, 0, (u_short*) &packet); 325 | packet.header.checksum = htons(checksum); 326 | 327 | /* Send the filename... */ 328 | send_results = tftp(sockfd, &packet, seqnum, 900000, FIN ); 329 | if (send_results == -1) { 330 | fprintf(stderr, "Time out..\n"); 331 | close(sockfd); 332 | return 2; 333 | } else if (send_results == -10) { 334 | printf("Received the final FIN.. Closing up shop."); 335 | fclose(filefd); 336 | close(sockfd); 337 | return 0; 338 | } 339 | seqnum++; 340 | 341 | printf("Goodbye\n"); 342 | freeaddrinfo(servinfo); // all done with this structure 343 | close(sockfd); 344 | return 0; 345 | } 346 | --------------------------------------------------------------------------------