/* Transfer a file to or from the server. */ int tftp_transfer(struct tftp_conn *tc) { int retval = 0; int len; int reclen; int totlen = 0; int terminate = 0; struct timeval timeout; /* Sanity check */ if (!tc) return -1; fd_set sfd; char recbuf[MSGBUF_SIZE]; FD_ZERO(&sfd); FD_SET(tc->sock, &sfd); len = BLOCK_SIZE + TFTP_DATA_HDR_LEN; reclen = 0; /* After the connection request we should start receiving data * immediately */ /* Set a timeout for resending data. */ timeout.tv_sec = TFTP_TIMEOUT; timeout.tv_usec = 0; /* Check if we are putting a file or getting a file and send * the corresponding request. */ if (tc->type == TFTP_TYPE_GET) { /* Send read request */ if(tftp_send_rrq(tc) < 0) fprintf(stderr,"FAIL TO SEND RRQ\n"); } else if (tc->type == TFTP_TYPE_PUT) { /* Send write request */ if(tftp_send_wrq(tc) < 0) fprintf(stderr,"FAIL TO SEND WRQ\n"); } else { return -1; } /* Put or get the file, block by block, in a loop. */ do { /* 1. Wait for something from the server (using * 'select'). If a timeout occurs, resend last block * or ack depending on whether we are in put or get * mode. */ /* ... */ printf("Waiting for response... \n"); FD_ZERO(&sfd); FD_SET(tc->sock, &sfd); switch (select(tc->sock + 1, &sfd, NULL, NULL, &timeout)) { case (-1): fprintf(stderr, "\nselect()\n"); break; case (0): /* Timeout, reinit the counter and do a resend. * Nested switch-case statemens are awesome! */ printf("**** TIMEOUT *****\n"); timeout.tv_sec = TFTP_TIMEOUT; timeout.tv_usec = 0; switch (ntohs(((u_int16_t*) tc->msgbuf)[0])) { case OPCODE_RRQ: tftp_send_rrq(tc); continue; case OPCODE_WRQ: tftp_send_wrq(tc); continue; case OPCODE_DATA: tftp_send_data(tc, -len); continue; case OPCODE_ACK: tftp_send_ack(tc); continue; case OPCODE_ERR: //TODO: Vilka error-medelanden ska skickas om, om några? continue; default: fprintf(stderr, "\nThis shouldn't happend\n"); goto out; //continue; } break; default: //TODO: Använda recvfrom() istället och kolla efter felaktig source port. /* Save the recieved bytes in 'rec_len' so we * can check if we should terminate the transfer */ printf("GOT SOMETHING!!!!\n"); reclen = recvfrom(tc->sock, recbuf, MSGBUF_SIZE,0, (struct sockaddr *) &tc->peer_addr, &tc->addrlen); print_message((struct tftp_msg *)recbuf, 1); //printf("%d\n", ntohs(((u_int16_t*) recbuf)[0])); break; } /* 2. Check the message type and take the necessary * action. */ switch (ntohs(((u_int16_t*) recbuf)[0])) { case OPCODE_DATA: /* Received data block, send ack */ //TODO: Skriv datan till en fil printf("Received data\n"); tc->blocknr++; if (tc->type == TFTP_TYPE_PUT) { fprintf(stderr, "\nExpected ack, got data\n"); goto out; } printf("We expect block number %d\n", tc->blocknr); printf("We got block number %d\n",ntohs(((u_int16_t*) recbuf)[1])); if (ntohs(((u_int16_t*) recbuf)[1]) != tc->blocknr) { fprintf(stderr, "\nGot unexpected data block§ nr\n"); goto out; } /* If we are getting and recieved a data package with * a block of < 512, we want to terminate the loop * after getting sending an ack */ if (reclen < (TFTP_DATA_HDR_LEN + BLOCK_SIZE)) terminate = 1; tftp_send_ack(tc); //TODO: Kolla returvärdet int i = 0; int hnllen = sizeof(HOST_NEWLINE_STYLE) - 1; int nanllen = sizeof(NETASCII_NEWLINE_STYLE) - 1; if (!strcmp(tc->mode, MODE_NETASCII)) { do { if (!strncmp(&recbuf[TFTP_DATA_HDR_LEN + i], NETASCII_NEWLINE_STYLE, nanllen)) { fwrite(HOST_NEWLINE_STYLE, 1, hnllen, tc->fp); i += nanllen; } else { fwrite(&recbuf[TFTP_DATA_HDR_LEN + i], 1, 1,tc->fp); i++; } } while(i < reclen - TFTP_DATA_HDR_LEN); } else { fwrite(&recbuf[TFTP_DATA_HDR_LEN],1,reclen - TFTP_DATA_HDR_LEN,tc->fp); } break; case OPCODE_ACK: printf("Received ACK, send next block\n"); if (tc->type == TFTP_TYPE_GET) { fprintf(stderr, "\nExpected data, got ack\n"); goto out; } /* If we are putting and sent a data package with * a block of < 512 bytes last time, we want to * terminate the loop after getting the final ack */ if (len < (TFTP_DATA_HDR_LEN + BLOCK_SIZE)) { terminate = 1; printf("We're done sending, let's terminate\n"); } else { /* Save the numer of sent bytes in 'len' in case * it's < 512 and the package has to be resent. */ len = tftp_send_data(tc, BLOCK_SIZE); printf("We sent a packet of length %d\n",len); } break; case OPCODE_ERR: printf("The transfer was terminated with an error "); printf("and the pitiful excuse given by the server was: "); printf("%s\n", ((struct tftp_err*) &recbuf)->errmsg); break; default: fprintf(stderr, "\nUnknown message type\n"); goto out; } totlen += (len + reclen); } while (!terminate); if (tc->type == TFTP_TYPE_GET && terminate) { /* The loop terminated succesfully but the last ack might * have been lost. Wait for a possible duplicate data * package and in that case send the ack one more time */ timeout.tv_sec = TFTP_TIMEOUT; timeout.tv_usec = 0; if (select(1, &sfd, NULL, NULL, &timeout) > 0) { read(tc->sock, tc->msgbuf, MSGBUF_SIZE); if (ntohs(((u_int16_t *) tc->msgbuf)[0]) == OPCODE_DATA && ntohs(((u_int16_t*) tc->msgbuf)[1]) == tc->blocknr) { tftp_send_ack(tc); } } } printf("\nTotal data bytes sent/received: %d.\n", totlen); out: fclose(tc->fp); return retval; }
/* Transfer a file to or from the server. */ int tftp_transfer(struct tftp_conn *tc) { int retval = 0; int len; int totlen = 0; struct timeval timeout; int loopend = 1; int final_pkt = 0; int first_rrq = 1; int first_wrq = 1; /* Sanity check */ if (!tc) return -1; len = 0; /* ===ADDED (NOT ACCORDING TO INSTRUCTIONS)=== */ long int file_size; fseek(tc->fp, 0L, SEEK_END); file_size = ftell(tc->fp); fseek(tc->fp, 0L, SEEK_SET); /* ===END OF ADDED=== */ /* After the connection request we should start receiving data * immediately */ /* Set a timeout for resending data. */ timeout.tv_sec = TFTP_TIMEOUT; timeout.tv_usec = 0; /* Check if we are putting a file or getting a file and send * the corresponding request. */ /* ===ADDED=== */ if (tc->type == TFTP_TYPE_GET) { retval = tftp_send_rrq(tc); } else if (tc->type == TFTP_TYPE_PUT) { retval = tftp_send_wrq(tc); } if (retval == -1) { return retval; } else { totlen += retval; } /* ===END OF ADDED=== */ /* Put or get the file, block by block, in a loop. */ int all_done = 0; do { /* 1. Wait for something from the server (using * 'select'). If a timeout occurs, resend last block * or ack depending on whether we are in put or get * mode. */ /* ===ADDED=== */ fd_set readfds; FD_ZERO(&readfds); FD_SET(tc->sock, &readfds); select(tc->sock + 1, &readfds, NULL, NULL, &timeout); if (FD_ISSET(tc->sock, &readfds)) { retval = recvfrom(tc->sock, tc->msgbuf, MSGBUF_SIZE, 0, (struct sockaddr *) &tc->peer_addr, &tc->addrlen); } else { // Timeout if (tc->type == TFTP_TYPE_PUT) { if (first_wrq == 1) { retval = tftp_send_wrq(tc); } else { retval = tftp_send_data(tc, -len); } continue; } else if (tc->type == TFTP_TYPE_GET) { if (first_rrq == 1) { retval = tftp_send_rrq(tc); } else if(final_pkt == 1) { break; } else { retval = tftp_send_ack(tc); } continue; } } /* ===END OF ADDED=== */ /* 2. Check the message type and take the necessary * action. */ /* ===ADDED/CHANGED=== */ u_int16_t received_opcode = htons(*((u_int16_t*)tc->msgbuf)); u_int16_t received_blocknr; struct tftp_data *data; struct tftp_ack *ack_recv; struct tftp_err *err_recv; switch (received_opcode) { case OPCODE_DATA: /* Received data block, send ack */ data = (struct tftp_data *) tc->msgbuf; totlen += retval; len = retval - TFTP_DATA_HDR_LEN; received_blocknr = ntohs(data->blocknr); if((tc->blocknr+1) == received_blocknr){ fwrite(data->data, 1, len, tc->fp); if(len < BLOCK_SIZE) { final_pkt = 1; } tc->blocknr++; } retval = tftp_send_ack(tc); first_rrq = 0; break; case OPCODE_ACK: /* Received ACK, send next block */ ack_recv = (struct tftp_ack *) tc->msgbuf; received_blocknr = ntohs(ack_recv->blocknr); if(received_blocknr == tc->blocknr){ if(all_done){ loopend = 0; } else { tc->blocknr++; long int file_pos = ftell(tc->fp); if (file_size - file_pos < BLOCK_SIZE) { retval = tftp_send_data(tc, file_size - file_pos); all_done = 1; } else { retval = tftp_send_data(tc, BLOCK_SIZE); } } } else { retval = tftp_send_data(tc, -len); } len = retval; first_wrq = 0; break; case OPCODE_ERR: err_recv = (struct tftp_err *) tc->msgbuf; printf("ERROR CODE %d: %s\n", ntohs(err_recv->errcode), err_recv->errmsg); goto out; /* ===END OF ADDED/CHANGED=== */ default: fprintf(stderr, "\nUnknown message type\n"); goto out; } /* ===ADDED=== */ totlen += retval; /* ===END OF ADDED=== */ /* ===CHANGED=== */ } while (loopend /* 3. Loop until file is finished */); /* ===END OF CHANGED=== */ printf("\nTotal data bytes sent/received: %d.\n", totlen); out: return retval; }