📄 huahtftp.lib
字号:
/*
* tftp.lib
*
* Copyright (C) Z-World, Inc. All rights reserved.
*
* Trivial File Transfer Protocol (TFTP)
* Based on RFCs:
* 783 'THE TFTP PROTOCOL (REVISION 2)'
*
*/
/* START LIBRARY DESCRIPTION *********************************************
TFTP.LIB
Copyright (c) 2001, ZWorld.
DESCRIPTION:
Trivial File Transfer Protocol.
This standard protocol (internet RFC783) is a lighweight protocol
typically used to transfer bootstrap or configuration files from
a server to a client host such as a diskless workstation. TFTP
allows data to be sent in either direction between client and server,
using UDP as the underlying transport.
This library fully implements TFTP, but as a client only.
Compared with more capable protocols such as FTP, TFTP:
. has no security or authentication
. is not as fast because of the step-by-step protocol
. uses fewer machine resources.
Because of the lack of authentication, most TFTP servers restrict
the set of accessible files to a small number of configuration files
in a single directory. For upload of files, servers are usually
configured to accept only certain file names that are writable by
any user.
If these restrictions are acceptable, TFTP has the advantage of
requiring very little 'footprint' in the client host. In conjunction
with DHCP/BOOTP (see BOOTP.LIB), and appropriate server configuration,
TFTP is often used to download a kernel image to a diskless host.
The target TCP/IP board does not currently support loading the BIOS
in this way, since the BIOS and application program are written to
non-volatile flash memory. However, the downloaded file does not
have to be a binary executable - it can be any reasonably small file
such as an application configuration file. TFTP and DHCP/BOOTP can
thus be used to administer the configuration of multiple targets from
a central server.
Using TFTP with BOOTP/DHCP requires minimal additional effort for
the programmer. See the sample program samples\tcpip\dhcp_bootfile.c
for an example of this use.
The Dynamic C TFTP library contains the following functions. Any of
these functions will require approximately 600-800 bytes of free
stack. The data buffer for the file to put or get is always
allocated in xmem (see xalloc()). The tftp_struct structure, which
is required for most of these functions, may be allocated either
in root data memory or in xmem. The tftp_struct structure is
approximately 155 bytes long.
tftp_init() Prepare for a TFTP session
tftp_initx() Prepare for a TFTP session
tftp_tick() Execute one non-blocking step in the TFTP session
tftp_tickx() Execute one non-blocking step in the TFTP session
tftp_exec() Prepare and execute a complete TFTP session, blocking
until complete.
A session can be either a single download (get) or upload (put).
The functions ending with 'x' are versions which use a data structure
allocated in extended memory, for applications which are constrained
in their use of root data memory.
END DESCRIPTION **********************************************************/
/*** BeginHeader */
#ifdef TFTP_DEBUG
#define _tftp_nodebug debug
#else
#define _tftp_nodebug nodebug
#endif
/*
* UDP well-known port number for TFTP server.
*/
#define IPPORT_TFTP 69
// Initial timeout value in milliseconds - default 3/4 sec. Will double every retry.
#ifndef TFTP_TIMEOUT
#define TFTP_TIMEOUT 750
#endif
// Number of times to retransmit same packet after successive timeouts
// before giving up.
#ifndef TFTP_RETRIES
#define TFTP_RETRIES 5
#endif
// TFTP opcodes - for efficiency, these are in (16-bit) network order
#define TFTP_OP_RRQ 0x0100
#define TFTP_OP_WRQ 0x0200
#define TFTP_OP_DATA 0x0300
#define TFTP_OP_ACK 0x0400
#define TFTP_OP_ERROR 0x0500
// TFTP Client Mode - By wangtao to support large file!
#define TFTP_BLOCK_MODE 0x80 /// One 512Bytes block!
#define TFTP_FILE_MODE 0x40 /// Whole file!
#define TFTP_USER_COPY 0x01 /// User defined data copiers!
#define DATA_IN 0x01
#define DATA_OUT 0x02
// Packet structure used by TFTP
typedef struct tftp_packet {
word opcode;
union {
char name_and_mode[514]; // For RRQ or WRQ
struct {
word blocknum;
char data[512];
} d; // For DATA or ACK
struct {
word errorcode;
char errmsg[512];
} e; // For ERROR
} u;
};
/*
* structure for send and receives
*/
typedef struct tftp_state {
int (*udhandler)(); /// user data handler! by wangtao !
unsigned char tcmode; /// TFTP Client Mode!
byte state; // Current state. LSB indicates read(0) or write(1). Other bits
// determine state within this:
#define TFTP_ST_INIT 0 // Initial (sending RRQ/WRQ)
#define TFTP_ST_WAIT 2 // Waiting for response (data if read, ack if write)
#define TFTP_ST_DONE 4 // Finished.
#define TFTP_ST_RETRY 6 // Resending previous packet (transient state)
long buf_addr; // Physical address of buffer
unsigned long buf_len; // Length of buffer! by wangtao !
unsigned long buf_used; // Amount Tx or Rx from/to buffer! by wangtao
word next_blk; // Next expected block number, or next to Tx
word my_tid; // UDP port number used by this host
udp_Socket * sock; // UDP socket to use
longword rem_ip; // IP address of remote host
longword timeout; // ms timer value for next timeout
char retry; // retransmit retry counter
char flags; // misc flags
#define TFTP_F_EXIT 0x01 // Exit from receive processing flag
#define TFTP_F_TRUNC 0x02 // Received file truncated
long sbufaddr; // Socket buffer address (0 if use UDP socket buffer pool)
word sbuflen; // Socket buffer length.
// Following fields not used after initial request has been acknowledged.
char mode; // Translation mode as follows:
#define TFTP_MODE_NETASCII 0 // ASCII text
#define TFTP_MODE_OCTET 1 // 8-bit binary
#define TFTP_MODE_MAIL 2 // Mail (remote file name is email address e.g. user@host.blob.org)
char file[129]; // File name on remote host (TFTP server) - null terminated.
// This field will be overwritten with a null-term error message from the
// sever if an error occurs.
};
/*** EndHeader */
/*** BeginHeader tftp_init, tftp_tick */
int tftp_init(struct tftp_state * ts);
int tftp_tick(struct tftp_state * ts);
/*** EndHeader */
/* START FUNCTION DESCRIPTION ********************************************
tftp_init <TFTP.LIB>
SYNTAX: int tftp_init(struct tftp_state * ts);
PARAMETER1: Pointer to TFTP state. This must have been set up according
to the description here.
KEYWORDS: tcpip dhcp bootp tftp
DESCRIPTION: This function is called to complete initialisation of the
TFTP state structure. Before calling this function, some
fields in the struct tftp_state must be set up as follows:
ts->state = <0 for read, 1 for write>
ts->buf_addr = <physical address of xmem buffer>
ts->buf_len = <length of physical buffer, 0-65535>
ts->my_tid = <UDP port number. Set 0 for default>
ts->sock = <address of UDP socket (udp_Socket *)>
ts->rem_ip = <IP address of TFTP server host>
ts->mode = <one of the following constants:
TFTP_MODE_NETASCII ASCII text
TFTP_MODE_OCTET 8-bit binary
TFTP_MODE_MAIL Mail>
strcpy(ts->file, <remote filename or mail address>)
Note that mail mode can only be used to write mail to
the TFTP server, and the file name is the email address
of the recipient. The mail message must be ASCII-encoded
and formatted with RFC822 headers.
RETURN VALUE: 0: OK
-4: Error, socket NULL.
-7: Server address zero.
SEE ALSO: tftp_tick, tftp_exec, tftp_initx, tftp_tickx
END DESCRIPTION **********************************************************/
_tftp_nodebug int tftp_init(struct tftp_state * ts)
{
if (!ts->my_tid)
ts->my_tid = findfreeport(0, 0); // Next unused UDP port, non-privileged.
ts->retry = 0;
ts->flags = 0;
ts->state &= 0x01; // Isolate to initial state.
if (!ts->sock)
return -4;
if (!ts->rem_ip)
return -7;
return 0;
}
/* START FUNCTION DESCRIPTION ********************************************
tftp_tick <TFTP.LIB>
SYNTAX: int tftp_tick(struct tftp_state * ts);
PARAMETER1: Pointer to TFTP state. This must have been set up using
tftp_init(), and must be passed to each call of tftp_tick()
without alteration.
KEYWORDS: tcpip dhcp bootp tftp
DESCRIPTION: This function is called periodically in order to take the
next step in a TFTP process. Appropriate use of this
function allows single or multiple transfers to occur
without blocking. For multiple concurrent transfers,
there must be a unique tftp_state structure, and a unique
UDP socket, for each transfer in progress. This function
calls sock_tick().
RETURN VALUE: 1: OK, transfer not yet complete.
0: OK, transfer complete
-1: Error from remote side, transfer terminated. In this
case, the ts_addr->file field will be overwritten with a
null-terminated error message from the server.
-2: Error, could not contact remote host or lost contact.
-3: Timed out, transfer terminated.
-4: (not used)
-5: Transfer complete, but truncated because buffer too
small to receive the complete file.
SEE ALSO: tftp_init, tftp_exec, tftp_initx, tftp_tickx
END DESCRIPTION **********************************************************/
_tftp_nodebug int tftp_tick(struct tftp_state * ts)
{
auto struct tftp_packet tp; // 516 bytes
auto char * p;
auto int status;
auto int udrc; /// by wangtao ! UserDataHandler's return code!
/// auto int len;
/// auto word newlen; by wangtao !
auto long len; /// by wangtao!
auto long newlen;
auto byte write;
auto byte state;
auto int retval;
#ifdef TFTP_ALLOW_BUG
auto int rh_bug;
#endif
write = ts->state & 0x01;
state = ts->state & 0xFE;
// Handle possible timeouts in states where waiting for response.
if (state == TFTP_ST_WAIT) {
if ((long)(MS_TIMER - ts->timeout) > 0) {
ts->retry++;
if (ts->retry > TFTP_RETRIES)
goto _tftp_return_timeout; // Timeout and all retries exhausted.
if (!ts->next_blk)
state &= 0x01; // Go to reinit state temporarily
else
state |= 0x06; // Go to retry state temporarily
}
}
switch (state) {
case TFTP_ST_INIT:
#ifdef TFTP_VERBOSE
printf("TFTP INIT\r\n");
#endif
tp.opcode = write ? TFTP_OP_WRQ : TFTP_OP_RRQ;
strcpy(tp.u.name_and_mode, ts->file);
switch(ts->mode) {
case TFTP_MODE_NETASCII:
p = "netascii"; break;
case TFTP_MODE_MAIL:
p = "mail"; break;
default:
p = "octet";
}
newlen = strlen(ts->file) + 1;
strcpy(tp.u.name_and_mode + (word)newlen, p);
newlen += strlen(p) + 1 + 2;
#ifdef TFTP_ALLOW_BUG
rh_bug = 0;
#endif
// Open to well-known port
if(udp_waitopen(ts->sock, IF_ANY, ts->my_tid, ts->rem_ip, 0, NULL, 0, 0, 1000) <= 0)
goto _tftp_return_openerr; // ARP couldn't resolve the IP address within 1sec.
// Send initial packet to his well-known port. He will reply
// from a different port, which we will later "bind to" on this
// socket.
udp_sendto(ts->sock, (byte *)&tp, (word)newlen, ts->rem_ip, IPPORT_TFTP);
ts->timeout = MS_TIMER + (TFTP_TIMEOUT << ts->retry);
ts->buf_used = 0;
ts->next_blk = 0;
ts->state = TFTP_ST_WAIT + write;
break;
case TFTP_ST_RETRY:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -