| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- /*
- * Copyright (C) 2008 by Thermotemp GmbH. All rights reserved.
- * Copyright (C) 2002-2007 by egnite Software GmbH. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
- * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- #include <stdio.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <sys/heap.h>
- #include "default.h"
- #include "debug.h"
- #include "tftp.h"
- tftp_header tx_frame;
- tftp_header rx_frame;
- int tftp_receive(char *filename, u_long tftp_ip, int (*callback)(u_char *buffer, u_short block_size, u_long offset, void* user_data), void* user_data)
- {
- unsigned char retry;
- int len = 0;
- int rx_len = 0;
- int tx_len = 0;
- unsigned short block = 0;
- char *cp;
- UDPSOCKET *tftp_socket;
- u_long remote_ip;
- u_short remote_port = TFTP_PORT;
- u_long offset = 0;
- int total_bytes = 0;
- /*
- * Do nothing if there's no TFTP host configured.
- */
- tftp_socket = NutUdpCreateSocket(TFTP_PORT);
- if (tftp_socket == 0) {
- ERROR("Could not create TFTP UDP socket\r\n");
- goto error;
- }
- /*
- * Prepare the transmit buffer for a file request.
- */
- tx_frame.th_opcode = htons(TFTP_RRQ);
- tx_len = 2;
- cp = tx_frame.th_u.tu_stuff;
- INFO("TFTP Loading %s\r\n", filename);
- strcpy(cp, filename);
- len = strlen(filename) + 1;
- tx_len += len;
- cp += len;
- strcpy(cp, "octet");
- tx_len += 6;
- /*
- * Loop until we receive a packet with less than 512 bytes of data.
- */
- do {
- /*
- * Send file request or acknowledge and receive
- * a data block. Maximum 3 retries on timeout or error
- */
- for (retry = 0; retry < 3; retry++) {
- if (NutUdpSendTo(tftp_socket, tftp_ip, remote_port, &tx_frame, tx_len) == 0) {
- rx_len = NutUdpReceiveFrom(tftp_socket, &remote_ip, &remote_port, &rx_frame, sizeof(tftp_header), 5000);
- if (rx_len >= 4) break;
- }
- }
- /*
- * Can't reach the TFTP server or got a malformed
- * repsonse.
- */
- if (retry >= 3 || rx_len < 4) {
- goto error;
- }
- /*
- * Accept data blocks only. Anything else will stop
- * the transfer with an error.
- */
- if (ntohs(rx_frame.th_opcode) != TFTP_DATA) {
- goto error;
- }
- /*
- * If this was the first block we received, prepare
- * the send buffer for sending ACKs.
- */
- if (block == 0) {
- tx_frame.th_opcode = htons(TFTP_ACK);
- tx_len = 4;
- }
- /*
- * If this block is out of sequence, we ignore it.
- * However, if we missed the first block, return
- * with an error.
- */
- if (ntohs(rx_frame.th_u.tu_block) != block + 1) {
- if (block == 0) {
- goto error;
- }
- continue;
- }
- /*
- * Burn the received data into the flash ROM.
- */
- if (rx_len > 4) {
- //INFO("TFTP received block %d\r\n", block);
- INFO(".");
- callback(rx_frame.th_data, rx_len-4, offset, user_data);
- total_bytes += rx_len-4;
- offset += MIN(rx_len - 4, 512);
- }
- /*
- * Update our block counter.
- */
- block++;
- tx_frame.th_u.tu_block = htons(block);
- } while (rx_len >= 516);
- /*
- * Send the last ACK.
- */
- NutUdpSendTo(tftp_socket, tftp_ip, remote_port, &tx_frame, tx_len);
- return total_bytes;
- error:
- return -1;
- }
|