前几天在看一年前的代码,看到了以前为Windows CE写的内核下载工具-- Eshell.微软也有一个,但当时看了一下TFTP的协议,就自己"造轮子"了,现在把代码贴出来,由于协议描述是件很累人的事情,大家就结合起来看吧.
(协议参考: http://www.longen.org/S-Z/details~z/TFTPProtocol.htm)
调试函数文件:
//------------------------------------------------------------------------------
//
// File: debug.h
//
// TFTP source code.
//
//------------------------------------------------------------------------------
#ifndef __DEBUG_H
#define __DEBUG_H
void DEBUGMSG(const char* message,...);
#endif // DEBUG
//------------------------------------------------------------------------------
//
// File: debug.c
//
// TFTP source code.
//
//------------------------------------------------------------------------------
#include <stdarg.h>
#include <stdio.h>
#include "../include/debug.h"
#include <tchar.h>
#ifdef DEBUG
void DEBUGMSG(const char* format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
}
#else
void DEBUGMSG(const char* format, ...)
{
}
#endif
Packet.h定义了该TFTP协议的数据包格式: RequestPacket, DataPacket, AckPacket, ErrorPacket.根据名字就应该知道是什么意思了吧.
//------------------------------------------------------------------------------
//
// File: packet.h
//
// TFTP source code.
//
//------------------------------------------------------------------------------
#ifndef __PACKET_H
#define __PACKET_H
#include <windows.h>
#include <stdio.h>
#define FILE_SIZE 9
#define MODE_SIZE 6
#define DATA_SIZE 512
#define ERR_MSG_SIZE 42
#define DATA_PACKET_SIZE 516
#define TYPE_PACKET_SIZE 9
#define REQ 1
#define WRQ 2
#define DATA 3
#define ACK 4
#define ERR 5
// Packet Structure Description.
#pragma pack(1)
typedef struct _RequestPacket {
WORD Opcode;
TCHAR szFileName[FILE_SIZE];
TCHAR szMode[MODE_SIZE];
} RequestPacket, *PRequestPacket;
typedef struct _DataPacket {
WORD Opcode;
WORD BlockNo;
TCHAR szData[DATA_SIZE];
} DataPacket, *PDataPacket;
typedef struct __ACKPacket {
WORD Opcode;
WORD BlockNo;
} AckPacket, *PACKPacket;
typedef struct _ErrorPacket {
WORD Opcode;
WORD ErrorCode;
TCHAR szErrorMsg[ERR_MSG_SIZE];
} ErrorPacket, *PErrorPacket;
#pragma pack()
typedef enum {READ, WRITE}MODE;
typedef enum {BINARY, ASCII}TYPE;
// Operation Packet.
extern DataPacket MakeDataPacket(const TCHAR* szFileContent,
const int nMsgLength,
const int nBlockNo);
extern AckPacket MakeACKPacket(const int nBlockNo);
extern ErrorPacket MakeErrorPacket(const int nErrorId);
extern RequestPacket MakeRequestPacket(MODE mode,
TYPE type,
const TCHAR* szFileName);
extern void DisplayErrorMsg(const TCHAR* szMsg);
#endif // PACKET_H
-------------------------------------------------------------------------------------------------------------------------------------------
packet.cpp是packet.cpp的几个实现,如果现在写的话,肯定会用c++类来封装了,不过如果是应用于纯c环境
的话,可以考虑 用函数指针进行封装.
//------------------------------------------------------------------------------
//
// File: packet.c
//
// TFTP source code.
//
//------------------------------------------------------------------------------
#include "../include/packet.h"
#include <winsock2.h>
static TCHAR* szErrMsg[] = {TEXT("Not defined, see error message (if any)."),
TEXT("File not found."),
TEXT("Access violation."),
TEXT("Disk full or allocation exceeded."),
TEXT("Illegal TFTP operation."),
TEXT("Unknown transfer ID."),
TEXT("File already exists."),
TEXT("No such user.")};
//------------------------------------------------------------------------------
// Function : MakeDataPacket()
// Fill file content into data packet.
//
// Input:
// szMsg [in]: Pointer to a message string.
//
// nMsgLength[in]: Message length.
//
// nBlockNo: Number of data block.
//
// Output:
// DataPacket: Prepared data packet to send.
//------------------------------------------------------------------------------
DataPacket MakeDataPacket(const TCHAR* szFileContent,
const int nMsgLength,
const int nBlockNo)
{
DataPacket datapack;
datapack.Opcode = htons(DATA);
datapack.BlockNo = htons(nBlockNo);
ZeroMemory(datapack.szData, DATA_SIZE);
memcpy(datapack.szData, szFileContent, nMsgLength);
return datapack;
}
//------------------------------------------------------------------------------
// Function : MakeACKPacket()
// Make ACK packet for responding data packet.
//
// Input:
// nBlockNo [in]: Number of data block.
//
// Output:
// ACKPacket: Packet to response.
//------------------------------------------------------------------------------
AckPacket MakeACKPacket(const int nBlockNo)
{
AckPacket ackpack;
ackpack.Opcode = htons(ACK);
ackpack.BlockNo = htons(nBlockNo);
return ackpack;
}
//------------------------------------------------------------------------------
// Function : MakeErrorPacket()
// Make error packet for dealing with error message.
//
// Input:
// nErrorId [in]: Error Id to choose error text.
//
// Output:
// ErrorPacket: Error packet to response.
//------------------------------------------------------------------------------
ErrorPacket MakeErrorPacket(const int nErrorId)
{
ErrorPacket errpack;
errpack.Opcode = htons(ERR);
errpack.ErrorCode = htons(nErrorId);
ZeroMemory(errpack.szErrorMsg, ERR_MSG_SIZE);
strcpy(errpack.szErrorMsg, szErrMsg[nErrorId]);
return errpack;
}
//------------------------------------------------------------------------------
// Function : MakeRequestPacket()
// Make request packet for sending or receving message.
//
// Input:
// mode [in]: Pointer to a message string.
//
// type [in]: The way to open file.
//
// szFileName[in]: File name which is filled in request packet.
//
// Output:
// RequestPacket: packet to request.
//------------------------------------------------------------------------------
RequestPacket MakeRequestPacket(MODE mode, TYPE type, const TCHAR* szFileName)
{
RequestPacket reqpack;
if (mode == READ)
{
reqpack.Opcode = htons(REQ);
}
else
{
reqpack.Opcode = htons(WRQ);
}
strcpy(reqpack.szFileName, szFileName);
if (type == BINARY)
{
// Binary File.
strcpy(reqpack.szMode, TEXT("octet/0"));
}
if (type == ASCII)
{
// Text File.
strcpy(reqpack.szMode, TEXT("netascii"));
}
return reqpack;
}
//------------------------------------------------------------------------------
// Function : DisplayErrorMsg()
// Get message string according to error message ID.
//
// Input:
// szMsg [in]: Message from server.
//
// Output:
// None.
//------------------------------------------------------------------------------
void DisplayErrorMsg(const TCHAR* szMsg)
{
DEBUGMSG(szErrMsg[szMsg[3]]);
}
---------------------------------------------------------------------------------------------------------------------------------------------
由于以前项目是个DLL的项目,因此有个dll.h的文件提供接口:
//------------------------------------------------------------------------------
//
// File: dll.h
//
// TFTP source code.
//
//------------------------------------------------------------------------------
#ifndef __DLL_H
#define __DLL_H
#include "packet.h"
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else // Not BUILDING_DLL.
# define DLLIMPORT __declspec (dllimport)
#endif // Not BUILDING_DLL.
// Establish connection and initialize socket.
DLLIMPORT DWORD InitalConnection();
// Disconnect and cleanup socket.
DLLIMPORT int CleanupConnection();
// Client sends data packet to server and receives ACK packet from server.
DLLIMPORT int StartClient();
// Send "PUT”request to server and establish communication with server.
DLLIMPORT int HandShake();
// Get the size of file which has been sent to server.
DLLIMPORT int GetSendData();
// Set TFTP parameters: IP address and port.
DLLIMPORT void SetTFTP(const TCHAR* szAddress, const int nPort);
// Set the name of file which is sent to server.
DLLIMPORT void SetFileName(const TCHAR* szFileName);
// Get the size of file which is sent to server.
DLLIMPORT int DoGetFileSize();
#endif // DLL_H
----------------------------------------------------------------------------------------------------------------------------------------------------
下面就是TFTP.c的描述了,代码比较长,下面两个东西值得注意,DEFAULT_FILENAME是boot.bin完全可以换成
nk.bin (boot.bin是Windows Mobile的bootloader文件, nk.bin是内核文件)
"192.168.100.101"和980分别对应Mobile上面的IP地址和端口号.
///------------------------------------------------------------------------------
//
// File: Tftp.c
//
// TFTP source code
//
//------------------------------------------------------------------------------
#define TRANSFER_OVER 0x01
#define ERROR_PACKET 0x02
#define TIME_OUT 0x03
#include "../include/dll.h"
// Internally used variables.
static SOCKET sock;
static SOCKADDR_IN fromaddr;
static HANDLE g_FileHandle = NULL;
static int HOST_SIZE = 1024;
static TCHAR* DEFAULT_FILENAME = TEXT("boot.bin/0");
static TCHAR g_FileName[128];
static TCHAR g_Address[16] = TEXT("192.168.100.101");
const int g_Port = 980;
static int nMsgLength = 0;
static WORD nBlockNo = 1;
static int g_nSendDataBytes = 0;
TCHAR pszSendBuffer[DATA_SIZE] = {0};
TCHAR szMsg[DATA_PACKET_SIZE] ={0};
// Internally used functions.
static int SendRequestPacket(const TCHAR* szFileName, TYPE type, MODE mode);
static int SendACKPacket(const int nBlockNo);
static int SendDataPacket(const DataPacket datapacket, const int nDataLength);
static int SendErrorPacket(const int ErrorId);
static int ProcessMsg(const TCHAR* szMsg, const int nMsgLength);
static int GetFile(const TCHAR* szMsg, const int nMsgLength);
static int PutFile(const TCHAR* szMsg, const int nMsgLength);
static int ReceiveMsg(TCHAR* szMsg);
static int PrePareFile(const TCHAR* szFileName, MODE mode);
static WORD GetFileInfo(const TCHAR* szMsg, MODE mode);
static WORD GetBlockNo(TCHAR hightByte, TCHAR lowByte);
//------------------------------------------------------------------------------
// Function : InitalConnection()
// Establish connection and initalize socket.
//
// Input:
// None.
//
// Output:
// 0: Initialize connection successfully, otherwise, return GetLastError().
//------------------------------------------------------------------------------
DLLIMPORT DWORD InitalConnection()
{
WSADATA wsaData;
WORD wVersionRequested;
SOCKADDR_IN skaddr;
int nReturn;
wVersionRequested = MAKEWORD(2, 2);
nReturn = WSAStartup(wVersionRequested, &wsaData);
if (nReturn != 0)
{
return GetLastError();
}
if (LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 2)
{
WSACleanup();
return GetLastError();
}
// Create socket based on UDP/IP protocol.
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (INVALID_SOCKET == sock)
{
return GetLastError();
}
#ifdef SERVER
skaddr.sin_family = AF_INET;
skaddr.sin_port = htons(DEFAULT_PORT);
skaddr.sin_addr.s_addr = inet_addr(DEFAULT_ADDRESS);
#else
skaddr.sin_family = AF_INET;
skaddr.sin_port = INADDR_ANY;
skaddr.sin_addr.s_addr = INADDR_ANY;
#endif
// Bind address to socket.
nReturn = bind(sock, (struct sockaddr *)&skaddr, sizeof(skaddr));
if(nReturn != 0)
{
return GetLastError();
}
return 0;
}
//------------------------------------------------------------------------------
// Function : CleanupConnection()
// Disconnect and cleanup socket.
//
// Input:
// None.
//
// Output:
// 0.
//------------------------------------------------------------------------------
DLLIMPORT int CleanupConnection()
{
nBlockNo = 0;
g_nSendDataBytes = 0;
if (g_FileHandle)
{
CloseHandle(g_FileHandle);
}
WSACleanup();
closesocket(sock);
return 0;
}
//------------------------------------------------------------------------------
// Function : SendACKPacket()
// Send ACK packet to client.
//
// Input:
// nBlockNo [in]: Number of block.
//
// Output:
// 0: Send ACK packet successfully.
//------------------------------------------------------------------------------
static int SendACKPacket(const int nBlockNo)
{
AckPacket ackpacket = MakeACKPacket(nBlockNo);
DEBUGMSG(TEXT("Send Block: %d/n"), nBlockNo);
int nSendACKBytes = sendto(sock,
(const TCHAR*)&ackpacket,
sizeof(ackpacket),
0,
(struct sockaddr*)&fromaddr,
sizeof(fromaddr));
if (SOCKET_ERROR == nSendACKBytes)
{
return GetLastError();
}
return 0;
}
//------------------------------------------------------------------------------
// Function : SendDataPacket()
// Send data packet to client.
//
// Input:
// datapacket [in]: Number of block.
// nDataLength [in]: Length of data.
//
// Output:
// 0: Send data packet successfully.
//------------------------------------------------------------------------------
static int SendDataPacket(const DataPacket datapacket, const int nDataLength)
{
g_nSendDataBytes += sendto(sock,
(const TCHAR*)&datapacket,
4 + nDataLength,
0,
(struct sockaddr*)&fromaddr,
sizeof(fromaddr));
if (SOCKET_ERROR == g_nSendDataBytes)
{
return GetLastError();
}
return 0;
}
//------------------------------------------------------------------------------
// Function : DispatchMsg()
// This function is used for server side to deal with message.
// szMsg[1] == REQ: Get read request.
// szMsg[1] == WRQ: Get write request.
// szMsg[1] == DATA: Get data packet and send ack packet.
// szMsg[1] == ACK: Get ack packet and send data packet.
// szMsg[1] == ERROR: Send error packet.
//
// Input:
// datapacket [in]: Number of block.
// nDataLength [in]: Length of data.
//
// Output:
// 0: Send data packet successfully.
//------------------------------------------------------------------------------
static int ProcessMsg(const TCHAR* szMsg, const int nMsgLength)
{
int nReturn = 0;
switch(szMsg[1])
{
case REQ:
nReturn = GetFileInfo(szMsg, READ);
nReturn = GetFile(szMsg, nMsgLength);
break;
case WRQ:
nReturn = GetFileInfo(szMsg, WRITE);
nReturn = SendACKPacket(0);
break;
case DATA:
nReturn = PutFile(szMsg, nMsgLength);
break;
case ACK:
nReturn = GetFile(szMsg, nMsgLength);
break;
case ERR:
nReturn = ERROR_PACKET;
break;
}
return nReturn;
}
//------------------------------------------------------------------------------
// Function : GetFile()
// Get read request from client, read data from file and send data to client.
//
// Input:
// *fp [in]: Pointer to file.
//
// Output:
// 0: Get File Successfully.
// TRANSFER_OVER: Read end of file.
//------------------------------------------------------------------------------
static int GetFile(const TCHAR* szMsg, const int nMsgLength)
{
DWORD nBytes;
int nReturn = 0;
static BOOL bFirst = TRUE;
WORD wDummy = GetBlockNo(szMsg[2], szMsg[3]);
if (!g_FileHandle || !pszSendBuffer)
{
return FALSE;
}
if (wDummy == nBlockNo || bFirst == TRUE)
{
// Read File to Buffer.
if(!ReadFile(g_FileHandle, pszSendBuffer, DATA_SIZE, &nBytes, NULL))
{
bFirst = TRUE;
CloseHandle(g_FileHandle);
return GetLastError();
}
if (bFirst == FALSE)
{
nBlockNo++;
}
} // if (wDummy == nBlockNo || bFirst == TRUE)
DEBUGMSG(TEXT("Receive BlockNo: %d"), wDummy);
DataPacket datapack = MakeDataPacket(pszSendBuffer, nBytes, nBlockNo);
DEBUGMSG(TEXT("Send BlockNo: %d/n"), nBlockNo);
// Send Buffer To Client.
nReturn = SendDataPacket(datapack, nBytes);
if (nBytes < DATA_SIZE && nReturn == 0)
{
nReturn = TRANSFER_OVER;
bFirst = TRUE;
}
bFirst = FALSE;
return nReturn;
}
//------------------------------------------------------------------------------
// Function : PutFile()
// Get write request, write data to local server file and send ack packet to
// client.
//
// Input:
// *fp [in]: Pointer to file.
// *szMsg [in]: Pointer to message.
// nMsgLength [in]: Length of message.
//
// Output:
// 0: Put file successfully.
// TRANSFER_OVER: Write end of file.
//------------------------------------------------------------------------------
static int PutFile(const TCHAR* szMsg, const int nMsgLength)
{
DWORD nWriteBytes;
int nReturn = 0;
nBlockNo = GetBlockNo(szMsg[2], szMsg[3]);
DEBUGMSG (TEXT("Receive BlockNo:%d/n"), nBlockNo);
if(!WriteFile(g_FileHandle, szMsg + 4, nMsgLength - 4, &nWriteBytes, NULL))
{
DEBUGMSG(TEXT("Write file error/n"));
CloseHandle(g_FileHandle);
return GetLastError();
}
nReturn = SendACKPacket(nBlockNo);
if (nWriteBytes < DATA_SIZE && nReturn == 0)
{
nReturn = TRANSFER_OVER;
CloseHandle(g_FileHandle);
}
return nReturn;
}
//------------------------------------------------------------------------------
// Function : ReceiveMsg()
// Receive message from client to fill message buffer.
//
// Input:
// szMsg [in]: Message buffer.
//
// Output:
// nMsgLength: Length of filled message.
//------------------------------------------------------------------------------
static int ReceiveMsg(TCHAR* szMsg)
{
int nLength = sizeof(fromaddr);
nMsgLength = 0;
int nTimeout = 1000;
ZeroMemory(szMsg, DATA_PACKET_SIZE);
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeout, sizeof(int));
nMsgLength = recvfrom(sock, szMsg, DATA_PACKET_SIZE, 0,
(struct sockaddr*)&fromaddr, &nLength);
return nMsgLength;
}
//------------------------------------------------------------------------------
// Function : PrePareFile()
// Client sends request packet to server and establish connection.
//
// Input:
// szFileName [in]: File name.
// mode [in]: Read or Write.
//
// Output:
// 0: Prepare file successfully and create a new file handler.
//------------------------------------------------------------------------------
static int PrePareFile(const TCHAR* szFileName, MODE mode)
{
if (mode == READ)
{
g_FileHandle = CreateFile(szFileName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
DEBUGMSG(TEXT("In read file/n"));
}
else if (mode == WRITE)
{
g_FileHandle = CreateFile(szFileName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
DEBUGMSG(TEXT("In write file/n"));
}
if (g_FileHandle == INVALID_HANDLE_VALUE)
{
DEBUGMSG(TEXT("file is invalid/n"));
return GetLastError();
}
return 0;
}
//------------------------------------------------------------------------------
// Function : GetFileInfo()
// Get file name and file type.
//
// Input:
// szMsg [in]: Pointer to a message string.
//
// MODE [in]: The way to open file.
//
// Output:
// 0: Get file information successfully.
//------------------------------------------------------------------------------
static WORD GetFileInfo(const TCHAR* szMsg, MODE mode)
{
TCHAR szFileName[FILE_SIZE];
int nFilePos = 0;
int loop = 0;
int nReturn = 0;
// Get File Name.
for(loop = 2; loop < DATA_PACKET_SIZE ; loop++)
{
szFileName[nFilePos++] = szMsg[loop];
if (szMsg[loop] == 0)
{
break;
}
} // End of for.
loop++;
DEBUGMSG(TEXT("File Name is: %s/n"), szFileName);
nReturn = PrePareFile(szFileName, mode);
return nReturn;
}
//------------------------------------------------------------------------------
// Function : GetBlockNo()
// High byte and low byte combine block number.
//
// Input:
// highByte [in]: Second byte of Message.
//
// lowByte [in]: Third byte of Message.
//
// Output:
// wDummy: Block number.
//------------------------------------------------------------------------------
static WORD GetBlockNo(TCHAR hightByte, TCHAR lowByte)
{
WORD wDummy = 0;
wDummy = hightByte;
wDummy <<= 8;
wDummy |= lowByte & 0x00ff;
return wDummy;
}
//------------------------------------------------------------------------------
// Function : SendRequestPacket()
// Client sends request packet to server and establishes connection.
//
// Input:
// None.
//
// Output:
// 0: Rebind socket successfully.
//------------------------------------------------------------------------------
static int SendRequestPacket(const TCHAR* szFileName, TYPE type, MODE mode)
{
RequestPacket reqpack = MakeRequestPacket(mode, type, szFileName);
fromaddr.sin_port = htons(g_Port);
fromaddr.sin_family = AF_INET;
fromaddr.sin_addr.s_addr = inet_addr(g_Address);
int nSendReqBytes = sendto(sock,
(const TCHAR*)&reqpack,
sizeof(reqpack),
0,
(struct sockaddr*)&fromaddr,
sizeof(fromaddr));
return nSendReqBytes;
}
//------------------------------------------------------------------------------
// Function : SendErrorPacket()
// Send error packet to server.
//
// Input:
// None.
//
// Output:
// 0: Send error packet successfully.
//------------------------------------------------------------------------------
static int SendErrorPacket(const int ErrorId)
{
ErrorPacket errpack = MakeErrorPacket(ErrorId);
int nSendErrBytes = sendto(sock,
(const TCHAR*)&errpack,
sizeof(errpack),
0,
(struct sockaddr*)&fromaddr,
sizeof(fromaddr));
DEBUGMSG(TEXT("Error packet size: %d/n"), nSendErrBytes);
return nSendErrBytes;
}
//------------------------------------------------------------------------------
// Function : SetTFTP()
// Set TFTP parameters: IP address and port.
//
// Input:
// szAddress [in]: IP address of target device.
// nPort [in]: port of target device.
//
// Output:
// None.
//------------------------------------------------------------------------------
DLLIMPORT void SetTFTP(const TCHAR* szAddress, const int nPort)
{
strcpy(g_Address, szAddress);
}
//------------------------------------------------------------------------------
// Function : SetFileName()
// Set the name of file which is sent to server.
//
// Input:
// None.
//
// Output:
// None.
//------------------------------------------------------------------------------
DLLIMPORT void SetFileName(const TCHAR* szFileName)
{
strcpy(g_FileName, szFileName);
}
//------------------------------------------------------------------------------
// Function : HandShake()
// Sends "PUT" request to server and establish communication with server.
//
// Input:
// None.
//
// Output:
// 0: Handshake with server successfully, otherwise return GetLastError().
//------------------------------------------------------------------------------
DLLIMPORT int HandShake()
{
int nRetry = 20;
int nResult = 0;
while (1)
{
// Send Request Message.
if (SendRequestPacket(DEFAULT_FILENAME, BINARY, WRITE) == SOCKET_ERROR)
{
return GetLastError();
}
// Get Message.
nResult = ReceiveMsg(szMsg);
if (nResult < 0)
{
if (GetLastError() != WSAETIMEDOUT)
{
CleanupConnection();
return GetLastError();
}
else
{
nRetry--;
// Time Out.
if (nRetry == 0)
{
CleanupConnection();
return WSAETIMEDOUT;
}
Sleep(1000);
}
}
else
{
break;
} // End of if (nResult < 0).
}
if (PrePareFile(g_FileName, READ) != 0)
{
CleanupConnection();
SendErrorPacket(1);
return GetLastError();
}
return 0;
}
//------------------------------------------------------------------------------
// Function : StartClient()
// Client sends data packet to server and receives ACK packet from server.
//
// Input:
// None.
//
// Output:
// 0: Client sends server image file successfully.
//------------------------------------------------------------------------------
DLLIMPORT int StartClient()
{
int nResult = 0;
int nRetry = 10;
while(1)
{
nResult = ProcessMsg(szMsg, nMsgLength);
if (nResult == TRANSFER_OVER)
{
DEBUGMSG(TEXT("Transfer over/n"));
break;
}
if (nResult != 0)
{
DEBUGMSG(TEXT("Error occur, error code = %d/n"), GetLastError());
break;
}
nMsgLength = ReceiveMsg(szMsg);
if (nMsgLength < 0)
{
if (GetLastError() != WSAETIMEDOUT)
{
nResult = GetLastError();
}
else
{
if (nRetry == 0)
{
nResult = WSAETIMEDOUT;
break;
}
nRetry--;
Sleep(1000);
}
}
else
{
nRetry = 20;
} // End of if (nMsgLength < 0).
} // End while.
CleanupConnection();
return nResult;
}
//------------------------------------------------------------------------------
// Function : GetSendData()
// Get the size of file which has been sent to server.
//
// Input:
// None.
//
// Output:
// int: The size of file which has been sent.
//------------------------------------------------------------------------------
DLLIMPORT int GetSendData()
{
g_nSendDataBytes -= 4;
return g_nSendDataBytes;
}
//------------------------------------------------------------------------------
// Function : DoGetFileSize()
// Get the size of file which is sent to server.
//
// Input:
// None.
//
// Output:
// int: The size of file.
//------------------------------------------------------------------------------
DLLIMPORT int DoGetFileSize()
{
int nFileSize = GetFileSize(g_FileHandle, (LPDWORD) NULL);
return nFileSize;
}
(协议参考: http://www.longen.org/S-Z/details~z/TFTPProtocol.htm)
调试函数文件:
//------------------------------------------------------------------------------
//
// File: debug.h
//
// TFTP source code.
//
//------------------------------------------------------------------------------
#ifndef __DEBUG_H
#define __DEBUG_H
void DEBUGMSG(const char* message,...);
#endif // DEBUG
//------------------------------------------------------------------------------
//
// File: debug.c
//
// TFTP source code.
//
//------------------------------------------------------------------------------
#include <stdarg.h>
#include <stdio.h>
#include "../include/debug.h"
#include <tchar.h>
#ifdef DEBUG
void DEBUGMSG(const char* format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
}
#else
void DEBUGMSG(const char* format, ...)
{
}
#endif
Packet.h定义了该TFTP协议的数据包格式: RequestPacket, DataPacket, AckPacket, ErrorPacket.根据名字就应该知道是什么意思了吧.
//------------------------------------------------------------------------------
//
// File: packet.h
//
// TFTP source code.
//
//------------------------------------------------------------------------------
#ifndef __PACKET_H
#define __PACKET_H
#include <windows.h>
#include <stdio.h>
#define FILE_SIZE 9
#define MODE_SIZE 6
#define DATA_SIZE 512
#define ERR_MSG_SIZE 42
#define DATA_PACKET_SIZE 516
#define TYPE_PACKET_SIZE 9
#define REQ 1
#define WRQ 2
#define DATA 3
#define ACK 4
#define ERR 5
// Packet Structure Description.
#pragma pack(1)
typedef struct _RequestPacket {
WORD Opcode;
TCHAR szFileName[FILE_SIZE];
TCHAR szMode[MODE_SIZE];
} RequestPacket, *PRequestPacket;
typedef struct _DataPacket {
WORD Opcode;
WORD BlockNo;
TCHAR szData[DATA_SIZE];
} DataPacket, *PDataPacket;
typedef struct __ACKPacket {
WORD Opcode;
WORD BlockNo;
} AckPacket, *PACKPacket;
typedef struct _ErrorPacket {
WORD Opcode;
WORD ErrorCode;
TCHAR szErrorMsg[ERR_MSG_SIZE];
} ErrorPacket, *PErrorPacket;
#pragma pack()
typedef enum {READ, WRITE}MODE;
typedef enum {BINARY, ASCII}TYPE;
// Operation Packet.
extern DataPacket MakeDataPacket(const TCHAR* szFileContent,
const int nMsgLength,
const int nBlockNo);
extern AckPacket MakeACKPacket(const int nBlockNo);
extern ErrorPacket MakeErrorPacket(const int nErrorId);
extern RequestPacket MakeRequestPacket(MODE mode,
TYPE type,
const TCHAR* szFileName);
extern void DisplayErrorMsg(const TCHAR* szMsg);
#endif // PACKET_H
-------------------------------------------------------------------------------------------------------------------------------------------
packet.cpp是packet.cpp的几个实现,如果现在写的话,肯定会用c++类来封装了,不过如果是应用于纯c环境
的话,可以考虑 用函数指针进行封装.
//------------------------------------------------------------------------------
//
// File: packet.c
//
// TFTP source code.
//
//------------------------------------------------------------------------------
#include "../include/packet.h"
#include <winsock2.h>
static TCHAR* szErrMsg[] = {TEXT("Not defined, see error message (if any)."),
TEXT("File not found."),
TEXT("Access violation."),
TEXT("Disk full or allocation exceeded."),
TEXT("Illegal TFTP operation."),
TEXT("Unknown transfer ID."),
TEXT("File already exists."),
TEXT("No such user.")};
//------------------------------------------------------------------------------
// Function : MakeDataPacket()
// Fill file content into data packet.
//
// Input:
// szMsg [in]: Pointer to a message string.
//
// nMsgLength[in]: Message length.
//
// nBlockNo: Number of data block.
//
// Output:
// DataPacket: Prepared data packet to send.
//------------------------------------------------------------------------------
DataPacket MakeDataPacket(const TCHAR* szFileContent,
const int nMsgLength,
const int nBlockNo)
{
DataPacket datapack;
datapack.Opcode = htons(DATA);
datapack.BlockNo = htons(nBlockNo);
ZeroMemory(datapack.szData, DATA_SIZE);
memcpy(datapack.szData, szFileContent, nMsgLength);
return datapack;
}
//------------------------------------------------------------------------------
// Function : MakeACKPacket()
// Make ACK packet for responding data packet.
//
// Input:
// nBlockNo [in]: Number of data block.
//
// Output:
// ACKPacket: Packet to response.
//------------------------------------------------------------------------------
AckPacket MakeACKPacket(const int nBlockNo)
{
AckPacket ackpack;
ackpack.Opcode = htons(ACK);
ackpack.BlockNo = htons(nBlockNo);
return ackpack;
}
//------------------------------------------------------------------------------
// Function : MakeErrorPacket()
// Make error packet for dealing with error message.
//
// Input:
// nErrorId [in]: Error Id to choose error text.
//
// Output:
// ErrorPacket: Error packet to response.
//------------------------------------------------------------------------------
ErrorPacket MakeErrorPacket(const int nErrorId)
{
ErrorPacket errpack;
errpack.Opcode = htons(ERR);
errpack.ErrorCode = htons(nErrorId);
ZeroMemory(errpack.szErrorMsg, ERR_MSG_SIZE);
strcpy(errpack.szErrorMsg, szErrMsg[nErrorId]);
return errpack;
}
//------------------------------------------------------------------------------
// Function : MakeRequestPacket()
// Make request packet for sending or receving message.
//
// Input:
// mode [in]: Pointer to a message string.
//
// type [in]: The way to open file.
//
// szFileName[in]: File name which is filled in request packet.
//
// Output:
// RequestPacket: packet to request.
//------------------------------------------------------------------------------
RequestPacket MakeRequestPacket(MODE mode, TYPE type, const TCHAR* szFileName)
{
RequestPacket reqpack;
if (mode == READ)
{
reqpack.Opcode = htons(REQ);
}
else
{
reqpack.Opcode = htons(WRQ);
}
strcpy(reqpack.szFileName, szFileName);
if (type == BINARY)
{
// Binary File.
strcpy(reqpack.szMode, TEXT("octet/0"));
}
if (type == ASCII)
{
// Text File.
strcpy(reqpack.szMode, TEXT("netascii"));
}
return reqpack;
}
//------------------------------------------------------------------------------
// Function : DisplayErrorMsg()
// Get message string according to error message ID.
//
// Input:
// szMsg [in]: Message from server.
//
// Output:
// None.
//------------------------------------------------------------------------------
void DisplayErrorMsg(const TCHAR* szMsg)
{
DEBUGMSG(szErrMsg[szMsg[3]]);
}
---------------------------------------------------------------------------------------------------------------------------------------------
由于以前项目是个DLL的项目,因此有个dll.h的文件提供接口:
//------------------------------------------------------------------------------
//
// File: dll.h
//
// TFTP source code.
//
//------------------------------------------------------------------------------
#ifndef __DLL_H
#define __DLL_H
#include "packet.h"
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else // Not BUILDING_DLL.
# define DLLIMPORT __declspec (dllimport)
#endif // Not BUILDING_DLL.
// Establish connection and initialize socket.
DLLIMPORT DWORD InitalConnection();
// Disconnect and cleanup socket.
DLLIMPORT int CleanupConnection();
// Client sends data packet to server and receives ACK packet from server.
DLLIMPORT int StartClient();
// Send "PUT”request to server and establish communication with server.
DLLIMPORT int HandShake();
// Get the size of file which has been sent to server.
DLLIMPORT int GetSendData();
// Set TFTP parameters: IP address and port.
DLLIMPORT void SetTFTP(const TCHAR* szAddress, const int nPort);
// Set the name of file which is sent to server.
DLLIMPORT void SetFileName(const TCHAR* szFileName);
// Get the size of file which is sent to server.
DLLIMPORT int DoGetFileSize();
#endif // DLL_H
----------------------------------------------------------------------------------------------------------------------------------------------------
下面就是TFTP.c的描述了,代码比较长,下面两个东西值得注意,DEFAULT_FILENAME是boot.bin完全可以换成
nk.bin (boot.bin是Windows Mobile的bootloader文件, nk.bin是内核文件)
"192.168.100.101"和980分别对应Mobile上面的IP地址和端口号.
///------------------------------------------------------------------------------
//
// File: Tftp.c
//
// TFTP source code
//
//------------------------------------------------------------------------------
#define TRANSFER_OVER 0x01
#define ERROR_PACKET 0x02
#define TIME_OUT 0x03
#include "../include/dll.h"
// Internally used variables.
static SOCKET sock;
static SOCKADDR_IN fromaddr;
static HANDLE g_FileHandle = NULL;
static int HOST_SIZE = 1024;
static TCHAR* DEFAULT_FILENAME = TEXT("boot.bin/0");
static TCHAR g_FileName[128];
static TCHAR g_Address[16] = TEXT("192.168.100.101");
const int g_Port = 980;
static int nMsgLength = 0;
static WORD nBlockNo = 1;
static int g_nSendDataBytes = 0;
TCHAR pszSendBuffer[DATA_SIZE] = {0};
TCHAR szMsg[DATA_PACKET_SIZE] ={0};
// Internally used functions.
static int SendRequestPacket(const TCHAR* szFileName, TYPE type, MODE mode);
static int SendACKPacket(const int nBlockNo);
static int SendDataPacket(const DataPacket datapacket, const int nDataLength);
static int SendErrorPacket(const int ErrorId);
static int ProcessMsg(const TCHAR* szMsg, const int nMsgLength);
static int GetFile(const TCHAR* szMsg, const int nMsgLength);
static int PutFile(const TCHAR* szMsg, const int nMsgLength);
static int ReceiveMsg(TCHAR* szMsg);
static int PrePareFile(const TCHAR* szFileName, MODE mode);
static WORD GetFileInfo(const TCHAR* szMsg, MODE mode);
static WORD GetBlockNo(TCHAR hightByte, TCHAR lowByte);
//------------------------------------------------------------------------------
// Function : InitalConnection()
// Establish connection and initalize socket.
//
// Input:
// None.
//
// Output:
// 0: Initialize connection successfully, otherwise, return GetLastError().
//------------------------------------------------------------------------------
DLLIMPORT DWORD InitalConnection()
{
WSADATA wsaData;
WORD wVersionRequested;
SOCKADDR_IN skaddr;
int nReturn;
wVersionRequested = MAKEWORD(2, 2);
nReturn = WSAStartup(wVersionRequested, &wsaData);
if (nReturn != 0)
{
return GetLastError();
}
if (LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 2)
{
WSACleanup();
return GetLastError();
}
// Create socket based on UDP/IP protocol.
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (INVALID_SOCKET == sock)
{
return GetLastError();
}
#ifdef SERVER
skaddr.sin_family = AF_INET;
skaddr.sin_port = htons(DEFAULT_PORT);
skaddr.sin_addr.s_addr = inet_addr(DEFAULT_ADDRESS);
#else
skaddr.sin_family = AF_INET;
skaddr.sin_port = INADDR_ANY;
skaddr.sin_addr.s_addr = INADDR_ANY;
#endif
// Bind address to socket.
nReturn = bind(sock, (struct sockaddr *)&skaddr, sizeof(skaddr));
if(nReturn != 0)
{
return GetLastError();
}
return 0;
}
//------------------------------------------------------------------------------
// Function : CleanupConnection()
// Disconnect and cleanup socket.
//
// Input:
// None.
//
// Output:
// 0.
//------------------------------------------------------------------------------
DLLIMPORT int CleanupConnection()
{
nBlockNo = 0;
g_nSendDataBytes = 0;
if (g_FileHandle)
{
CloseHandle(g_FileHandle);
}
WSACleanup();
closesocket(sock);
return 0;
}
//------------------------------------------------------------------------------
// Function : SendACKPacket()
// Send ACK packet to client.
//
// Input:
// nBlockNo [in]: Number of block.
//
// Output:
// 0: Send ACK packet successfully.
//------------------------------------------------------------------------------
static int SendACKPacket(const int nBlockNo)
{
AckPacket ackpacket = MakeACKPacket(nBlockNo);
DEBUGMSG(TEXT("Send Block: %d/n"), nBlockNo);
int nSendACKBytes = sendto(sock,
(const TCHAR*)&ackpacket,
sizeof(ackpacket),
0,
(struct sockaddr*)&fromaddr,
sizeof(fromaddr));
if (SOCKET_ERROR == nSendACKBytes)
{
return GetLastError();
}
return 0;
}
//------------------------------------------------------------------------------
// Function : SendDataPacket()
// Send data packet to client.
//
// Input:
// datapacket [in]: Number of block.
// nDataLength [in]: Length of data.
//
// Output:
// 0: Send data packet successfully.
//------------------------------------------------------------------------------
static int SendDataPacket(const DataPacket datapacket, const int nDataLength)
{
g_nSendDataBytes += sendto(sock,
(const TCHAR*)&datapacket,
4 + nDataLength,
0,
(struct sockaddr*)&fromaddr,
sizeof(fromaddr));
if (SOCKET_ERROR == g_nSendDataBytes)
{
return GetLastError();
}
return 0;
}
//------------------------------------------------------------------------------
// Function : DispatchMsg()
// This function is used for server side to deal with message.
// szMsg[1] == REQ: Get read request.
// szMsg[1] == WRQ: Get write request.
// szMsg[1] == DATA: Get data packet and send ack packet.
// szMsg[1] == ACK: Get ack packet and send data packet.
// szMsg[1] == ERROR: Send error packet.
//
// Input:
// datapacket [in]: Number of block.
// nDataLength [in]: Length of data.
//
// Output:
// 0: Send data packet successfully.
//------------------------------------------------------------------------------
static int ProcessMsg(const TCHAR* szMsg, const int nMsgLength)
{
int nReturn = 0;
switch(szMsg[1])
{
case REQ:
nReturn = GetFileInfo(szMsg, READ);
nReturn = GetFile(szMsg, nMsgLength);
break;
case WRQ:
nReturn = GetFileInfo(szMsg, WRITE);
nReturn = SendACKPacket(0);
break;
case DATA:
nReturn = PutFile(szMsg, nMsgLength);
break;
case ACK:
nReturn = GetFile(szMsg, nMsgLength);
break;
case ERR:
nReturn = ERROR_PACKET;
break;
}
return nReturn;
}
//------------------------------------------------------------------------------
// Function : GetFile()
// Get read request from client, read data from file and send data to client.
//
// Input:
// *fp [in]: Pointer to file.
//
// Output:
// 0: Get File Successfully.
// TRANSFER_OVER: Read end of file.
//------------------------------------------------------------------------------
static int GetFile(const TCHAR* szMsg, const int nMsgLength)
{
DWORD nBytes;
int nReturn = 0;
static BOOL bFirst = TRUE;
WORD wDummy = GetBlockNo(szMsg[2], szMsg[3]);
if (!g_FileHandle || !pszSendBuffer)
{
return FALSE;
}
if (wDummy == nBlockNo || bFirst == TRUE)
{
// Read File to Buffer.
if(!ReadFile(g_FileHandle, pszSendBuffer, DATA_SIZE, &nBytes, NULL))
{
bFirst = TRUE;
CloseHandle(g_FileHandle);
return GetLastError();
}
if (bFirst == FALSE)
{
nBlockNo++;
}
} // if (wDummy == nBlockNo || bFirst == TRUE)
DEBUGMSG(TEXT("Receive BlockNo: %d"), wDummy);
DataPacket datapack = MakeDataPacket(pszSendBuffer, nBytes, nBlockNo);
DEBUGMSG(TEXT("Send BlockNo: %d/n"), nBlockNo);
// Send Buffer To Client.
nReturn = SendDataPacket(datapack, nBytes);
if (nBytes < DATA_SIZE && nReturn == 0)
{
nReturn = TRANSFER_OVER;
bFirst = TRUE;
}
bFirst = FALSE;
return nReturn;
}
//------------------------------------------------------------------------------
// Function : PutFile()
// Get write request, write data to local server file and send ack packet to
// client.
//
// Input:
// *fp [in]: Pointer to file.
// *szMsg [in]: Pointer to message.
// nMsgLength [in]: Length of message.
//
// Output:
// 0: Put file successfully.
// TRANSFER_OVER: Write end of file.
//------------------------------------------------------------------------------
static int PutFile(const TCHAR* szMsg, const int nMsgLength)
{
DWORD nWriteBytes;
int nReturn = 0;
nBlockNo = GetBlockNo(szMsg[2], szMsg[3]);
DEBUGMSG (TEXT("Receive BlockNo:%d/n"), nBlockNo);
if(!WriteFile(g_FileHandle, szMsg + 4, nMsgLength - 4, &nWriteBytes, NULL))
{
DEBUGMSG(TEXT("Write file error/n"));
CloseHandle(g_FileHandle);
return GetLastError();
}
nReturn = SendACKPacket(nBlockNo);
if (nWriteBytes < DATA_SIZE && nReturn == 0)
{
nReturn = TRANSFER_OVER;
CloseHandle(g_FileHandle);
}
return nReturn;
}
//------------------------------------------------------------------------------
// Function : ReceiveMsg()
// Receive message from client to fill message buffer.
//
// Input:
// szMsg [in]: Message buffer.
//
// Output:
// nMsgLength: Length of filled message.
//------------------------------------------------------------------------------
static int ReceiveMsg(TCHAR* szMsg)
{
int nLength = sizeof(fromaddr);
nMsgLength = 0;
int nTimeout = 1000;
ZeroMemory(szMsg, DATA_PACKET_SIZE);
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeout, sizeof(int));
nMsgLength = recvfrom(sock, szMsg, DATA_PACKET_SIZE, 0,
(struct sockaddr*)&fromaddr, &nLength);
return nMsgLength;
}
//------------------------------------------------------------------------------
// Function : PrePareFile()
// Client sends request packet to server and establish connection.
//
// Input:
// szFileName [in]: File name.
// mode [in]: Read or Write.
//
// Output:
// 0: Prepare file successfully and create a new file handler.
//------------------------------------------------------------------------------
static int PrePareFile(const TCHAR* szFileName, MODE mode)
{
if (mode == READ)
{
g_FileHandle = CreateFile(szFileName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
DEBUGMSG(TEXT("In read file/n"));
}
else if (mode == WRITE)
{
g_FileHandle = CreateFile(szFileName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
DEBUGMSG(TEXT("In write file/n"));
}
if (g_FileHandle == INVALID_HANDLE_VALUE)
{
DEBUGMSG(TEXT("file is invalid/n"));
return GetLastError();
}
return 0;
}
//------------------------------------------------------------------------------
// Function : GetFileInfo()
// Get file name and file type.
//
// Input:
// szMsg [in]: Pointer to a message string.
//
// MODE [in]: The way to open file.
//
// Output:
// 0: Get file information successfully.
//------------------------------------------------------------------------------
static WORD GetFileInfo(const TCHAR* szMsg, MODE mode)
{
TCHAR szFileName[FILE_SIZE];
int nFilePos = 0;
int loop = 0;
int nReturn = 0;
// Get File Name.
for(loop = 2; loop < DATA_PACKET_SIZE ; loop++)
{
szFileName[nFilePos++] = szMsg[loop];
if (szMsg[loop] == 0)
{
break;
}
} // End of for.
loop++;
DEBUGMSG(TEXT("File Name is: %s/n"), szFileName);
nReturn = PrePareFile(szFileName, mode);
return nReturn;
}
//------------------------------------------------------------------------------
// Function : GetBlockNo()
// High byte and low byte combine block number.
//
// Input:
// highByte [in]: Second byte of Message.
//
// lowByte [in]: Third byte of Message.
//
// Output:
// wDummy: Block number.
//------------------------------------------------------------------------------
static WORD GetBlockNo(TCHAR hightByte, TCHAR lowByte)
{
WORD wDummy = 0;
wDummy = hightByte;
wDummy <<= 8;
wDummy |= lowByte & 0x00ff;
return wDummy;
}
//------------------------------------------------------------------------------
// Function : SendRequestPacket()
// Client sends request packet to server and establishes connection.
//
// Input:
// None.
//
// Output:
// 0: Rebind socket successfully.
//------------------------------------------------------------------------------
static int SendRequestPacket(const TCHAR* szFileName, TYPE type, MODE mode)
{
RequestPacket reqpack = MakeRequestPacket(mode, type, szFileName);
fromaddr.sin_port = htons(g_Port);
fromaddr.sin_family = AF_INET;
fromaddr.sin_addr.s_addr = inet_addr(g_Address);
int nSendReqBytes = sendto(sock,
(const TCHAR*)&reqpack,
sizeof(reqpack),
0,
(struct sockaddr*)&fromaddr,
sizeof(fromaddr));
return nSendReqBytes;
}
//------------------------------------------------------------------------------
// Function : SendErrorPacket()
// Send error packet to server.
//
// Input:
// None.
//
// Output:
// 0: Send error packet successfully.
//------------------------------------------------------------------------------
static int SendErrorPacket(const int ErrorId)
{
ErrorPacket errpack = MakeErrorPacket(ErrorId);
int nSendErrBytes = sendto(sock,
(const TCHAR*)&errpack,
sizeof(errpack),
0,
(struct sockaddr*)&fromaddr,
sizeof(fromaddr));
DEBUGMSG(TEXT("Error packet size: %d/n"), nSendErrBytes);
return nSendErrBytes;
}
//------------------------------------------------------------------------------
// Function : SetTFTP()
// Set TFTP parameters: IP address and port.
//
// Input:
// szAddress [in]: IP address of target device.
// nPort [in]: port of target device.
//
// Output:
// None.
//------------------------------------------------------------------------------
DLLIMPORT void SetTFTP(const TCHAR* szAddress, const int nPort)
{
strcpy(g_Address, szAddress);
}
//------------------------------------------------------------------------------
// Function : SetFileName()
// Set the name of file which is sent to server.
//
// Input:
// None.
//
// Output:
// None.
//------------------------------------------------------------------------------
DLLIMPORT void SetFileName(const TCHAR* szFileName)
{
strcpy(g_FileName, szFileName);
}
//------------------------------------------------------------------------------
// Function : HandShake()
// Sends "PUT" request to server and establish communication with server.
//
// Input:
// None.
//
// Output:
// 0: Handshake with server successfully, otherwise return GetLastError().
//------------------------------------------------------------------------------
DLLIMPORT int HandShake()
{
int nRetry = 20;
int nResult = 0;
while (1)
{
// Send Request Message.
if (SendRequestPacket(DEFAULT_FILENAME, BINARY, WRITE) == SOCKET_ERROR)
{
return GetLastError();
}
// Get Message.
nResult = ReceiveMsg(szMsg);
if (nResult < 0)
{
if (GetLastError() != WSAETIMEDOUT)
{
CleanupConnection();
return GetLastError();
}
else
{
nRetry--;
// Time Out.
if (nRetry == 0)
{
CleanupConnection();
return WSAETIMEDOUT;
}
Sleep(1000);
}
}
else
{
break;
} // End of if (nResult < 0).
}
if (PrePareFile(g_FileName, READ) != 0)
{
CleanupConnection();
SendErrorPacket(1);
return GetLastError();
}
return 0;
}
//------------------------------------------------------------------------------
// Function : StartClient()
// Client sends data packet to server and receives ACK packet from server.
//
// Input:
// None.
//
// Output:
// 0: Client sends server image file successfully.
//------------------------------------------------------------------------------
DLLIMPORT int StartClient()
{
int nResult = 0;
int nRetry = 10;
while(1)
{
nResult = ProcessMsg(szMsg, nMsgLength);
if (nResult == TRANSFER_OVER)
{
DEBUGMSG(TEXT("Transfer over/n"));
break;
}
if (nResult != 0)
{
DEBUGMSG(TEXT("Error occur, error code = %d/n"), GetLastError());
break;
}
nMsgLength = ReceiveMsg(szMsg);
if (nMsgLength < 0)
{
if (GetLastError() != WSAETIMEDOUT)
{
nResult = GetLastError();
}
else
{
if (nRetry == 0)
{
nResult = WSAETIMEDOUT;
break;
}
nRetry--;
Sleep(1000);
}
}
else
{
nRetry = 20;
} // End of if (nMsgLength < 0).
} // End while.
CleanupConnection();
return nResult;
}
//------------------------------------------------------------------------------
// Function : GetSendData()
// Get the size of file which has been sent to server.
//
// Input:
// None.
//
// Output:
// int: The size of file which has been sent.
//------------------------------------------------------------------------------
DLLIMPORT int GetSendData()
{
g_nSendDataBytes -= 4;
return g_nSendDataBytes;
}
//------------------------------------------------------------------------------
// Function : DoGetFileSize()
// Get the size of file which is sent to server.
//
// Input:
// None.
//
// Output:
// int: The size of file.
//------------------------------------------------------------------------------
DLLIMPORT int DoGetFileSize()
{
int nFileSize = GetFileSize(g_FileHandle, (LPDWORD) NULL);
return nFileSize;
}