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

📄 tftputil.c

📁 在ARM7和UC/OSII的平台上实现了GPS自动报站的功能,涉及GPS模块LEA_4S的驱动,位置速寻算法,语音芯片ISD4004的录放音驱动,LED页面管理等等.从启动代码到操作系统的移植以及到业
💻 C
📖 第 1 页 / 共 2 页
字号:
       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 + -