/*++ Copyright (c) 2000 Microsoft Corporation Module Name: tftp.c Abstract: XBox TFTP client program Revision History: 06/30/2000 davidx Created it. --*/ #include "precomp.h" #include "tftp.h" CHAR TftpRecvBuf[TFTP_PACKET_BUFSIZE]; CHAR TftpSendBuf[TFTP_PACKET_BUFSIZE]; DWORD TftpSendBufsize; DWORD TftpRecvBufsize; CHAR* TftpMode = "octet"; CHAR* TftpServerAddr = "157.56.10.165"; CHAR* SrcFilename = "c:\\temp\\data2"; CHAR* DstFilename = "c:\\temp\\test"; INT testFlag = 1; INT err; struct sockaddr_in sockname; #define VERIFY(cond, _apiname) \ if (!(cond)) { \ DbgPrint(#_apiname " failed: %d %d\n", err, GetLastError()); \ goto failed; \ } SOCKET ConnectTftpServer() { SOCKET sock = INVALID_SOCKET; sock = socket(AF_INET, SOCK_DGRAM, 0); VERIFY(sock != INVALID_SOCKET, socket); ZeroMem(&sockname, sizeof(sockname)); sockname.sin_family = AF_INET; err = _bind(sock, &sockname); VERIFY(err == NO_ERROR, bind); err = _setrcvtimeout(sock, TFTP_RECV_TIMEOUT); VERIFY(err == NO_ERROR, setrcvtimeout); return sock; failed: if (sock != INVALID_SOCKET) { closesocket(sock); } return INVALID_SOCKET; } // // Send initial request to the server and wait for response // BOOL SendRequestAndWait( SOCKET sock, UINT opcode, UINT blocknum ) { INT retries = TFTP_MAX_RETRIES; UINT buflen; ZeroMem(&sockname, sizeof(sockname)); sockname.sin_family = AF_INET; while (TRUE) { if (retries-- == 0) { WARNING_("Server doesn't appear to be responding..."); goto failed; } sockname.sin_port = htons(TFTP_SERVER_PORT); sockname.sin_addr.s_addr = inet_addr(TftpServerAddr); DbgPrint("Sending request to TFTP server: %s:%d\n", inet_ntoa(sockname.sin_addr), ntohs(sockname.sin_port)); buflen = TftpSendBufsize; err = _sendto(sock, TftpSendBuf, &buflen, &sockname); VERIFY(err == NO_ERROR, sendto); TftpRecvBufsize = sizeof(TftpRecvBuf); if (_recvfrom(sock, TftpRecvBuf, &TftpRecvBufsize, &sockname) == NO_ERROR) { UINT op, blk, buflen = TftpRecvBufsize; CHAR* buf = TftpRecvBuf; GETUSHORTFIELD(op); GETUSHORTFIELD(blk); if (op == opcode && blocknum == blk) break; if (op == TFTPOP_ERROR) { WARNING_("Received ERROR packet: %d", blk); return FALSE; } } } DbgPrint("Connecting to TFTP server: %s:%d\n", inet_ntoa(sockname.sin_addr), ntohs(sockname.sin_port)); err = _connect(sock, &sockname); VERIFY(err == NO_ERROR, connect); err = _getsockname(sock, &sockname); VERIFY(err == NO_ERROR, getsockname); DbgPrint("Local address: %s:%d\n", inet_ntoa(sockname.sin_addr), ntohs(sockname.sin_port)); return TRUE; failed: return FALSE; } // // Send data to the server and wait for response // BOOL SendAndWait( SOCKET sock, UINT opcode, UINT blocknum ) { INT retries = TFTP_MAX_RETRIES; UINT buflen; while (retries--) { buflen = TftpSendBufsize; err = _send(sock, TftpSendBuf, &buflen); VERIFY(err == NO_ERROR, send); TftpRecvBufsize = sizeof(TftpRecvBuf); if (_recv(sock, TftpRecvBuf, &TftpRecvBufsize) == NO_ERROR) { UINT op, blk, buflen = TftpRecvBufsize; CHAR* buf = TftpRecvBuf; GETUSHORTFIELD(op); GETUSHORTFIELD(blk); if (op == opcode && blocknum == blk) return TRUE; if (op == TFTPOP_ERROR) { WARNING_("Received ERROR packet: %d", blk); return FALSE; } } } SetLastError(ERROR_TIMEOUT); failed: return FALSE; } // // Send file to the TFTP server // VOID PutTest() { SeqFile* file; SOCKET sock = INVALID_SOCKET; CHAR* buf; DWORD buflen, timer, total = 0; UINT blocknum = 0; DbgPrint("Opening local file %s for reading...\n", SrcFilename); file = _CreateFile(SrcFilename, GENERIC_READ); VERIFY(file != NULL, CreateFile); timer = GetTickCount(); sock = ConnectTftpServer(); VERIFY(sock != INVALID_SOCKET, ConnectTftpServer); DbgPrint("Writing remote file %s...\n", DstFilename); buf = TftpSendBuf; ADDUSHORTFIELD(TFTPOP_WRQ); ADDSTRINGFIELD(DstFilename); ADDSTRINGFIELD(TftpMode); TftpSendBufsize = buf-TftpSendBuf; VERIFY(SendRequestAndWait(sock, TFTPOP_ACK, blocknum), WaitWRQAck); ASSERT(cfgSeqFileBufSize % TFTP_DATAPACKET_BLOCKSIZE == 0); do { // // Read a block of data from the file // buflen = TFTP_DATAPACKET_BLOCKSIZE; VERIFY(_ReadFile(file, &buf, &buflen), ReadFile); CopyMem(&TftpSendBuf[TFTP_DATAPACKET_HEADERSIZE], buf, buflen); // // Munge data packet header // blocknum++; buf = TftpSendBuf; ADDUSHORTFIELD(TFTPOP_DATA); ADDUSHORTFIELD(blocknum); TftpSendBufsize = TFTP_DATAPACKET_HEADERSIZE+buflen; VERIFY(SendAndWait(sock, TFTPOP_ACK, blocknum), WaitDataAck); total += buflen; } while (buflen == TFTP_DATAPACKET_BLOCKSIZE); timer = GetTickCount() - timer; if (timer == 0) timer = 1; DbgPrint("Total transfer: %d bytes in %d msecs\n", total, timer); DbgPrint("Transfer speed: %d bytes /sec\n", MulDiv(total, 1000, timer)); failed: _CloseFile(file); if (sock != INVALID_SOCKET) { closesocket(sock); } } // // Retrieve file from the TFTP server // VOID GetTest() { SeqFile* file; SOCKET sock = INVALID_SOCKET; CHAR* buf; DWORD buflen, timer, total = 0; UINT blocknum = 1; DbgPrint("Opening local file %s for writing...\n", DstFilename); file = _CreateFile(DstFilename, GENERIC_WRITE); VERIFY(file != NULL, CreateFile); timer = GetTickCount(); sock = ConnectTftpServer(); VERIFY(sock != INVALID_SOCKET, ConnectTftpServer); DbgPrint("Reading remote file %s...\n", SrcFilename); buf = TftpSendBuf; ADDUSHORTFIELD(TFTPOP_RRQ); ADDSTRINGFIELD(SrcFilename); ADDSTRINGFIELD(TftpMode); TftpSendBufsize = buf-TftpSendBuf; VERIFY(SendRequestAndWait(sock, TFTPOP_DATA, blocknum), WaitRRQAck); ASSERT(cfgSeqFileBufSize % TFTP_DATAPACKET_BLOCKSIZE == 0); while (TRUE) { buf = &TftpRecvBuf[TFTP_DATAPACKET_HEADERSIZE]; buflen = TftpRecvBufsize - TFTP_DATAPACKET_HEADERSIZE; if (buflen > 0) { total += buflen; VERIFY(_WriteFile(file, buf, buflen), WriteFile); } // Prepare ACK packet buf = TftpSendBuf; ADDUSHORTFIELD(TFTPOP_ACK); ADDUSHORTFIELD(blocknum); TftpSendBufsize = buf-TftpSendBuf; if (buflen != TFTP_DATAPACKET_BLOCKSIZE) { VERIFY(_send(sock, TftpSendBuf, &TftpSendBufsize) == NO_ERROR, send); break; } blocknum++; VERIFY(SendAndWait(sock, TFTPOP_DATA, blocknum), WaitData); } timer = GetTickCount() - timer; if (timer == 0) timer = 1; DbgPrint("Total transfer: %d bytes in %d msecs\n", total, timer); DbgPrint("Transfer speed: %d bytes /sec\n", MulDiv(total, 1000, timer)); failed: _CloseFile(file); if (sock != INVALID_SOCKET) { closesocket(sock); } } #define BREAK_INTO_DEBUGGER __asm int 3 void __cdecl main() { WSADATA wsadata; DbgPrint("Loading XBox network stack...\n"); err = XnetInitialize(NULL, TRUE); if (err != NO_ERROR) { WARNFAIL(XnetInitialize); goto stop; } err = WSAStartup(WINSOCK_VERSION, &wsadata); if (err != NO_ERROR) { WARNFAIL(WSAStartup); goto unload; } DbgPrint("*** Test started, press 'g' to continue...\n"); while (TRUE) { DbgPrint("*** To quit, press CTRL-C and type: ed %x 0;g\n", &testFlag); BREAK_INTO_DEBUGGER if (testFlag <= 0) break; if (testFlag == 1) { PutTest(); } else { GetTest(); } } WSACleanup(); unload: DbgPrint("Unloading XBox network stack...\n"); XnetCleanup(); stop: if (testFlag == 0) HalReturnToFirmware(HalRebootRoutine); else Sleep(INFINITE); }