📄 huahtftp.lib
字号:
#ifdef TFTP_VERBOSE
printf("TFTP: retry\n");
#endif
if (write)
goto _tftp_resend_data;
else
goto _tftp_resend_ack;
case TFTP_ST_WAIT:
tcp_tick(NULL);
len = udp_recv(ts->sock, (byte *)&tp, sizeof(tp));
if (len == -1)
break;
if (len < 0)
goto _tftp_sock_err;
if (len < 4)
break; // Min TFTP packet is 4 bytes; ignore less.
len -= 4; // Reduce len to actual data length
// Reverse blocknum
tp.u.d.blocknum = intel16(tp.u.d.blocknum);
#ifdef TFTP_VERBOSE
printf("TFTP got opc=%d blk=%d length=%d\r\n", intel16(tp.opcode), tp.u.d.blocknum, len);
#endif
switch (tp.opcode) {
case TFTP_OP_DATA:
if (write)
break; // Ignore data packets if writing
if (tp.u.d.blocknum != ts->next_blk+1) // Ignore if not expected block
break;
ts->retry = 0; // Reset retry counter, since got data
if (len < 512) // TFTP last data packet
ts->flags |= TFTP_F_EXIT;
newlen = ts->buf_used + len; // Total length of data obtained
if ( (ts->udhandler == NULL) || ((ts->tcmode & TFTP_USER_COPY) == 0) )
{
if (newlen < ts->buf_used || newlen > ts->buf_len) { // Buffer overflow?
len = ts->buf_len - ts->buf_used;
ts->flags |= TFTP_F_TRUNC | TFTP_F_EXIT;
}
if (len > 0) {
root2xmem(ts->buf_addr + ts->buf_used, tp.u.d.data, (unsigned)len);
ts->buf_used += len;
}
if (ts->udhandler != NULL)
udrc = ts->udhandler(ts, &len, DATA_IN); /// by wangtao !
}
else if ( (ts->udhandler != NULL)&&(ts->tcmode & TFTP_USER_COPY) ) /// by wangtao !
{
if (len > 0) {
root2xmem(ts->buf_addr, tp.u.d.data, (unsigned)len);
ts->buf_used += len;
}
udrc = ts->udhandler(ts, &len, DATA_IN); /// by wangtao !
}
ts->next_blk++;
_tftp_resend_ack:
// Send an ACK for last block seen
tp.opcode = TFTP_OP_ACK;
tp.u.d.blocknum = intel16(ts->next_blk);
udp_send(ts->sock, (byte *)&tp, 4);
#ifdef TFTP_VERBOSE
printf("TFTP sent ack blk=%d\r\n", ts->next_blk);
#endif
ts->timeout = MS_TIMER + (TFTP_TIMEOUT << ts->retry);
// If len is < 512, then transmission is finished, either because a short packet was
// transmitted, or because our own buffer was filled. Really, we should linger on
// to make sure that server doesn't retransmit the last packet (indicating that it
// didn't get our ACK), but no great loss if we don't...
if ( ts->flags & TFTP_F_EXIT)
goto _tftp_return_complete;
if ( (ts->udhandler != NULL) && (udrc != 0) ) /// by wangtao !
goto _tftp_return_complete;
break;
case TFTP_OP_ACK:
if (!write)
break; // Ignore ack packets if reading
#ifdef TFTP_ALLOW_BUG
// Some versions of tftp server (e.g. RH Linux 7.0) had bug where 1st block was set to
// 1 instead of 0. Try to hack around this. A very bad hack - don't use it!
if (tp.u.d.blocknum == 1 && !ts->next_blk)
rh_bug = 1;
if ( //!(tp.u.d.blocknum == 1 && !ts->next_blk) &&
tp.u.d.blocknum != ts->next_blk + rh_bug) // Ignore if not expected block
break;
#else
if (tp.u.d.blocknum != ts->next_blk) // Ignore if not expected block
break;
#endif
ts->retry = 0; // Reset retry counter, since got acknowledgement
if (ts->next_blk) {
ts->buf_used += 512;
if (ts->buf_used > ts->buf_len || !ts->buf_used)
goto _tftp_return_complete;
}
ts->next_blk++;
_tftp_resend_data:
////////////adde by wangtao to support userdatahandler !
if ( (ts->udhandler == NULL) || ( (ts->tcmode & TFTP_USER_COPY) == 0) )
{
len = ts->buf_len - ts->buf_used;
if (len < 0 || len > 512) len = 512; // Max size block
if (len > 0)
xmem2root(tp.u.d.data, ts->buf_addr + ts->buf_used, (unsigned)len);
if (ts->udhandler != NULL)
udrc = ts->udhandler(ts, &len, DATA_OUT); /// by wangtao !
}
else if ( (ts->udhandler != NULL) && (ts->tcmode & TFTP_USER_COPY) )
{
udrc = ts->udhandler(ts, &len, DATA_OUT);
if (len < 0 || len > 512)
len = 512; // Max size block
if (len > 0)
xmem2root(tp.u.d.data, ts->buf_addr, (unsigned)len);
}
tp.opcode = TFTP_OP_DATA;
tp.u.d.blocknum = intel16(ts->next_blk);
udp_send(ts->sock, (byte *)&tp, (unsigned)(len+4) );
#ifdef TFTP_VERBOSE
printf("TFTP sent data blk=%d len=%d\r\n", ts->next_blk, len);
#endif
ts->timeout = MS_TIMER + (TFTP_TIMEOUT << ts->retry);
break;
case TFTP_OP_ERROR:
tp.u.e.errmsg[127] = 0; // Truncate to 127 chars
#ifdef TFTP_VERBOSE
printf("TFTP Error: code=%d msg=%s\r\n", intel16(tp.u.e.errorcode), tp.u.e.errmsg);
#endif
strcpy(ts->file, tp.u.e.errmsg);
goto _tftp_return_tftperr;
default:
break;
} // switch on opcode
break;
default:
return 0;
} // switch on state
// Indicate not yet complete
return 1;
_tftp_return_tftperr:
retval = -1;
goto _tftp_bye;
_tftp_return_timeout:
retval = -3;
goto _tftp_bye;
_tftp_sock_err:
_tftp_return_openerr:
retval = -2;
goto _tftp_bye;
_tftp_return_complete:
retval = 0;
if (ts->flags & TFTP_F_TRUNC)
retval = -5;
else if ( ( ts->udhandler != NULL) && (udrc != 0) )
retval = udrc;
_tftp_bye:
ts->state = TFTP_ST_DONE;
sock_close((sock_type *)ts->sock);
return retval;
}
/*** BeginHeader tftp_initx, tftp_tickx */
int tftp_initx(long ts_addr);
int tftp_tickx(long ts_addr);
/*** EndHeader */
/* START FUNCTION DESCRIPTION ********************************************
tftp_initx <TFTP.LIB>
SYNTAX: int tftp_initx(long ts_addr);
PARAMETER1: Physical address of TFTP state (struct tftp_state).
KEYWORDS: tcpip dhcp bootp tftp
DESCRIPTION: This function is called to complete initialisation of the
TFTP state structure, where the structure is possibly
stored somewhere other than in the root data space.
This is a wrapper function for tftp_init(). See that
function description for details.
RETURN VALUE: 0: OK
-1: Error, default socket in use.
SEE ALSO: tftp_tick, tftp_exec, tftp_init, tftp_tickx
END DESCRIPTION **********************************************************/
_tftp_nodebug int tftp_initx(long ts_addr)
{
auto struct tftp_state ts;
auto int rc;
xmem2root(&ts, ts_addr, sizeof(ts));
rc = tftp_init(&ts);
root2xmem(ts_addr, &ts, sizeof(ts));
return rc;
}
/* START FUNCTION DESCRIPTION ********************************************
tftp_tickx <TFTP.LIB>
SYNTAX: int tftp_tickx(long ts_addr);
PARAMETER1: Physical address of TFTP state (struct tftp_state).
KEYWORDS: tcpip dhcp bootp tftp
DESCRIPTION: This function is a wrapper for calling tftp_tick(), where
the structure is possibly stored somewhere other than in
the root data space. See that function description for
details.
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_tick
END DESCRIPTION **********************************************************/
_tftp_nodebug int tftp_tickx(long ts_addr)
{
auto struct tftp_state ts;
auto int rc;
xmem2root(&ts, ts_addr, sizeof(ts));
rc = tftp_tick(&ts);
root2xmem(ts_addr, &ts, sizeof(ts));
return rc;
}
/*** BeginHeader tftp_exec */
int tftp_exec( char write, long buf_addr, word * len, int mode,
char * host, char * hostfile, udp_Socket * sock );
/*** EndHeader */
/* START FUNCTION DESCRIPTION ********************************************
tftp_exec <TFTP.LIB>
SYNTAX: int tftp_exec( char put, long buf_addr, word * len, int mode,
char * host, char * hostfile, udp_Socket * sock );
PARAMETER1: 0: get file from remote host; 1: put file to host.
PARAMETER2: physical address of data buffer.
PARAMETER3: length of data buffer. This is both an input and a return
parameter. It should be initialised to the buffer
length. On return, it will be set to the actual length
received (for a get), or unchanged (for a put).
PARAMETER4: Data representation: 0=NETASCII, 1=OCTET (binary), 2=MAIL.
PARAMETER5: Remote host name.
PARAMETER6: Name of file on remote host, or email address for mail.
PARAMETER7: UDP socket to use
KEYWORDS: tcpip dhcp bootp tftp
DESCRIPTION: This function is a wrapper for tftp_init() and tftp_tick().
It does not return until the complete file is transferred
or an error occurs. Note that approximately 750 bytes of
free stack will be required by this function.
RETURN VALUE: 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: sock parameter was NULL
-7: host was NULL
SEE ALSO: tftp_init, tftp_initx, tftp_tick, tftp_tickx
END DESCRIPTION **********************************************************/
_tftp_nodebug
int tftp_exec( char put, long buf_addr, word * len, int mode,
char * host, char * hostfile, udp_Socket * sock )
{
auto struct tftp_state ts;
auto int status;
ts.state = put ? 1 : 0;
ts.buf_addr = buf_addr;
ts.buf_len = *len;
if (!put)
*len = 0;
ts.my_tid = 0; // Find an unused one
ts.sock = sock;
if (host) {
ts.rem_ip = resolve(host);
if (!ts.rem_ip) return -2; // Host not resolved
}
else
return -7;
ts.mode = mode;
strcpy(ts.file, hostfile);
// Now do the transfer
status = tftp_init(&ts);
if (status) return status;
while ((status = tftp_tick(&ts)) == 1); // Loop until complete or error
if (!put)
*len = ts.buf_used;
return status;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -