2 Copyright 2006 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "tftpclient.h"
23 TftpClient::TftpClient()
25 log = Log::getInstance();
31 TftpClient::~TftpClient()
33 log->log("TftpClient", Log::DEBUG, "Someone calls tftpclient::~tftpclient");
37 int TftpClient::shutdown()
39 if (threadIsActive()) threadCancel();
48 log->log("TftpClient", Log::DEBUG, "shutdown");
53 int TftpClient::run(char* tbaseDir, char* tpeerIP, USHORT tpeerPort, UCHAR* data, int length)
55 if (threadIsActive()) return 1;
56 log->log("TftpClient", Log::DEBUG, "Client handler started");
60 strncpy(peerIP, tpeerIP, 16);
63 if (length > 599) return 0;
64 bufferLength = length;
65 memcpy(buffer, data, length);
69 log->log("TftpClient", Log::DEBUG, "DSock init error");
76 log->log("TftpClient", Log::DEBUG, "Thread start error");
84 void TftpClient::threadMethod()
88 // process the first message received by the parent listener
89 // the first incoming message is placed in buffer by above run method
90 if (!processMessage(buffer, bufferLength))
92 log->log("TftpClient", Log::INFO, "threadMethod terminating connection");
98 for(int counter = 0; counter < 10; counter++)
100 // log->log("TftpClient", Log::DEBUG, "Starting wait");
101 // timer system to expire after x seconds
102 retval = ds.waitforMessage(1);
103 // log->log("TftpClient", Log::DEBUG, "Wait finished");
107 log->log("TftpClient", Log::CRIT, "Wait for packet error");
110 else if (retval == 1)
113 // see if we need to retransmit a data packet
114 if (((state == 1) || (state == 2)) && (lastCom < (time(NULL) - 1)))
116 // log->log("TftpClient", Log::DEBUG, "Retransmitting buffer");
124 if (strcmp(ds.getFromIPA(), peerIP)) continue; // not from my client's IP
125 if (ds.getFromPort() != peerPort) continue; // not from my client's port
127 if (!processMessage((UCHAR*)ds.getData(), ds.getDataLength()))
129 log->log("TftpClient", Log::INFO, "processMessage terminating connection");
133 counter = 0; // that was a valid packet, reset the counter
136 log->log("TftpClient", Log::DEBUG, "Lost connection, exiting");
139 void TftpClient::threadPostStopCleanup()
141 // log->log("TftpClient", Log::DEBUG, "Deleting tftpclient");
142 // delete this; // careful
145 int TftpClient::processMessage(UCHAR* data, int length)
147 // log->log("TftpClient", Log::DEBUG, "Got request");
148 // dump(data, (USHORT)length);
150 if ((UINT)length < sizeof(USHORT)) return 0;
151 USHORT opcode = ntohs(*(USHORT*)data);
152 data += sizeof(USHORT);
153 length -= sizeof(USHORT);
157 case 1: // Read request
159 if (!processReadRequest(data, length)) return 0;
162 case 2: // Write request
164 log->log("TftpClient", Log::ERR, "Client wanted to send us a file!");
169 log->log("TftpClient", Log::ERR, "Client sent a data packet!");
174 if (!processAck(data, length)) return 0;
184 log->log("TftpClient", Log::ERR, "Client TFTP protocol error");
192 int TftpClient::processReadRequest(UCHAR* data, int length)
194 if (state != 0) return 0;
196 // Safety checking - there should be two nulls in the data/length
199 for(int i = 0; i < length; i++)
201 if (data[i] == '\0') nullsFound++;
204 if (nullsFound != 2) return 0;
206 char* filename = (char*)data;
207 char* mode = (char*)(data + strlen(filename) + 1);
209 log->log("TftpClient", Log::DEBUG, "RRQ received for %s", filename);
211 if (strcasecmp(mode, "octet")) return 0;
212 if (!openFile(filename)) return 0;
213 if (!sendBlock()) return 0;
215 lastCom = time(NULL);
221 int TftpClient::processAck(UCHAR* data, int length)
223 if ((state != 1) && (state != 2)) return 0;
225 if (length != 2) return 0;
227 USHORT ackBlock = ntohs(*(USHORT*)data);
229 if (ackBlock == (blockNumber - 1))
231 // successful incoming packet
232 lastCom = time(NULL);
234 // log->log("TftpClient", Log::DEBUG, "Ack received for block %i - success", ackBlock);
236 if (state == 1) // it wasn't the final block
242 // state == 2, end of transfer. kill connection
243 log->log("TftpClient", Log::INFO, "File transfer finished");
249 // log->log("TftpClient", Log::DEBUG, "Ack received for block %i - rejected, retransmitting block\n", ackBlock);
256 int TftpClient::openFile(char* requestedFile)
258 char fileName[PATH_MAX];
259 strcpy(fileName, requestedFile);
261 for(UINT i = 0; i < strlen(fileName); i++)
263 if (fileName[i] == '/')
265 log->log("TftpClient", Log::ERR, "TFTP filename from client contained a path");
270 char fileName2[PATH_MAX];
271 snprintf(fileName2, PATH_MAX, "%s%s", baseDir, fileName);
273 log->log("TftpClient", Log::INFO, "File: '%s'", fileName2);
276 file = fopen(fileName2, "r");
281 int TftpClient::sendBlock()
283 *(USHORT*)&buffer[0] = htons(3);
284 *(USHORT*)&buffer[2] = htons(blockNumber++);
285 bufferLength = 4 + fread(&buffer[4], 1, 512, file);
287 if (bufferLength < 516) // 512 + 4 header
304 void TftpClient::transmitBuffer()
306 ds.send(peerIP, peerPort, (char*)buffer, bufferLength);
307 // dump(buffer, bufferLength);
308 // log->log("TftpClient", Log::DEBUG, "Sent block number %i", blockNumber - 1);