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

📄 drv_tftp.c

📁 tftp在vxWorks上的实现
💻 C
字号:
#include "vxWorks.h"                /* always first */
#include "config.h"                 /* board support configuration header */
#include "typedef.h"
#include "Drv_Tftp.h"
#include "../board/Minip/Drv_Minip.h"
#include "../bsp.h"

#define  DRV_TFTP_DEBUG     0

extern int taskDelay (int ticks);
extern void sysMsDelay(_U32 delay);

/**************************************************************************
 * Function:       LOAD_TftpMakeReqPkt
 * Description:    组装TFTP包
 * Input:   usOpcode:   操作码
            szFileName: TFTP服务器上的文件名。
            lMode:     TFTP传输方式
            pstPacket: 组装完成后的TFTP包
 * Output:         None
 * Return:         return 0 if succeed, return others if fail.
 * Others:
**************************************************************************/
long LOAD_TftpMakeReqPkt(_U16 usOpcode, _U8 *szFileName, long lMode,
                                 LOAD_TFTP_PACKET_S *pstPacket)
{
    _U8 *pCp;

    if (pstPacket == NULL )
    {
        return (long)FAILURE;
    }

    if( usOpcode != LOAD_TFTP_RRQ && usOpcode != LOAD_TFTP_WRQ )
    {
        return (long)FAILURE;
    }
    if ( (lMode != LOAD_TFTP_TRANSFER_MODE_ASCII)
       &&(lMode != LOAD_TFTP_TRANSFER_MODE_BINARY) )
    {
        return (long)FAILURE;
    }

    pstPacket->usOpcode = htons((_U16)usOpcode);
    pCp = (_U8*)(pstPacket->uMsg.szName_Mode);
    strcpy((char *)pCp, (char *)szFileName);
    pCp += strlen((char *)szFileName);
    *pCp++ = '\0';
    if (lMode == LOAD_TFTP_TRANSFER_MODE_ASCII)
    {
        strcpy((char *)pCp,"netascii");
    }
    else
    {
        strcpy((char *)pCp,"octet");
    }
    pCp += strlen((char *)pCp);
    *pCp++ = '\0';

    return ((long)pCp - (long)pstPacket);
}

/**************************************************************************
 * Function:       LOAD_TftpGet
 * Description:    从TFTP服务器获取文件
 * Input:   szRmtHost:    TFTP服务器的IP地址字符串。
            szRmtFile:    TFTP服务器上的文件名。
            szLocalFile: 本地硬盘或Flash上的文件名。
            lTransMode:   TFTP传输方式
            ulUserID:    执行此远程下载命令的用户的标识。
 * Output:         None
 * Return:         return 0 if succeed, return others if fail.
 * Others:
**************************************************************************/
_U32 LOAD_TftpGet(_U8 *szRmtHost, _U8 *szRmtFile, _U8 *szRamAddr, long lTransMode)
{

    long lSockNum;
    struct sockaddr_in stClientAddr, stServerAddr;
    long lEn;
    LOAD_TFTP_PACKET_S stRcvPkt, stSndPkt;
    long lPktSize = 0;
    long lFromLen;
    struct timeval stTimeout;
    long lTotTime = 0;
    long lRc;
    _U16 usCurBlkNum = 1;
    int i;
    struct timeval pasttv;

    if(( szRmtHost == NULL )||( szRmtFile == NULL )||( szRamAddr == NULL ))
    {
        Drv_Print("\r\nInput param error!");
        return FAILURE;
    }

    stTimeout.tv_sec    = LOAD_TFTP_TIMEOUT_TIME;
    stTimeout.tv_usec   = 0;

    /*creat a socket*/
    if((lSockNum = minip_socket(MINIP_AF_INET, MINIP_SOCK_DGRAM, 0)) <= 0)
    {
#if DRV_TFTP_DEBUG
        Drv_Print( "\r\nSocket initialize fail!\r\n");
#endif
        return FAILURE;
    }
#if DRV_TFTP_DEBUG
    Drv_Print( "\r\nSocket initialize finish!\r\n");
#endif
    /* specify a local address for this socket */
    memset((void *)&stClientAddr, 0 , sizeof(stClientAddr));
    stClientAddr.sin_family = MINIP_AF_INET;
    stClientAddr.sin_port   = htons(10240);     /* 最小协议栈不支持端口号动态分配 */

    stClientAddr.sin_addr.s_addr = htonl(MINIP_INADDR_ANY);
    lEn = minip_bind(lSockNum, (struct sockaddr *)(char *)&stClientAddr, sizeof(stClientAddr));
    if( lEn != 0 )
    {
#if DRV_TFTP_DEBUG
        Drv_Print("\r\nSocket bind failure!\r\n");
#endif
        goto exit1;
    }

    /* set server internet address*/
    memset((void *)&stServerAddr, 0 , sizeof(stServerAddr));
    stServerAddr.sin_family = MINIP_AF_INET;
    stServerAddr.sin_port   = htons(LOAD_TFTP_SERVER_PORT);
    stServerAddr.sin_addr.s_addr = minip_strtoip(szRmtHost);
    if(stServerAddr.sin_addr.s_addr == 0XFFFFFFFF)
    {
#if DRV_TFTP_DEBUG
        Drv_Print("\r\nCannot resolve hostname!\r\n");
#endif
        goto exit1;
    }


    /* form request packet - RRQ */
    lPktSize = LOAD_TftpMakeReqPkt(LOAD_TFTP_RRQ,szRmtFile,lTransMode,&stSndPkt);

    if (lPktSize <= 0)
    {
#if DRV_TFTP_DEBUG
        Drv_Print("\r\nLoad tftp create msg error = %ld!",lPktSize);
#endif
    }
    lFromLen = sizeof(stClientAddr);

#ifdef TCPIP_INCLUDE_MINIP
    /* 加载前先等待1秒 */
    (void)taskDelay(1);
#endif

    for(;;)
    {
        lEn = minip_sendto(lSockNum,(char *)&stSndPkt,(int)lPktSize,0,
                (struct sockaddr *)(char*)&stServerAddr,sizeof(stServerAddr));
        if(lEn != lPktSize)
        {
#if DRV_TFTP_DEBUG
            Drv_Print("\r\nhave sent %ld, need to send %ld",lEn,lPktSize);
            Drv_Print("\r\nCannot send require message to TFTP server, download fails!\r\n");
#endif
            (void)taskDelay(1);
            goto exit1;
        }

        /* wait for DATA packet */
        pasttv.tv_sec  = 0;
        pasttv.tv_usec = 0;
        for(i = 0; i < 6000; i ++)
        {
            sysMsDelay(1);
            (void)taskDelay(0);
            lEn = minip_recvfrom(lSockNum,(char *)&stRcvPkt,LOAD_TFTP_PKTSIZE,0,
                    (struct sockaddr *)(char *)&stClientAddr,(int*)&lFromLen);
            if(lEn > 0)
            {
                break;
            }
            pasttv.tv_usec += 1000;
            pasttv.tv_sec  += pasttv.tv_usec/(1000000);
            pasttv.tv_usec %= 1000000;
            if(pasttv.tv_sec >= stTimeout.tv_sec){
                break;
            }
        }
        if(lEn < 0)
        {
#if DRV_TFTP_DEBUG
            Drv_Print("\r\nDownload fails\r\n");
#endif
            goto exit1;
        }
        else if (lEn == 0)
        {
            lTotTime++;
            if (lTotTime < LOAD_TFTP_ATTEMPTS)
            {
                continue;
            }
            else
            {
#if DRV_TFTP_DEBUG
                Drv_Print("\r\nCannot receive message from TFTP server because of time out, download fails!\r\n");
#endif
                goto exit1;
            }
        }

        stServerAddr.sin_port = stClientAddr.sin_port;

        lTotTime = 0;

        /* packet size of received */
        lRc = lEn;

        /* convert network opcode to host format after receive. */
        stRcvPkt.usOpcode = ntohs(stRcvPkt.usOpcode);

        /* if this packet is OPT packet */
        if(stRcvPkt.usOpcode == LOAD_TFTP_OPT)
        {
            stSndPkt.usOpcode = htons(LOAD_TFTP_ACK);
            stSndPkt.uMsg.usBlkNum = htons(0);
            lPktSize = LOAD_TFTP_HDRSIZE;
            continue;
        }

        /* if this packet is ERROR packet */
        if(stRcvPkt.usOpcode == LOAD_TFTP_ERROR)
        {
#if DRV_TFTP_DEBUG
            Drv_Print("\r\nBad packet received from TFTP server, download fails!\r\n");
#endif
            goto exit1;
        }

        /* if this packet is unkonwn or incorrect packet */
        if(stRcvPkt.usOpcode != LOAD_TFTP_DATA)
        {
#if DRV_TFTP_DEBUG
            Drv_Print("\r\nUnkonwn or incorrect packet received from TFTP server, download fails!\r\n");
#endif
            goto exit1;
        }

        /* if this packet is DATA packet */
        stRcvPkt.uMsg.stData.blknum = ntohs(stRcvPkt.uMsg.stData.blknum);
        if(stRcvPkt.uMsg.stData.blknum == usCurBlkNum)
        {
            /* this packet is the correct DATA packet */
good_pkt:
            /* form the ACK packet for the DATA packet received */
            stSndPkt.usOpcode = htons(LOAD_TFTP_ACK);
            stSndPkt.uMsg.usBlkNum = htons(usCurBlkNum);
            lPktSize = LOAD_TFTP_HDRSIZE;

            lRc -= LOAD_TFTP_HDRSIZE;

            /* display bytes num that have received */
            memcpy((char *)szRamAddr, stRcvPkt.uMsg.stData.buf, (_U32)lRc);
            szRamAddr += lRc;

            /* print a pot every 100 packets */
            if( (usCurBlkNum - 1)%100 == 0 )
            {
                Drv_Print(".");
            }

            /* this packet is the final DATA packet */
            if(lRc != LOAD_TFTP_BLKSIZE)
            {
                (void)minip_sendto(lSockNum,(char *)&stSndPkt,(int)lPktSize,0,
                        (struct sockaddr *)(char *)&stServerAddr,sizeof(stServerAddr));
#if DRV_TFTP_DEBUG
                Drv_Print( "done!\r\n");
#endif
                /* receiving complete */
                if (minip_close(lSockNum) != SUCCESS)
                {
                    // err
                }
                return SUCCESS;
            }

            usCurBlkNum++;
        }
        else
        {
            (void)taskDelay(1);

            /* get rid of any accumulated datagrams */
            stTimeout.tv_sec = 5;
            pasttv.tv_sec    = 0;
            pasttv.tv_usec   = 0;
            for(i = 0; i < 6000; i ++)
            {
                sysMsDelay(1);
                (void)taskDelay(0);
                lEn = minip_recvfrom(lSockNum,(char *)&stRcvPkt,LOAD_TFTP_PKTSIZE,0,
                        (struct sockaddr *)(char *)&stClientAddr,(int*)&lFromLen);
                if(lEn > 0)
                {
                    break;
                }
                pasttv.tv_usec += 1*1000;
                pasttv.tv_sec  += pasttv.tv_usec/(1000000);
                pasttv.tv_usec %= 1000000;
                if(pasttv.tv_sec >= stTimeout.tv_sec){
                    break;
                }
            }
            if(lRc <=0)
            {
#if DRV_TFTP_DEBUG
                Drv_Print( "\r\nDownload fails!\r\n");
#endif
                goto exit1;
            }

            stServerAddr.sin_port = stClientAddr.sin_port;
            stRcvPkt.usOpcode = ntohs(stRcvPkt.usOpcode);
            if(stRcvPkt.usOpcode == LOAD_TFTP_DATA)
            {
                stRcvPkt.uMsg.stData.blknum = ntohs(stRcvPkt.uMsg.stData.blknum);
            }
            else
            {
#if DRV_TFTP_DEBUG
                Drv_Print( "\r\nUnkonwn or incorrect packet received from TFTP server, download fails!\r\n");
#endif
                goto exit1;
            }

            stTimeout.tv_sec = LOAD_TFTP_TIMEOUT_TIME;

            /*if we now have the previous data block, the host probably
              never got our ACK, so we should re-send it.*/
            if (stRcvPkt.uMsg.stData.blknum < usCurBlkNum)
            {
                continue;
            }
            else if(stRcvPkt.uMsg.stData.blknum == usCurBlkNum)
            {
                goto good_pkt;
            }
        }
    }

exit1:
    if (minip_close(lSockNum) != SUCCESS)
    {
    }

    return FAILURE;
}

⌨️ 快捷键说明

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