?? tftputil.c
字號:
cn->callback(TFC_FOREIGN, cn, errtxt);
USE_ARG(len);
}
/* tfsndack() - build and send ack for latest block */
int
tfsndack(struct tfconn *cn)
{
struct tfack * pack;
int e;
tftp_udpbuffer(cn, sizeof(struct tfack) );
if(cn->tf_outbuf.data == NULL)
return ENP_NOBUFFER;
pack = (struct tfack *)(cn->tf_outbuf.data);
cn->tf_lastlen = sizeof(struct tfack);
pack->tf_op = TF_ACK; /* in local endian, tf_write will fix */
pack->tf_block = cn->tf_expected;
e = tf_write(cn, sizeof(struct tfack)); /* send the ack */
return e;
}
/* tf_write() - write (send) a tftp packet to the other host */
int
tf_write(struct tfconn * cn, unsigned len)
{
struct tfack * packet;
packet = (struct tfack *)(cn->tf_outbuf.data);
if(packet == NULL)
{
dtrap("tftputil 2\n"); /* prog error */
return ENP_NOBUFFER;
}
if(packet->tf_op != TF_RRQ && packet->tf_op != TF_WRQ)
{
packet->tf_block = htons(packet->tf_block);
cn->tf_tries = TFTPTRIES;
}
else
cn->tf_tries = REQTRIES;
packet->tf_op = htons(packet->tf_op); /* convert op to net format */
cn->tf_lastlen = len;
cn->tf_snt++;
cn->tf_sent = cticks;
cn->tf_tick = cticks + cn->tf_rt; /* set time to retry */
cn->tf_NR = 1;
return(tftp_udpsend(cn, cn->tf_outbuf.data, len));
}
/* Send a TFTP data block. */
int
tfsndata(struct tfconn *cn)
{
struct tfdata * tfdata;
int bytes = 0; /* bytes read from file */
int err;
tftp_udpbuffer(cn, NORMLEN + sizeof(struct tfdata) );
if(cn->tf_outbuf.data == NULL)
return ENP_NOBUFFER;
tfdata = (struct tfdata *) (cn->tf_outbuf.data);
tfdata->tf_op = TF_DATA;
tfdata->tf_block = cn->tf_expected;
/* load file data into tftp buffer */
if(!cn->tf_NR) /* if this is NOT a retry, read in new data */
{
bytes = vfread(tfdata->tf_data, 1, NORMLEN, cn->tf_fd); /* read next block from file */
if(bytes < NORMLEN) /* end of file? */
{
if(vferror(cn->tf_fd)) /* see if it;'s an error */
{
if(cn->callback)
cn->callback(TFC_FILEREAD, cn, "file read error");
return FALSE;
}
/* else at End Of File; fall through to do last send */
}
cn->tf_flen = bytes; /* bytes in last packet sent */
cn->tf_size += bytes; /* total bytes sent so far */
}
else
{ dtrap("tftputil 3\n"); /* can this happen? */
}
err = tf_write(cn, sizeof(struct tfdata)-512+bytes); /* send the data block */
if(err == 0) /* if sent OK, wait for reply */
{
if(cn->tf_flen == NORMLEN) /* this a full sized block? */
cn->tf_state = ACKWAIT; /* yes, normal wait for ack */
else
cn->tf_state = SENTLAST; /* no, this is last block to send */
}
else /* else kill connection */
{
if (cn->callback)
{
if (err == ENP_NOBUFFER)
cn->callback(TFC_BUFFER, cn, "UDP alloc failed");
else
cn->callback(TFC_UDPSEND, cn, "UDP send failed");
}
tfkill(cn);
}
return err;
}
/* Handle an incoming ack. */
void
tfdoack(struct tfconn *cn)
{
struct tfack *ack;
TFTPBUF p = &cn->tf_inbuf;
ack = (struct tfack *)(p->data);
if(htons(ack->tf_block) != cn->tf_expected)
{/* We have received an ACK,
but not for the data block we sent. It must be for
a duplicate, since we wouldn't have sent
the current data block if we hadn't gotten an ACK for
the previous one. This duplicate ACK means either
that the network resent a packet that it wasn't sure
got through, or else the other end resent the ACK
because our current data block is lost or late.
In either case, we can safely ignore this extra ACK,
and if the ACK we want doesn't come our own timer will
get us started again. It isn't safe
to resend the current data block now unless we are
absolutely certain that the other end won't reack
it if the earlier send was just delayed. */
cn->tf_ous++;
}
else
{
tf_good(cn);
/* If ack was for last packet, we are done with this connection */
if(cn->tf_state == SENTLAST)
{
cn->tf_state = TERMINATED;
}
else
cn->tf_state = RCVACK;
tftp_udpfree(cn); /* free acked data bufffer */
cn->tf_expected++; /* ready to do next block */
}
}
/* tftprcv() - Handle an incoming TFTP packet.
This is upcalled from the tftpudp.c code which handles UDP semantics.
Note that contents of cn->tf_inbuf are only good for the duration of this
upcall.
*/
void
tftprcv(struct tfconn *cn, unshort fport)
{
TFTPBUF p;
struct tfdata * pdata;
unshort op;
unsigned len;
p = &cn->tf_inbuf; /* data is in connection's buffer */
len = p->dlen; /* size of received data in buffer */
/* If tf_fport is still not set, this should be ack for first block */
if(cn->tf_fport == TFTPPORT)
{
struct tfack * ack = (struct tfack *)(p->data);
if(htons(ack->tf_block) <= 1) /* only do this on first block */
cn->tf_fport = fport; /* set port from upcalled value */
}
cn->tf_rcv++;
pdata = (struct tfdata *) (p->data);
op = htons(pdata->tf_op);
pdata->tf_op = op;
switch(op)
{
case TF_RRQ: /* retry of original req? */
case TF_WRQ:
break; /* silently ignore... */
case TF_DATA:
tfdodata(cn, p, len);
break;
case TF_ACK:
tfdoack(cn);
break;
case TF_ERROR:
tfdoerr(cn, p, len);
break;
default:
dtrap("tftputil 4\n"); /* printf("TFTPRCV: Got bad opcode %u.\n", op); */
tfsnderr(cn, ILLTFTP, " ");
break;
}
check_state(cn); /* see if we need to send something */
return;
}
void
tfkill(struct tfconn * cn)
{
cn->tf_state = DEAD; /* will get cleaned up later */
cn->tf_tick = cticks + TPS; /* clean up after one second */
}
/* the tftp task/superloop handler. This scans all tftp connections to
see if any states have timed out. This should be called on every
received tftp packet and 1 second timer.
*/
static int in_tftp_tick = 0; /* re-entry guard */
void
tftp_tick(void)
{
struct tfconn * cn, * nextcn;
if(in_tftp_tick) /* avoid re-entring */
return;
in_tftp_tick++;
for(cn = tftp_conns; cn; cn = nextcn)
{
nextcn = cn->next; /* in case cn is deleted in check_state */
if(cn->tf_tick > cticks) /* time for state check? */
continue;
check_state(cn);
}
in_tftp_tick--;
}
void
check_state(struct tfconn * cn)
{
char * msg;
/* prevent clock ticks from re-entering. Do not exit
this routine without decrementing this counter! */
in_tftp_tick++;
switch (cn->tf_state)
{
case DATAWAIT: /* waiting for data? */
case ACKWAIT: /* waiting for ack? */
case SENTLAST: /* sent last data block? */
if(cn->tf_tick <= cticks) /* timeout now? */
tftptmo(cn);
break;
case TIMEOUT:
tfsnderr(cn, ERRTXT, "Retry limit exceeded, giving up");
if (cn->callback)
cn->callback(TFC_TIMEOUT, cn, "retry limit exceeded");
tfkill(cn);
break;
case RCVLASTDATA: /* receive last incoming block of file */
case TERMINATED: /* sent last outgoing block of file */
if(cn->callback)
{
if(cn->tf_size == 0L)
cn->callback(TFC_ZEROFILE, cn, "zero length file");
else
{
unsigned secs, tenths, elapsed;
msg = cn->tf_inbuf.data;
elapsed = (unsigned)(cticks - cn->tf_start); /* elapsed ticks for transfer */
secs = elapsed/TPS; /* round down to number of whole seconds */
tenths = ((unsigned)(cticks - cn->tf_start) - (secs*TPS))/2; /* approximate 10ths of a second */
sprintf_t(msg, "Transferred %lu bytes in %u.%u seconds",
cn->tf_size, secs, tenths);
cn->callback(TFC_SUCCESS, cn, msg);
}
}
cn->tf_state = DEAD;
break;
case RCVACK: /* got an ack */
tfsndata(cn); /* send more data */
break;
case RCVDATA:
tfsndack(cn);
break;
case DEAD:
tfcleanup(cn);
break;
default:
dtrap("tftputil 5\n"); /* bad state */
if (cn->callback)
cn->callback(TFC_BADSTATE, cn, " ");
tfkill(cn);
break;
}
in_tftp_tick--;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -