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

📄 tftputil.c

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

   Copyright 1998-1999 by InterNiche Technologies, Inc. All rights reserved.
   Copyright 1995 by NetPort Software.
   Copyright 1986 by Carnegie Mellon
   Copyright 1984 by the Massachusetts Institute of Technology
*/

#include "tftpport.h"

#include "tftp.h"

/* internal routine */
static void check_state(struct tfconn * cn);

struct tfconn * tftp_conns = NULL;   /* list of active connections */

int ntftps = 0;   /* number of connections */

/* Setup a TFTP connection block. */

struct tfconn * 
tfmkcn(void)
{
struct tfconn * cn;

   cn = (struct tfconn *)TFC_ALLOC(sizeof(struct tfconn));
   if(!cn)
      return NULL;

   ntftps++;
   cn->next = tftp_conns;   /* add this tfconn to list */
   tftp_conns = cn;

   cn->tf_srtt = cn->tf_rt = TPS/2;   /* init round trip timer with large-ish guess */
   if (cn->tf_rt > TF_MAXTMO)
      cn->tf_rt = TF_MAXTMO;
   if (cn->tf_rt < TF_MINTMO)
      cn->tf_rt = TF_MINTMO;
   cn->tf_NR_last = 1;   /* fake last packet Number retrys */

   return cn;
}


/* Cleanup routine called when done */

void
tfcleanup(struct tfconn *cn)
{
struct tfconn * tmp, * last;

   /* unlink cn from list */
   tmp = tftp_conns;
   last = NULL;
   while(tmp)   /* traverse list, looking of cn to free */
   {
      if(tmp == cn)
      {
         if(last)   /* unlink from list */
            last->next = tmp->next;
         else   /* was first in list, fix list pointer */
            tftp_conns = tmp->next;
         break;
      }
      last = tmp;
      tmp = tmp->next;
   }
   if(!tmp)   /* connection not in master list? */
   {
      dtrap("tftputil 1\n");   /* serious prog error..... */
   }

   if(cn->tf_fd != NULL)
      vfclose(cn->tf_fd);
   if(cn->tf_outbuf.data)
      tftp_udpfree(cn);
   if(cn->tf_conn != 0)
      tftp_udpclose(cn->tf_conn);

   TFC_FREE(cn);
   ntftps--;
}


void 
tftptmo(struct tfconn * cn)
{
TFTPBUF p;

   cn->tf_tmo++;
   /* if we have more tries... */
   if((cn->tf_tries == 0) || (--cn->tf_tries))
   {
   int e;

      cn->tf_rsnd++;
      cn->tf_NR++;
      /* do the actual retry. Don't use tf_write() since it will re-init 
         the round trip & retry count values. */
      p = &cn->tf_outbuf;
      e = tftp_udpsend(cn, p->data, cn->tf_lastlen);
      if(e < 0)
      {
         if (cn->callback)
         {
            if (e == ENP_NOBUFFER)
               cn->callback(TFC_BUFFER, cn, "UDP alloc failed");
            else
               cn->callback(TFC_UDPSEND, cn, "UDP send failed");
         }
         tfkill(cn);    /* UDP send error, kill tftp session */
      }
      else  /* udp retry packet sent OK */
      {
         cn->tf_rt <<= 1;      /* double round trip est. */
         if (cn->tf_rt > TF_MAXTMO)
            cn->tf_rt = TF_MAXTMO;
         cn->tf_tick = cticks + cn->tf_rt;   /* set time to do next retry */
      }
   }
   else 
   {
      cn->tf_state = TIMEOUT;
   }
}

/* tf_good() - called to do timing calcs after good receives */

void
tf_good(struct tfconn * cn)
{
unsigned long trt;

   trt = cticks - cn->tf_sent;  /*  Measured round trip time  */
   /* set smoothed round trip time based on measured */
   if((cn->tf_srtt > trt) && (cn->tf_srtt > 1))
      cn->tf_srtt--;
   else if((cn->tf_srtt) < trt)
      cn->tf_srtt++;
   /* set the retry time: experimental algorithm: */
   trt = trt + cn->tf_srtt + 1;
   if (trt < TF_MINTMO)
      cn->tf_rt = TF_MINTMO;
   else if (trt > TF_MAXTMO)
      cn->tf_rt = TF_MAXTMO;
   else
      cn->tf_rt = trt;

   cn->tf_NR_last = cn->tf_NR;
   cn->tf_NR = 0;
}



/* tfdodata() - Process a data packet received for TFTP connection cn.
Handle out of sequence blocks and check on block length. If a block
is way to short (len < tftp header size) send back an error message
and abort the transfer. If the block is less than 512 bytes long, shut 
down the transfer; we're done. Otherwise, just write it to disk (if necessary).

Returns TRUE if OK, FALSE if error.
*/

int /* BOOL */
tfdodata(struct tfconn * cn,
   TFTPBUF p,
   unsigned len)
{
char * data;
struct tfdata *ptfdat;

   if(len < 4) 
   {
      tfsnderr(cn, ERRTXT, "Bad len (too short)");
      if (cn->callback)
         cn->callback(TFC_BADLEN, cn, "short data from peer");
      tfkill(cn);
      return FALSE;
   }

   if(cn->tf_state != DATAWAIT)
   {
      tfsnderr(cn, ERRTXT, "Rcvd unexpected data block");
      return FALSE;
   }

   /* point to tftp header at front of */
   ptfdat = (struct tfdata *) p->data;
   len -= 4;   /* subtract length of header from data */

   if(htons(ptfdat->tf_block) != cn->tf_expected)
   {

   /*   We got a retransmission of a packet we have already tried to
   ACK.  If we retransmit the ACK, and the old ACK finally gets through also,
   our correspondent will resend the next data block, and we will do the same
   thing for it, on through to the end of the file.  So we shouldn't retransmit
   the ACK until we are convinced that the first one was actually lost.  We will
   become convinced if our own timeout waiting for the next data packet
   expires.  */

      cn->tf_ous++;   
      return FALSE;
   }
   tf_good(cn);   /* adjust timer values */

   cn->tf_size += len;
   cn->tf_flen = len;

   /* write UDP data into file */
   data = ptfdat->tf_data;
   if((int)vfwrite(data, 1, len, cn->tf_fd) != (int)len)
   {
      tf_full(cn);
      return FALSE;
   }
   
   /* Send the ack & move to next state */
   tfsndack(cn);
   if(len == NORMLEN) 
      cn->tf_state = DATAWAIT;
   else    /* sub-normal len (less than 512) indicates end of file */
      cn->tf_state = RCVLASTDATA;

   cn->tf_expected++;
   return TRUE;
}

/*  Handle disk full condition by sending error packet and killing
    this connection.  */
void
tf_full(struct tfconn *cn)
{
   tfsnderr(cn, DISKFULL, " ");
   tfkill(cn);   
   if(cn->callback)
       cn->callback(TFC_DISKFULL, cn, tferrors[DISKFULL] );
}

/* Send an error packet. If the code is nonzero, put it in the packet.
   Otherwise, copy the text into the packet. */

char * tferrors[] = 
{
   "See text",
   "File not found",
   "Access violation",
   "Disk full",
   "Illegal TFTP operation",
   "Unknown transfer ID",
   "File already exists",
   "No such user"
};

void
tfsnderr(struct tfconn * cn,
   unsigned code,
   char *text)
{
unsigned len;
struct tferr *perr;

   len = sizeof(struct tferr)-2;

   tftp_udpbuffer(cn, sizeof(struct tfack) );
   if(cn->tf_outbuf.data == NULL)
      return;

   perr = (struct tferr *)(cn->tf_outbuf.data);
   perr->tf_op = htons(TF_ERROR);
   perr->tf_code = htons(code);

   if(code == ERRTXT)
   {
      strcpy(perr->tf_err, text);
      len += strlen(text)+1;
   }
   else
   {
      strcpy(perr->tf_err, tferrors[code]);
      len += strlen(tferrors[code]) + 1;
   }
   tftp_udpsend(cn, perr, len);
   tftp_udpfree(cn);    /* free now, there are no retrys on these */
}

/* Process an incoming error packet */

void
tfdoerr(struct tfconn *cn, TFTPBUF p, unsigned len)
{
struct tferr * perr;
int tferror;   /* tftp protocol error */
char * errtxt;   /* text of/for error */

   /* if connection is dead, don't worry about this... */
   if(cn->tf_state == DEAD || cn->tf_state == TERMINATED)
      return;

   tfkill(cn);

   perr = (struct tferr *) p->data;   /* overlay tftp error packet struct */
   tferror = htons(perr->tf_code);      /* get tftp error code (see rfc) */
   if(tferror > 0 && tferror < 8)      /* check for known range of errors */
      errtxt = tferrors[tferror];      /* get text from array if known error */
   else   /* not know error, try to extract text from tftp packet */
   {
      errtxt = perr->tf_err;
      if(*errtxt <= ' ' || *errtxt & 0x80 || (strlen(errtxt) > 100))   /* make sure it's printable */
         errtxt = "bogus tftp error text";
   }
   if(cn->callback)

⌨️ 快捷键说明

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