TFTP客户端实现





tftp.h

/******************************************************************************
 * 文 件 名    :    tftp.h
 * 负 责 人    :    
 * 创建日期    :    20170717
 * 版 本 号    :    v1.1
 * 文件描述    :    tftp
 * 其    他    :    无
 * 修改日志    :    无
******************************************************************************/

#ifndef _TFTP_H_
#define _TFTP_H_

#ifdef __cplusplus
extern "C"
{
#endif


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>





#if 0
#endif



#define TFTP_PORT                69


/*opcode definition*/
#define TFTP_OPCODE_RRQ        1
#define TFTP_OPCODE_WRQ        2
#define TFTP_OPCODE_DATA        3
#define TFTP_OPCODE_ACK        4
#define TFTP_OPCODE_ERROR        5


/*mode definition*/
#define TFTP_MODE_NETASCII    "netascii"
#define TFTP_MODE_OCTET        "octet"
#define TFTP_MODE_MAIL            "mail"


#define TFTP_MAX_FILE_SIZE    (32 * 1024 * 1024)

#define TFTP_CMD_SIZE            520 /*确保不会溢出*/
#define TFTP_BUF_SIZE            520 /*4字节前缀+512DATA*/


/*TFTP限制最大文件传输字节,0-511表示传输完成*/
#define TFTP_MAX_DATA_SIZE    512

#define TFTP_MIN_HEAD_SIZE    2
#define TFTP_MIN_CMD_SIZE        4
#define TFTP_MIN_DATA_SIZE    4
#define TFTP_MIN_ERROR_SIZE    5
#define TFTP_MIN_ACK_SIZE        4


#define TFTP_DATA_BLOCK_OFFSET    2
#define TFTP_ACK_BLOCK_OFFSET        2


#define TFTP_TIMEOUT_CNT        3
#define TFTP_TIMEOUT            3




#define TFTP_BUF_SIZE_ERR        (-11)





#if 0
#endif





#define TFTP_SAFE_FREE(m)    \
{                            \
    if (m != NULL)            \
    {                        \
        free (m);        \
        m = NULL;            \
    }                        \
}







/*TFTP功能打印开关*/
extern int    gTftpCltDbgSw;


#define TFTP_DBG_PRINT(FORMAT, args...)\
{\
    if (gTftpCltDbgSw)\
    {\
        printf("%s:%d: "FORMAT, __FUNCTION__, __LINE__, ##args);\
    }\
}


#define TFTP_FLUSH_PRINT(FORMAT, args...)\
{\
    if (gTftpCltDbgSw)\
    {\
        printf(FORMAT, ##args);\
        fflush(stdout);\
    }\
}


#define PRINT_TFTP_BUF(bufToPrint,lengthToPrint)\
{\
    u_char printch = 0;\
    u_int printIndex = 0;\
    printf("\r\n%s:%d: pkt=%p, len=%d.", __FUNCTION__, __LINE__,((void *)(bufToPrint)),((int)(lengthToPrint)));\
    for (printIndex = 0; printIndex < (int)(lengthToPrint); printIndex++)\
    {\
        if ((printIndex) % 4 == 0)\
        {\
            printf(" ");\
        }\
        if ((printIndex) % 16 == 0)\
        {\
            printf("\r\n");\
        }\
        printch = *((u_char *)(bufToPrint) + printIndex);\
        printf("%02x ", (unsigned int)printch);\
    }\
    printf("\r\n\r\n");\
}


#define TFTP_PKT_PRINT(pktToPrint,lengthToPrint)\
{\
    if (gTftpCltDbgSw)\
    {\
        PRINT_TFTP_BUF(pktToPrint,lengthToPrint);\
    }\
}







#if 0
#endif




/*外部宏引用*/
#define COM_SET fd_set
#define COM_FD_ISSET FD_ISSET
#define COM_FD_SET FD_SET
#define COM_FD_CLR FD_CLR
#define COM_FD_ZERO FD_ZERO


#define COM_AF_INET AF_INET
#define COM_SOCK_STREAM SOCK_STREAM
#define COM_SOCK_DGRAM SOCK_DGRAM         
#define COM_EINPROGRESS EINPROGRESS
#define COM_EALREADY EALREADY
#define COM_SOL_SOCKET SOL_SOCKET
#define COM_SO_LINGER SO_LINGER
#define COM_FIONBIO FIONBIO
#define COM_INADDR_ANY INADDR_ANY
#define COM_SO_SNDBUF SO_SNDBUF


#define COM_EWOULDBLOCK EWOULDBLOCK
#define COM_IPPROTO_TCP IPPROTO_TCP
#define COM_TCP_NODELAY TCP_NODELAY
#define COM_SO_ERROR SO_ERROR
#define COM_O_RDWR O_RDWR


#define COM_OPEN(name,flag,mode) open(name,flag,mode)
#define COM_CLOSE(fd) close(fd)
#define COM_WRITE(fd,buf,nbytes) write(fd,buf,nbytes)
#define COM_READ(fd,buf,maxbytes) read(fd,buf,maxbytes)
#define COM_RECV(fd, buffer, length, flags) recv(fd, buffer, length, flags)
#define COM_SEND(fd, buffer, length, flags) send(fd, buffer, length, flags)
#define COM_SELECT(width,pReadFds,pWriteFds,pExceptFds,pTimeOut) \
    select(width,pReadFds,pWriteFds,pExceptFds,pTimeOut)
#define COM_IO_CTL(fd,func,arg) ioctl(fd,func,arg)
#define COM_ERR_NO_GET() errno


#define COM_SOCKET_CREATE(domain,type,protocol) socket(domain,type,protocol)
#define COM_BIND(s,name,namelen) bind(s,name,namelen)
#define COM_LISTEN(s,backlog) listen(s,backlog)
#define COM_ACCEPT(s,addr,addrlen) accept(s,addr,addrlen)
#define COM_CONNECT(s,name,namelen) connect(s,name,namelen)
#define COM_SEND_TO(s,buf,buflen,flag,to,tolen) sendto(s,buf,buflen,flag,to,tolen)
#define COM_RECV_FROM(s,buf,buflen,flag,from,plen) recvfrom(s,buf,buflen,flag,from,plen)
#define COM_GET_SOCK_OPT(s,level,optname,optval,optlen) getsockopt(s,level,optname,optval,optlen)
#define COM_SET_SOCK_OPT(s,level,optname,optval,optlen) setsockopt(s,level,optname,optval,optlen)
#define COM_GET_SOCK_NAME(s,name,namelen) getsockname(s,name,namelen)
#define COM_GET_PEER_NAME(s,name,namelen) getpeername(s,name,namelen)


typedef struct timeval com_timeval;
typedef struct linger com_linger;
typedef struct sockaddr_in com_sockaddr_in;
typedef struct sockaddr com_sockaddr;
typedef socklen_t com_socklen_t;



















#ifdef __cplusplus
}
#endif

#endif/*#ifndef _TFTP_H_*/






tftp.c

/******************************************************************************
 * 文 件 名    :    tftp.c
 * 负 责 人    :    
 * 创建日期    :    20170708
 * 版 本 号    :    v1.1
 * 文件描述    :    TFTP模块
 * 其    他    :    无
 * 修改日志    :    无
******************************************************************************/
#ifdef __cplusplus
extern "C"
{
#endif


#include "tftp.h"





/*TFTP功能打印开关*/
int        gTftpCltDbgSw = 1;

/*TFTP数据请求超时时间,单位秒*/
int        tftpDataTimeout = TFTP_TIMEOUT;




#if 0
#endif




/**************************************************************************
* 函 数 名    :    setTftpCltDbgSw
* 负 责 人    :    scyang
* 创建日期    :    201403
* 函数功能    :    调试开关
* 输入参数    :    
* 输出参数    :    
* 返 回 值    :    
* 调用关系    :    
* 其    它    :    
* 修改记录    :    
**************************************************************************/
int setTftpCltDbgSw(int enable)
{
    gTftpCltDbgSw = enable;
    return 0;
}



/**************************************************************************
* 函 数 名    :    tftpGetFileSize
* 负 责 人    :    scyang
* 创建日期    :    201403
* 函数功能    :    计算文件大小
* 输入参数    :    
* 输出参数    :    
* 返 回 值    :    
* 调用关系    :    
* 其    它    :    
* 修改记录    :    
**************************************************************************/
int tftpGetFileSize(const char *path)
{
    int            filesize = 0;
    struct stat    statbuff;

    if (path == NULL)
    {
        return -1;
    }
    
    if (stat (path, &statbuff) < 0)
    {
        return 0;
    }
    else
    {
        filesize = statbuff.st_size;
    }
    
    return filesize;
}


#if 0
#endif



/**************************************************************************
* 函 数 名    :    tftpSockSafeClose
* 负 责 人    :    scyang
* 创建日期    :    201403
* 函数功能    :    关闭SOCKET连接
* 输入参数    :    int *pSockfd    --- SOCKET描述符
* 输出参数    :    
* 返 回 值    :    0 --- 成功;-1 --- 失败;
* 调用关系    :    
* 其    它    :    
* 修改记录    :    
**************************************************************************/
int tftpSockSafeClose(int *pSockfd)
{
    if (pSockfd == NULL)
    {
        TFTP_DBG_PRINT("tftpSockSafeClose para is null.\n");
        return -1;
    }

    if (*pSockfd >= 0)
    {
        TFTP_DBG_PRINT("Close socket %d connect...\n", *pSockfd);
        if (COM_CLOSE(*pSockfd) < 0)
        {
            TFTP_DBG_PRINT("Close socket error(%d)...\n", COM_ERR_NO_GET());
        }
        *pSockfd = -1;
    }
    
    return 0;
}





/***************************************************************
* 函 数 名  : tftpSocketCreate
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : 创建UDP连接
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpSocketCreate(int *pSockfd)
{
    int                sockfd = -1;
    unsigned long    flags = 0;
    
    TFTP_DBG_PRINT("Init create tftp socket ...\n");
    if(pSockfd == NULL)
    {
        TFTP_DBG_PRINT("tftpSocketCreate para is null.\n");
        return -1;
    }

    sockfd = COM_SOCKET_CREATE(COM_AF_INET, COM_SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        TFTP_DBG_PRINT("create socket error(%d).\n", COM_ERR_NO_GET());
        return -1;
    }

    flags = 1; /*非阻塞模式*/
    if(COM_IO_CTL(sockfd, COM_FIONBIO, (void *)(&flags)) < 0)
    {
        COM_CLOSE(sockfd);
        TFTP_DBG_PRINT("ioctl FIONBIO error(%d).\n", COM_ERR_NO_GET());
        return -1;
    }

    *pSockfd = sockfd;
    return 0;
}



/***************************************************************
* 函 数 名  : tftpBuildCmd
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : 构建读写命令
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpBuildCmd(unsigned short opCode, char *fileName, char *cmd, int *cmdLen)
{
    int        offset = 0;

    if (fileName == NULL || cmd == NULL || cmdLen == NULL)
    {
        TFTP_DBG_PRINT("tftpCommand para is null.\n");
        return -1;
    }

    if ((opCode != TFTP_OPCODE_RRQ) && (opCode != TFTP_OPCODE_WRQ))
    {
        TFTP_DBG_PRINT("tftpCommand op code %u error.\n", opCode);
        return -1;
    }

    if ((*cmdLen) < (TFTP_MIN_CMD_SIZE + strlen(TFTP_MODE_OCTET) + strlen(fileName)))
    {
        TFTP_DBG_PRINT("Input para cmd length %d error.\n", (*cmdLen));
        return -1;
    }

    /******************************************************************
    **  
    **   2 bytes   string       1 byte string      1 byte
    **   +--------+------------+------+------------+-----+
    **   | Opcode |  Filename  |   0  |    Mode    |  0  |
    **   +--------+------------+------+------------+-----+
    **            
    **   RRQ: opcode = 1
    **   WRQ: opcode = 2
    **                  
    *******************************************************************/

    /*OP CODE*/
    offset = 0;
    *(unsigned short *)(cmd + offset) = htons(opCode);
    offset += 2;

    /*filename*/
    memcpy((cmd + offset), fileName, strlen(fileName));
    offset += strlen(fileName);

    *(unsigned char *)(cmd + offset) = 0;
    offset += 1;

    /*set mode*/
    memcpy((cmd + offset), TFTP_MODE_OCTET, strlen(TFTP_MODE_OCTET));
    offset += strlen(TFTP_MODE_OCTET);

    *(unsigned char *)(cmd + offset) = 0;
    offset += 1;

    *cmdLen = offset;

    /*TFTP_PKT_PRINT(cmd, offset);*/
    return 0;
}



/***************************************************************
* 函 数 名  : tftpBuildAck
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : 构建ACK
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpBuildAck(unsigned short blockId, char *cmd, int *cmdLen)
{
    int        offset = 0;

    if (cmd == NULL || cmdLen == NULL)
    {
        TFTP_DBG_PRINT("Input para is null.\n");
        return -1;
    }

    if ((*cmdLen) < TFTP_MIN_CMD_SIZE)
    {
        TFTP_DBG_PRINT("Input para cmd length %d error.\n", (*cmdLen));
        return -1;
    }
    
    /***********************************************************
    **   ACK packet definition
    **----------------------------------------------------------
    **    opcode = 4
    **
    **     2 bytes    2 bytes
    **    +--------+------------+
    **    | Opcode |   Block #  |
    **    +--------+------------+
    **
    ***********************************************************/

    /*OP CODE*/
    offset = 0;
    *(unsigned short *)(cmd + offset) = htons(TFTP_OPCODE_ACK);
    offset += 2;

    *(unsigned short *)(cmd + offset) = htons(blockId);
    offset += 2;

    *cmdLen = offset;

    /*TFTP_FLUSH_PRINT("K");*/
    return 0;
}




/***************************************************************
* 函 数 名  : tftpCmdSend
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : 发送TFTP命令
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpCmdSend(int fd, com_sockaddr_in *addr, char *cmd, int cmdLen)
{
    char        hostIp[32] = {0};
    
    if (fd < 0 || addr == NULL || cmd == NULL)
    {
        TFTP_DBG_PRINT("Input para is null.\n");
        return -1;
    }
    
    if (COM_SEND_TO(fd, cmd, cmdLen, 0, (com_sockaddr *)addr, sizeof(com_sockaddr_in)) < 0)
    {
        inet_ntop(AF_INET, &addr->sin_addr, hostIp, (sizeof(hostIp) - 1));
        TFTP_DBG_PRINT("Send msg to %s failed: error(%d).\n", hostIp, COM_ERR_NO_GET());
        return -1;
    }

    return 0;
}



#if 0
#endif



/***************************************************************
* 函 数 名  : tftpParseData
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : 解析TFTP数据包
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpParseData(char *inBuf, int bufLen)
{
    int                offset = 0;
    unsigned short    opCode = 0;
    unsigned short    errCode = 0;

    if (inBuf == NULL)
    {
        TFTP_DBG_PRINT("Input para is null.\n");
        return -1;
    }

    if (bufLen < TFTP_MIN_HEAD_SIZE)
    {
        TFTP_DBG_PRINT("Input buffer length %d error.\n", bufLen);
        return -1;
    }

    /***********************************************************
    **   Data package definition
    **----------------------------------------------------------
    **    opcode = 3
    **
    **     2 bytes     2 bytes      n bytes
    **    +--------+------------+------------+
    **    | Opcode |   Block #  |   Data     |
    **    +--------+------------+------------+
    **
    **
    ************************************************************
    **   Error package definition
    **----------------------------------------------------------
    **    opcode = 5
    **
    **    2 bytes     2 bytes      string    1 byte
    **    +--------+------------+------------+------+
    **    | Opcode |  ErrorCode |   ErrMsg   |   0  |
    **    +--------+------------+------------+------+
    **
    **
    ************************************************************
    **   ACK packet definition
    **----------------------------------------------------------
    **    opcode = 4
    **
    **     2 bytes    2 bytes
    **    +--------+------------+
    **    | Opcode |   Block #  |
    **    +--------+------------+
    **
    ***********************************************************/
    /*TFTP_PKT_PRINT(inBuf, (bufLen <= 16 ? bufLen : 16));*/

    offset = 0;
    opCode = ntohs(*(unsigned short *)inBuf);
    offset += 2; /*OP CODE*/

    switch (opCode)
    {
        case TFTP_OPCODE_DATA:
        {
            if (bufLen < TFTP_MIN_DATA_SIZE)
            {
                TFTP_DBG_PRINT("Get remote data size %u error.\n", bufLen);
                return -1;
            }

            /*收到的数据包长度固定为512*/
            if (bufLen > (TFTP_MAX_DATA_SIZE + TFTP_MIN_DATA_SIZE))
            {
                TFTP_DBG_PRINT("Get remote data size %u error.\n", bufLen);
                return -1;
            }
            
            /*TFTP_FLUSH_PRINT("#");*/
            return TFTP_OPCODE_DATA;
        }
        case TFTP_OPCODE_ACK:
        {
            if (bufLen < TFTP_MIN_ACK_SIZE)
            {
                TFTP_DBG_PRINT("Get remote ack size %u error.\n", bufLen);
                return -1;
            }
            
            /*TFTP_FLUSH_PRINT("K");*/
            return TFTP_OPCODE_ACK;
        }
        case TFTP_OPCODE_ERROR:
        {
            if (bufLen < TFTP_MIN_ERROR_SIZE)
            {
                TFTP_DBG_PRINT("Get remote error size %u error.\n", bufLen);
                return -1;
            }
            
            errCode = ntohs(*(unsigned short *)(inBuf + offset));
            offset += 2; /*error CODE*/
            TFTP_DBG_PRINT("Get remote error code %u msg [%s]\n", errCode, (inBuf + offset));
            return TFTP_OPCODE_ERROR;
        }
        default:
        {
            TFTP_DBG_PRINT("Get remote opcode %u error.\n", opCode);
            return -1;
        }
    }
}



/***************************************************************
* 函 数 名  : tftpGetRemoteData
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : 获取远程TFTP数据包
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpGetRemoteData(int sockfd, com_sockaddr_in *addr, char *outBuf, int *inOutBufLen)
{
    int        rvLen = 0;
    int        inBufLen = 0;
    int        errFlag = 1;
    int        counter = TFTP_TIMEOUT_CNT;
    
    COM_SET            fdset;
    com_socklen_t    addrLen = 0;
    com_timeval        time;
    
    if (sockfd < 0 || addr == NULL || outBuf == NULL || inOutBufLen == NULL)
    {
        TFTP_DBG_PRINT("getRemoteData para is null.\n");
        return -1;
    }

    inBufLen = *inOutBufLen;
    *inOutBufLen = 0;

    while (counter > 0)
    {
        counter--;
        COM_FD_ZERO(&fdset);
        COM_FD_SET(sockfd, &fdset);    

        time.tv_sec = tftpDataTimeout;
        time.tv_usec = 0;
        if (COM_SELECT(sockfd + 1, &fdset, 0, 0, &time) <= 0)
        {
            TFTP_DBG_PRINT("time out for recv remote data(%u).\n", counter);
            continue;
        }

        if (COM_FD_ISSET(sockfd, &fdset) == 0)
        {
            TFTP_DBG_PRINT("fd_isset error.\n");
            continue;
        }

        memset(outBuf, 0, inBufLen);
        addrLen = sizeof(com_sockaddr_in);
        rvLen = COM_RECV_FROM(sockfd, outBuf, inBufLen, 0, (com_sockaddr *)addr, &addrLen);
        if (rvLen <= 0)
        {
            TFTP_DBG_PRINT("Recv file from remote error(%d).\n", COM_ERR_NO_GET());
            break;
        }
        else
        {
            errFlag = 0;
            break;
        }
    }

    *inOutBufLen = rvLen;
    if (errFlag != 0)
    {
        return -1;
    }
    return 0;
}



/***************************************************************
* 函 数 名  : tftpUploadLocalData
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : 上传TFTP数据包
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpUploadLocalData(int sockfd, com_sockaddr_in *addr, char *inBuf, int bufLen)
{
    int        sdLen = 0;
    int        errFlag = 1;
    int        counter = TFTP_TIMEOUT_CNT;

    COM_SET            fdset;
    com_timeval        time;
    
    if (sockfd < 0 || addr == NULL || inBuf == NULL || bufLen <= 0)
    {
        TFTP_DBG_PRINT("getRemoteData para is null.\n");
        return -1;
    }

    while (counter > 0)
    {
        counter--;
        COM_FD_ZERO(&fdset);
        COM_FD_SET(sockfd, &fdset);    

        time.tv_sec = tftpDataTimeout;
        time.tv_usec = 0;
        if (COM_SELECT(sockfd + 1, 0, &fdset, 0, &time) <= 0)
        {
            TFTP_DBG_PRINT("time out for recv remote data(%u).\n", counter);
            continue;
        }

        if (COM_FD_ISSET(sockfd, &fdset) == 0)
        {
            TFTP_DBG_PRINT("fd_isset error.\n");
            continue;
        }

        sdLen = COM_SEND_TO(sockfd, inBuf, bufLen, 0, (com_sockaddr *)addr, sizeof(com_sockaddr_in));
        if (sdLen != bufLen)
        {
            TFTP_DBG_PRINT("Send file to remote error(%d).\n", COM_ERR_NO_GET());
            break;
        }
        else
        {
            errFlag = 0;
            break;
        }
    }

    if (errFlag != 0)
    {
        return -1;
    }
    return 0;
}




/***************************************************************
* 函 数 名  : tftpParseData
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : 发送返回ACK
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpAckSend(int sockfd, com_sockaddr_in *addr, unsigned short blockId)
{
    int        cmdLen = TFTP_CMD_SIZE;
    char    cmd[TFTP_CMD_SIZE] = {0};

    if (sockfd < 0 || addr == NULL)
    {
        TFTP_DBG_PRINT("Input para is error.\n");
        return -1;
    }

    if ((tftpBuildAck(blockId, cmd, &cmdLen) != 0)
        || (tftpUploadLocalData(sockfd, addr, cmd, cmdLen) != 0))
    {
        TFTP_DBG_PRINT("Tftp send ack(%u) error.\n", blockId);
        return -1;
    }

    return 0;
}



/***************************************************************
* 函 数 名  : tftpAckRecv
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : 接收ACK
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpAckRecv(int sockfd, com_sockaddr_in *addr, unsigned short *blockId)
{
    int                recvLen = 0;
    int                counter = TFTP_TIMEOUT_CNT;
    unsigned short    retVal = 0;
    unsigned short    tBlockId = 0;
    char            recvBuf[TFTP_CMD_SIZE] = {0};

    if (sockfd < 0 || addr == NULL || blockId == NULL)
    {
        TFTP_DBG_PRINT("Input para is error.\n");
        return -1;
    }

    while(counter > 0)
    {
        /*发送命令后接收一次ACK*/
        counter--;
        recvLen = TFTP_CMD_SIZE;
        memset(recvBuf, 0, TFTP_CMD_SIZE);
        if (tftpGetRemoteData(sockfd, addr, recvBuf, &recvLen) != 0)
        {
            TFTP_DBG_PRINT("Tftp get remote file error.\n");
            return 1;
        }
        
        if ((retVal = tftpParseData(recvBuf, recvLen)) < 0)
        {
            /*收到的不是ACK,则继续收,直到收到为止*/
            TFTP_DBG_PRINT("Tftp parse data error.\n");
            continue;
        }
        
        if (retVal == TFTP_OPCODE_ACK)
        {
            if (recvLen < TFTP_MIN_ACK_SIZE)
            {
                TFTP_DBG_PRINT("Tftp get remote file end.\n");
                return -1;
            }
        
            /*写命令的ACK对应的BLOCKID=0*/
            tBlockId = ntohs(*(unsigned short *)(recvBuf + TFTP_ACK_BLOCK_OFFSET));
            *blockId = tBlockId;
            return 0;
        }
        else if (retVal == TFTP_OPCODE_ERROR)
        {
            TFTP_DBG_PRINT("Tftp get error ack info...\n");
            return -1;
        }
        else
        {
            /*收到的不是ACK,则继续收,直到收到为止*/
            TFTP_DBG_PRINT("Tftp get wrong ack(%u).\r\n", retVal);
            continue;
        }
    }

    return -1;
}



#if 0
#endif



/***************************************************************
* 函 数 名  : tftpDownloadBase
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : TFTP下载
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpDownloadBase(
    char    *outBuf,
    int        *inoutBufLen,
    char    *hostIp,
    char    *fileName)
{
    int                sockfd = -1;
    int                count = 0;
    int                ramsize = 0;
    int                cmdLen = 0;
    int                recvLen = 0;
    int                status = 0;
    int                errFlag = 1;
    int                counter = TFTP_TIMEOUT_CNT;

    unsigned short    blockId = 1; /*块号连续且从1开始*/
    unsigned short    tBlockId = 0;
    unsigned short    retVal = 0;
    char            *rambuf = NULL;

    char            cmd[TFTP_CMD_SIZE] = {0};
    char            *recvBuf = NULL;
    com_sockaddr_in    addr;

    if (outBuf == NULL || inoutBufLen == NULL || hostIp == NULL || fileName == NULL)
    {
        TFTP_DBG_PRINT("Input para is null.\n");
        return -1;
    }

    rambuf = outBuf;
    ramsize = *inoutBufLen;

    if ((recvBuf = (char *)malloc (TFTP_BUF_SIZE)) == NULL)
    {
        TFTP_DBG_PRINT("Malloc error.\r\n");
        return -1;
    }

    memset(&addr, 0, sizeof(com_sockaddr_in));
    addr.sin_family = COM_AF_INET;
    addr.sin_port = htons(TFTP_PORT);
    inet_pton(AF_INET, hostIp, &addr.sin_addr);

    do
    {
        /*create socket*/
        if (tftpSocketCreate(&sockfd) < 0)
        {
            TFTP_DBG_PRINT("Create socket failed: error(%d).\n", COM_ERR_NO_GET());
            break;
        }

        memset(cmd, 0, sizeof(cmd));
        cmdLen = TFTP_CMD_SIZE;
        if (tftpBuildCmd(TFTP_OPCODE_RRQ, fileName, cmd, &cmdLen) < 0)
        {
            TFTP_DBG_PRINT("Build tftp get remote file command failed.\n");
            break;
        }

        if (tftpCmdSend(sockfd, &addr, cmd, cmdLen) < 0)
        {
            TFTP_DBG_PRINT("Send msg to %s failed.\n", hostIp);
            break;
        }

        while (1)
        {
            if (counter <= 0)
            {
                status = -1;
                TFTP_DBG_PRINT("Tftp get remote data(%u) timeout(%d).\n", blockId, counter);
                break;
            }
            
            counter--;
            recvLen = TFTP_BUF_SIZE;
            memset(recvBuf, 0, TFTP_BUF_SIZE);
            if (tftpGetRemoteData(sockfd, &addr, recvBuf, &recvLen) != 0)
            {
                /*如果接收第一块DATA就超时,说明命令就没有发送成功*/
                if (blockId == 1)
                {
                    TFTP_DBG_PRINT("Tftp get remote data(%u) error.\n", blockId);
                    break;
                }
                else
                {
                    /*不是第一块DATA,有可能是ACK没有发送成功,重发ACK*/
                    TFTP_DBG_PRINT("Tftp get remote data(%u) error.\n", blockId);

                    /*没有收到DATA,重发上一个ACK*/
                    if (tftpAckSend(sockfd, &addr, tBlockId) != 0)
                    {
                        status = -1;
                        TFTP_DBG_PRINT("Tftp send ack(%u) error.\n", tBlockId);
                        break;
                    }
                    continue;
                }
            }

            if ((retVal = tftpParseData(recvBuf, recvLen)) < 0)
            {
                status = -1;
                TFTP_DBG_PRINT("Tftp parse data error.\n");
                break;
            }
            
            switch (retVal)
            {
                case TFTP_OPCODE_DATA:
                {
                    /*块号连续且从1开始*/
                    tBlockId = ntohs(*(unsigned short*)(recvBuf + TFTP_DATA_BLOCK_OFFSET));
                    if (tBlockId != blockId)
                    {
                        TFTP_DBG_PRINT("Tftp get remote block id %u/%u error(%d).\n", tBlockId, blockId, counter);

                        if (tBlockId < blockId)
                        {
                            /*重新发ACK请求上一个数据*/
                            if (tftpAckSend(sockfd, &addr, tBlockId) != 0)
                            {
                                status = -1;
                                TFTP_DBG_PRINT("Tftp send ack(%u) counter(%d) error.\n", tBlockId, counter);
                                break;
                            }
                            continue;
                        }
                        else
                        {
                            /*如果发来的数据(tBlockId > blockId)则说明逻辑出问题了*/
                            status = -1;
                            break;
                        }
                    }
                    else
                    {
                        /*正常则COUNTER恢复*/
                        counter = TFTP_TIMEOUT_CNT;
                        blockId++;
                    }

                    /*校验长度,防止写越界*/
                    recvLen -= TFTP_MIN_DATA_SIZE;
                    if ((count + recvLen) > TFTP_MAX_FILE_SIZE) /*tftp支持的最大文件*/
                    {
                        status = -1;
                        TFTP_DBG_PRINT("Tftp get remote data length %d too big.\n", (count + recvLen));
                        break;
                    }
                    
                    if ((recvLen > 0) && ((count + recvLen) > ramsize))
                    {
                        memcpy ((rambuf + count), (recvBuf + TFTP_MIN_DATA_SIZE), (ramsize - count));
                        count += (ramsize - count);
                        status = TFTP_BUF_SIZE_ERR;
                        TFTP_DBG_PRINT("Tftp buffer small: count=%d, recvLen=%d, ramsize=%d.\r\n", count, recvLen, ramsize);
                        break;
                    }
                    else
                    {
                        if (recvLen > 0)
                        {
                            memcpy((rambuf + count), (recvBuf + TFTP_MIN_DATA_SIZE), recvLen);
                            count += recvLen;
                        }

                        /*接收一个包,需要返回一个ACK*/
                        if (tftpAckSend(sockfd, &addr, tBlockId) != 0)
                        {
                            status = -1;
                            TFTP_DBG_PRINT("Tftp send ack(%u) error.\n", tBlockId);
                            break;
                        }
                    }

                    if (recvLen < TFTP_MAX_DATA_SIZE)
                    {
                        errFlag = 0;
                        TFTP_DBG_PRINT("Tftp get remote file end(%d).\n", recvLen);
                        break;
                    }

                    break;
                }
                case TFTP_OPCODE_ERROR:
                {
                    status = -1;
                    TFTP_DBG_PRINT("Tftp parse remote data error.\n");
                    break;
                }
                default:
                {
                    TFTP_DBG_PRINT("Tftp parse remote data(%d) error.\n", retVal);
                    break;
                }
            }

            /*数据接收状态异常,或者文件传输完成,则退出循环*/
            if ((status != 0) || (errFlag == 0))
            {
                break;
            }
        }
        errFlag = 0;
    }while(0);
    
    *inoutBufLen = count;
    tftpSockSafeClose(&sockfd);
    TFTP_SAFE_FREE(recvBuf);
    TFTP_DBG_PRINT("Tftp download complete(%d/%d)...\n", count, ramsize);

    if (errFlag != 0)
    {
        return -1;
    }
    return status;
}






/***************************************************************
* 函 数 名  : tftpUploadBase
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : TFTP上传
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpUploadBase(
    char    *outBuf,
    int        bufLen,
    char    *hostIp,
    char    *fileName)
{
    int                sockfd = -1;
    int                count = 0;
    int                ramsize = 0;
    int                cmdLen = 0;
    int                sendLen = 0;
    int                status = 0;
    int                retVal = 0;
    int                errFlag = 1;
    int                completion = 0;
    int                counter = TFTP_TIMEOUT_CNT;
    unsigned short    blockId = 0;
    unsigned short    tBlockId = 0;
    
    char            *rambuf = NULL;
    char            cmd[TFTP_CMD_SIZE] = {0};
    char            *sendBuf = NULL;
    com_sockaddr_in    addr;

    if (outBuf == NULL || hostIp == NULL || fileName == NULL)
    {
        TFTP_DBG_PRINT("Input para is null.\n");
        return -1;
    }

    if (bufLen <= 0)
    {
        TFTP_DBG_PRINT("Input para buffer length %d error.\n", bufLen);
        return -1;
    }

    rambuf = outBuf;
    ramsize = bufLen;

    if ((sendBuf = (char *)malloc (TFTP_BUF_SIZE)) == NULL)
    {
        TFTP_DBG_PRINT("Malloc error.\r\n");
        return -1;
    }

    memset(&addr, 0, sizeof(com_sockaddr_in));
    addr.sin_family = COM_AF_INET;
    addr.sin_port = htons(TFTP_PORT);
    inet_pton(AF_INET, hostIp, &addr.sin_addr);

    do
    {
        /*create socket*/
        if (tftpSocketCreate(&sockfd) < 0)
        {
            TFTP_DBG_PRINT("Create socket failed: error(%d).\n", COM_ERR_NO_GET());
            break;
        }

        memset(cmd, 0, sizeof(cmd));
        cmdLen = TFTP_CMD_SIZE;
        if (tftpBuildCmd(TFTP_OPCODE_WRQ, fileName, cmd, &cmdLen) < 0)
        {
            TFTP_DBG_PRINT("Build tftp get remote file command failed.\n");
            break;
        }

        if (tftpCmdSend(sockfd, &addr, cmd, cmdLen) < 0)
        {
            TFTP_DBG_PRINT("Send tftp command to %s failed.\n", hostIp);
            break;
        }

        retVal = tftpAckRecv(sockfd, &addr, &tBlockId);
        if ((retVal != 0) || (tBlockId != 0))
        {
            TFTP_DBG_PRINT("Get cmd ack(%u) error.\n", tBlockId);
            break;
        }

        /*开始上传数据*/
        blockId++;
        while (completion == 0)
        {
            sendLen = 0;
            memset(sendBuf, 0, TFTP_BUF_SIZE);

            *(unsigned short *)sendBuf = htons(TFTP_OPCODE_DATA);
            *(unsigned short *)(sendBuf + TFTP_DATA_BLOCK_OFFSET) = htons(blockId);

            if ((ramsize - count) >= TFTP_MAX_DATA_SIZE)
            {
                memcpy(sendBuf + TFTP_MIN_DATA_SIZE, rambuf + count, TFTP_MAX_DATA_SIZE);
                sendLen = TFTP_MIN_DATA_SIZE + TFTP_MAX_DATA_SIZE;
                count += TFTP_MAX_DATA_SIZE;
            }
            else
            {
                if (ramsize > count)
                {
                    memcpy(sendBuf + TFTP_MIN_DATA_SIZE, rambuf + count, (ramsize - count));
                    sendLen = TFTP_MIN_DATA_SIZE + (ramsize - count);
                    count += ramsize - count;
                }
                else
                {
                    sendLen = TFTP_MIN_DATA_SIZE;
                }

                /*结束发送*/
                completion = 1;
            }

data_send:
            if (counter <= 0)
            {
                status = -1;
                TFTP_DBG_PRINT("Tftp send data(%u) timeout(%d).\n", blockId, counter);
                break;
            }

            counter--;
            if (tftpUploadLocalData(sockfd, &addr, sendBuf, sendLen) != 0)
            {
                status = -1;
                TFTP_DBG_PRINT("Tftp send local file(%u) error.\n", blockId);
                break;
            }

            retVal = tftpAckRecv(sockfd, &addr, &tBlockId);
            if (retVal == 0)
            {
                if (tBlockId == blockId)
                {
                    counter = TFTP_TIMEOUT_CNT;
                    blockId++;
                    continue;
                }
                else if (tBlockId != blockId)
                {
                    TFTP_DBG_PRINT("Tftp get remote ack(%u/%u) counter(%d) error.\n", tBlockId, blockId, counter);

                    /*BLOCK ID必须大于0,对于BLOCK ID非如下情况,视为异常处理*/
                    if ((tBlockId == (blockId - 1)) && (tBlockId != 0) && (counter > 0))
                    {
                        goto data_send;
                    }
                    else
                    {
                        status = -1;
                        break;
                    }
                }
                else
                {
                    status = -1;
                    TFTP_DBG_PRINT("Get data ack(%u) error.\n", tBlockId);
                    break;
                }
            }
            else if (retVal == 1)
            {
                /*接收ACK超时,有可能是DATA远程没有收到,重发DATA*/
                TFTP_DBG_PRINT("Get data ack timeout(%d).\n", retVal);
                goto data_send;
            }
            else
            {
                status = -1;
                TFTP_DBG_PRINT("Get data ack error(%d).\n", retVal);
                break;
            }
        }
        
        errFlag = 0;
    }while(0);
    
    tftpSockSafeClose(&sockfd);
    TFTP_SAFE_FREE(sendBuf);
    TFTP_DBG_PRINT("Tftp upload complete(%d/%d)...\n", count, ramsize);

    if (errFlag != 0)
    {
        return -1;
    }
    return status;
}




/***************************************************************
* 函 数 名  : tftpDownloadFile
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : TFTP下载
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpDownloadFile(
    char    *hostIp,
    char    *remotefile,
    char    *localfile)
{
    int                sockfd = -1;
    int                filefd = -1;
    int                count = 0;
    int                cmdLen = 0;
    int                recvLen = 0;
    int                wtLen = 0;
    int                status = 0;
    int                errFlag = 1;
    int                counter = TFTP_TIMEOUT_CNT;

    unsigned short    blockId = 1; /*块号连续且从1开始*/
    unsigned short    tBlockId = 0;
    unsigned short    retVal = 0;

    char            cmd[TFTP_CMD_SIZE] = {0};
    char            *recvBuf = NULL;
    com_sockaddr_in    addr;

    if (remotefile == NULL || localfile == NULL || hostIp == NULL)
    {
        TFTP_DBG_PRINT("Input para is null.\n");
        return -1;
    }

    /*open file*/
    if ((filefd = open(localfile, O_WRONLY | O_CREAT | O_TRUNC, 0x777)) < 0)
    {
        TFTP_DBG_PRINT("Open localfile %s error.\r\n", localfile);
        return -1;
    }

    if ((recvBuf = (char *)malloc (TFTP_BUF_SIZE)) == NULL)
    {
        close(filefd);
        TFTP_DBG_PRINT("Malloc error.\r\n");
        return -1;
    }

    memset(&addr, 0, sizeof(com_sockaddr_in));
    addr.sin_family = COM_AF_INET;
    addr.sin_port = htons(TFTP_PORT);
    inet_pton(AF_INET, hostIp, &addr.sin_addr);

    do
    {
        /*create socket*/
        if (tftpSocketCreate(&sockfd) < 0)
        {
            TFTP_DBG_PRINT("Create socket failed: error(%d).\n", COM_ERR_NO_GET());
            break;
        }

        memset(cmd, 0, sizeof(cmd));
        cmdLen = TFTP_CMD_SIZE;
        if (tftpBuildCmd(TFTP_OPCODE_RRQ, remotefile, cmd, &cmdLen) < 0)
        {
            TFTP_DBG_PRINT("Build tftp get remote file command failed.\n");
            break;
        }

        if (tftpCmdSend(sockfd, &addr, cmd, cmdLen) < 0)
        {
            TFTP_DBG_PRINT("Send msg to %s failed.\n", hostIp);
            break;
        }

        while (1)
        {
            if (counter <= 0)
            {
                status = -1;
                TFTP_DBG_PRINT("Tftp get remote data(%u) timeout(%d).\n", blockId, counter);
                break;
            }
            
            counter--;
            recvLen = TFTP_BUF_SIZE;
            memset(recvBuf, 0, TFTP_BUF_SIZE);
            if (tftpGetRemoteData(sockfd, &addr, recvBuf, &recvLen) != 0)
            {
                /*如果接收第一块DATA就超时,说明命令就没有发送成功*/
                if (blockId == 1)
                {
                    TFTP_DBG_PRINT("Tftp get remote data(%u) error.\n", blockId);
                    break;
                }
                else
                {
                    /*不是第一块DATA,有可能是ACK没有发送成功,重发ACK*/
                    TFTP_DBG_PRINT("Tftp get remote data(%u) error.\n", blockId);

                    /*没有收到DATA,重发上一个ACK*/
                    if (tftpAckSend(sockfd, &addr, tBlockId) != 0)
                    {
                        status = -1;
                        TFTP_DBG_PRINT("Tftp send ack(%u) error.\n", tBlockId);
                        break;
                    }
                    continue;
                }
            }

            if ((retVal = tftpParseData(recvBuf, recvLen)) < 0)
            {
                status = -1;
                TFTP_DBG_PRINT("Tftp parse data error.\n");
                break;
            }
            
            switch (retVal)
            {
                case TFTP_OPCODE_DATA:
                {
                    /*块号连续且从1开始*/
                    tBlockId = ntohs(*(unsigned short*)(recvBuf + TFTP_DATA_BLOCK_OFFSET));
                    if (tBlockId != blockId)
                    {
                        TFTP_DBG_PRINT("Tftp get remote block id %u/%u error(%d).\n", tBlockId, blockId, counter);

                        if (tBlockId < blockId)
                        {
                            /*重新发ACK请求上一个数据*/
                            if (tftpAckSend(sockfd, &addr, tBlockId) != 0)
                            {
                                status = -1;
                                TFTP_DBG_PRINT("Tftp send ack(%u) counter(%d) error.\n", tBlockId, counter);
                                break;
                            }
                            continue;
                        }
                        else
                        {
                            /*如果发来的数据(tBlockId > blockId)则说明逻辑出问题了*/
                            status = -1;
                            break;
                        }
                    }
                    else
                    {
                        /*正常则COUNTER恢复*/
                        counter = TFTP_TIMEOUT_CNT;
                        blockId++;
                    }

                    /*校验长度,防止写越界*/
                    recvLen -= TFTP_MIN_DATA_SIZE;
                    count += recvLen;
                    if (count > TFTP_MAX_FILE_SIZE) /*tftp支持的最大文件*/
                    {
                        status = -1;
                        TFTP_DBG_PRINT("Tftp get remote data length %d too big.\n", count);
                        break;
                    }
                    
                    if (recvLen > 0)
                    {
                        if ((wtLen = write (filefd, (recvBuf + TFTP_MIN_DATA_SIZE), recvLen)) != recvLen)
                        {
                            status = -1;
                            TFTP_DBG_PRINT("Tftp write file %s error.\n", localfile);
                            break;
                        }
                    }

                    /*接收一个包,需要返回一个ACK*/
                    if (tftpAckSend(sockfd, &addr, tBlockId) != 0)
                    {
                        status = -1;
                        TFTP_DBG_PRINT("Tftp send ack(%u) error.\n", tBlockId);
                        break;
                    }

                    if (recvLen < TFTP_MAX_DATA_SIZE)
                    {
                        errFlag = 0;
                        TFTP_DBG_PRINT("Tftp get remote file end(%d).\n", recvLen);
                        break;
                    }

                    break;
                }
                case TFTP_OPCODE_ERROR:
                {
                    status = -1;
                    TFTP_DBG_PRINT("Tftp parse remote data error.\n");
                    break;
                }
                default:
                {
                    TFTP_DBG_PRINT("Tftp parse remote data(%d) error.\n", retVal);
                    break;
                }
            }

            /*数据接收状态异常,或者文件传输完成,则退出循环*/
            if ((status != 0) || (errFlag == 0))
            {
                break;
            }
        }
        errFlag = 0;
    }while(0);
    
    close(filefd);
    tftpSockSafeClose(&sockfd);
    TFTP_SAFE_FREE(recvBuf);
    TFTP_DBG_PRINT("Tftp download file complete...\n");

    if (errFlag != 0)
    {
        return -1;
    }
    return status;
}






/***************************************************************
* 函 数 名  : tftpUploadFile
* 负 责 人  : scyang
* 创建日期  : 20170720
* 函数功能  : TFTP上传
* 输入参数  :
* 输出参数  :
* 返 回 值  :
* 调用关系  :
* 其    它  :
****************************************************************/
int tftpUploadFile(
    char    *hostIp,
    char    *remotefile,
    char    *localfile)
{
    int                sockfd = -1;
    int                filefd = -1;
    int                count = 0;
    int                ramsize = 0;
    int                cmdLen = 0;
    int                sendLen = 0;
    int                rdLen = 0;
    int                status = 0;
    int                retVal = 0;
    int                errFlag = 1;
    int                completion = 0;
    int                counter = TFTP_TIMEOUT_CNT;
    unsigned short    blockId = 0;
    unsigned short    tBlockId = 0;
    
    char            cmd[TFTP_CMD_SIZE] = {0};
    char            *sendBuf = NULL;
    com_sockaddr_in    addr;

    if (hostIp == NULL || localfile == NULL || remotefile == NULL)
    {
        TFTP_DBG_PRINT("Input para is null.\n");
        return -1;
    }

    ramsize = tftpGetFileSize(localfile);
    if ((ramsize <= 0) || (ramsize > TFTP_MAX_FILE_SIZE)) /*tftp支持的最大文件*/
    {
        TFTP_DBG_PRINT("Tftp upload file %s length %d error.\n", localfile, ramsize);
        return -1;
    }

    if ((filefd = open(localfile, O_RDONLY, 0x777)) < 0)
    {
        TFTP_DBG_PRINT("Open localfile %s error.\r\n", localfile);
        return -1;
    }

    if ((sendBuf = (char *)malloc (TFTP_BUF_SIZE)) == NULL)
    {
        close(filefd);
        TFTP_DBG_PRINT("Malloc error.\r\n");
        return -1;
    }

    memset(&addr, 0, sizeof(com_sockaddr_in));
    addr.sin_family = COM_AF_INET;
    addr.sin_port = htons(TFTP_PORT);
    inet_pton(AF_INET, hostIp, &addr.sin_addr);

    do
    {
        /*create socket*/
        if (tftpSocketCreate(&sockfd) < 0)
        {
            TFTP_DBG_PRINT("Create socket failed: error(%d).\n", COM_ERR_NO_GET());
            break;
        }

        memset(cmd, 0, sizeof(cmd));
        cmdLen = TFTP_CMD_SIZE;
        if (tftpBuildCmd(TFTP_OPCODE_WRQ, remotefile, cmd, &cmdLen) < 0)
        {
            TFTP_DBG_PRINT("Build tftp get remote file command failed.\n");
            break;
        }

        if (tftpCmdSend(sockfd, &addr, cmd, cmdLen) < 0)
        {
            TFTP_DBG_PRINT("Send tftp command to %s failed.\n", hostIp);
            break;
        }

        retVal = tftpAckRecv(sockfd, &addr, &tBlockId);
        if ((retVal != 0) || (tBlockId != 0))
        {
            TFTP_DBG_PRINT("Get cmd ack(%u) error.\n", tBlockId);
            break;
        }

        /*开始上传数据*/
        blockId++;
        while (completion == 0)
        {
            sendLen = 0;
            memset(sendBuf, 0, TFTP_BUF_SIZE);

            *(unsigned short *)sendBuf = htons(TFTP_OPCODE_DATA);
            *(unsigned short *)(sendBuf + TFTP_DATA_BLOCK_OFFSET) = htons(blockId);

            rdLen = read(filefd, (sendBuf + TFTP_MIN_DATA_SIZE), TFTP_MAX_DATA_SIZE);
            if (rdLen >= 0)
            {
                count += rdLen;
                sendLen = TFTP_MIN_DATA_SIZE + rdLen;
                if (rdLen < TFTP_MAX_DATA_SIZE)
                {
                    /*结束发送*/
                    TFTP_DBG_PRINT("Tftp read file end(%d/%d)...\n", count, ramsize);
                    completion = 1;
                }
            }
            else
            {
                status = -1;
                TFTP_DBG_PRINT("Tftp read file %s error(%d).\n", errno);
                break;
            }

data_send:
            if (counter <= 0)
            {
                status = -1;
                TFTP_DBG_PRINT("Tftp send data(%u) timeout(%d).\n", blockId, counter);
                break;
            }

            counter--;
            if (tftpUploadLocalData(sockfd, &addr, sendBuf, sendLen) != 0)
            {
                status = -1;
                TFTP_DBG_PRINT("Tftp send local file(%u) error.\n", blockId);
                break;
            }

            retVal = tftpAckRecv(sockfd, &addr, &tBlockId);
            if (retVal == 0)
            {
                if (tBlockId == blockId)
                {
                    counter = TFTP_TIMEOUT_CNT;
                    blockId++;
                    continue;
                }
                else if (tBlockId != blockId)
                {
                    TFTP_DBG_PRINT("Tftp get remote ack(%u/%u) counter(%d) error.\n", tBlockId, blockId, counter);

                    /*BLOCK ID必须大于0,对于BLOCK ID非如下情况,视为异常处理*/
                    if ((tBlockId == (blockId - 1)) && (tBlockId != 0) && (counter > 0))
                    {
                        goto data_send;
                    }
                    else
                    {
                        status = -1;
                        break;
                    }
                }
                else
                {
                    status = -1;
                    TFTP_DBG_PRINT("Get data ack(%u) error.\n", tBlockId);
                    break;
                }
            }
            else if (retVal == 1)
            {
                /*接收ACK超时,有可能是DATA远程没有收到,重发DATA*/
                TFTP_DBG_PRINT("Get data ack timeout(%d).\n", retVal);
                goto data_send;
            }
            else
            {
                status = -1;
                TFTP_DBG_PRINT("Get data ack error(%d).\n", retVal);
                break;
            }
        }
        
        errFlag = 0;
    }while(0);

    close(filefd);
    tftpSockSafeClose(&sockfd);
    TFTP_SAFE_FREE(sendBuf);
    TFTP_DBG_PRINT("Tftp upload file complete...\n");

    if (errFlag != 0)
    {
        return -1;
    }
    return status;
}




#if 0
#endif




int main(int argc, char *argv[])
{
    int        bufLen = 32 * 1024 * 1024;
    char    *buf = NULL;
    char    *ip = argv[1];
    char    *filename = argv[2];

    buf = (char *)malloc(32 * 1024 * 1024);

    if (argc != 3)
    {
        printf("Usage: tftp.exe ip file_name\r\n");
        return -1;
    }

#if 1
    if (tftpDownloadFile(ip, filename, "tmp.txt") < 0)
    {
        printf("tftpDownloadFile error.\r\n");
        return -1;
    }

    if (tftpUploadFile(ip, "tmp1.txt", "tmp.txt") < 0)
    {
        printf("tftpUploadFile error.\r\n");
        return -1;
    }
#endif

#if 1
    if (tftpDownloadBase(buf, &bufLen, ip, filename) < 0)
    {
        printf("tftpDownloadBase error.\r\n");
        return -1;
    }
    
    if (tftpUploadBase(buf, bufLen, ip, "tmp2.txt") < 0)
    {
        printf("tftpUploadBase error.\r\n");
        return -1;
    }
#endif

    return 0;
}












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值