⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tftp_client.c

📁 redboot 源代码
💻 C
字号:
//==========================================================================////      net/tftp_client.c////      Stand-alone TFTP support for RedBoot////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.// Copyright (C) 2002 Gary Thomas//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s):    gthomas// Contributors: gthomas// Date:         2000-07-14// Purpose:      // Description:  //              // This code is part of RedBoot (tm).////####DESCRIPTIONEND####////==========================================================================// TFTP client support#include <redboot.h>     // have_net#include <net/net.h>#include <net/tftp.h>#include <net/tftp_support.h>// So we remember which ports have been usedstatic int get_port = 7700;static struct {    bool open;    int  total_timeouts;    unsigned short last_good_block;    int  avail, actual_len;    struct sockaddr_in local_addr, from_addr;    char data[SEGSIZE+sizeof(struct tftphdr)];    char *bufp;} tftp_stream;inttftp_stream_open(connection_info_t *info,                 int *err){    struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;    char *cp, *fp;    char test_buf;    if (!have_net || tftp_stream.open) {        *err = TFTP_INVALID;  // Already open        return -1;    }    // Create initial request    hdr->th_opcode = htons(RRQ);  // Read file    cp = (char *)&hdr->th_stuff;    fp = info->filename;    while (*fp) *cp++ = *fp++;    *cp++ = '\0';    // Since this is used for downloading data, OCTET (binary) is the    // only mode that makes sense.    fp = "OCTET";    while (*fp) *cp++ = *fp++;    *cp++ = '\0';    memset((char *)&tftp_stream.local_addr, 0, sizeof(tftp_stream.local_addr));    tftp_stream.local_addr.sin_family = AF_INET;    tftp_stream.local_addr.sin_addr.s_addr = htonl(INADDR_ANY);    tftp_stream.local_addr.sin_port = htons(get_port++);    if (info->server->sin_port == 0) {        info->server->sin_port = htons(TFTP_PORT);    }    // Send request - note: RFC 1350 (TFTP rev 2) indicates that this should be    // only as long as required to hold the request, with the nul terminator.    // Some servers silently go to lunch if the request is not the correct size.    if (__udp_sendto(tftp_stream.data, cp-(char *)hdr,                      info->server, &tftp_stream.local_addr) < 0) {        // Problem sending request        *err = TFTP_NETERR;        return -1;    }    tftp_stream.open = true;    tftp_stream.avail = 0;    tftp_stream.actual_len = -1;    tftp_stream.last_good_block = 0;    tftp_stream.total_timeouts = 0;    tftp_stream.from_addr.sin_port = 0;    // Try and read the first byte [block] since no errors are    // reported until then.    if (tftp_stream_read(&test_buf, 1, err) == 1) {        // Back up [rewind] over this datum        tftp_stream.bufp--;        tftp_stream.avail++;        return 0;  // Open and first read successful    } else {        tftp_stream.open = false;        return -1; // Couldn't read    }}voidtftp_stream_close(int *err){    tftp_stream.open = false;}inttftp_stream_read(char *buf,                 int len,                 int *err){    int total_bytes = 0;    int size, recv_len, data_len;    struct timeval timeout;    struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;    while (total_bytes < len) {        // Move any bytes which we've already read/buffered        if (tftp_stream.avail > 0) {            size = tftp_stream.avail;            if (size > (len - total_bytes)) size = len - total_bytes;            memcpy(buf, tftp_stream.bufp, size);            buf += size;            tftp_stream.bufp += size;            tftp_stream.avail -= size;            total_bytes += size;        } else {            if (tftp_stream.last_good_block != 0) {                // Send out the ACK                hdr->th_opcode = htons(ACK);                hdr->th_block = htons(tftp_stream.last_good_block);                if (__udp_sendto(tftp_stream.data, 4 /* FIXME */,                                  &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) {                    // Problem sending ACK                    *err = TFTP_NETERR;                    return -1;                }            }            if ((tftp_stream.actual_len >= 0) && (tftp_stream.actual_len < SEGSIZE)) {                // Out of data                break;            }            timeout.tv_sec = TFTP_TIMEOUT_PERIOD;            timeout.tv_usec = 0;            recv_len = sizeof(tftp_stream.data);            if ((data_len = __udp_recvfrom(&tftp_stream.data[0], recv_len, &tftp_stream.from_addr,                                            &tftp_stream.local_addr,  &timeout)) < 0) {                // No data, try again                if ((++tftp_stream.total_timeouts > TFTP_TIMEOUT_MAX) ||                     (tftp_stream.last_good_block == 0)) {                    // Timeout - no data received                    *err = TFTP_TIMEOUT;                    return -1;                }            } else {                if (ntohs(hdr->th_opcode) == DATA) {                    if (ntohs(hdr->th_block) == (tftp_stream.last_good_block+1)) {                        // Consume this data                        data_len -= 4;  /* Sizeof TFTP header */                        tftp_stream.avail = tftp_stream.actual_len = data_len;                        tftp_stream.bufp = hdr->th_data;                        tftp_stream.last_good_block++;                    }                } else {                    if (ntohs(hdr->th_opcode) == ERROR) {                        *err = ntohs(hdr->th_code);                        return -1;                    } else {                        // What kind of packet is this?                        *err = TFTP_PROTOCOL;                        return -1;                    }                }            }        }    }    return total_bytes;}char *tftp_error(int err){    char *errmsg = "Unknown error";    switch (err) {    case TFTP_ENOTFOUND:        return "file not found";    case TFTP_EACCESS:        return "access violation";    case TFTP_ENOSPACE:        return "disk full or allocation exceeded";    case TFTP_EBADOP:        return "illegal TFTP operation";    case TFTP_EBADID:        return "unknown transfer ID";    case TFTP_EEXISTS:        return "file already exists";    case TFTP_ENOUSER:        return "no such user";    case TFTP_TIMEOUT:        return "operation timed out";    case TFTP_NETERR:        return "some sort of network error";    case TFTP_INVALID:        return "invalid parameter";    case TFTP_PROTOCOL:        return "protocol violation";    case TFTP_TOOLARGE:        return "file is larger than buffer";    }    return errmsg;}//// RedBoot interface//GETC_IO_FUNCS(tftp_io, tftp_stream_open, tftp_stream_close,              0, tftp_stream_read, tftp_error);RedBoot_load(tftp, tftp_io, true, true, 0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -