]> git.vomp.tv Git - vompserver.git/blob - tftpclient.c
TFTP server (not quite finished)
[vompserver.git] / tftpclient.c
1 /*
2     Copyright 2006 Chris Tallon
3
4     This file is part of VOMP.
5
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.
10
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.
15
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
19 */
20
21 #include "tftpclient.h"
22
23 void dump(unsigned char* data, USHORT size);
24 unsigned char dcc(UCHAR c);
25
26 TftpClient::TftpClient()
27 {
28   log = Log::getInstance();
29   state = 0;
30   blockNumber = 1;
31   lastCom = 0;
32 }
33
34 TftpClient::~TftpClient()
35 {
36   shutdown();
37 }
38
39 int TftpClient::shutdown()
40 {
41   if (threadIsActive()) threadCancel();
42   ds.shutdown();
43
44   if (file)
45   {
46     fclose(file);
47     file = NULL;
48   }
49
50   log->log("TftpClient", Log::DEBUG, "shutdown");
51
52   return 1;
53 }
54
55 int TftpClient::run(char* tpeerIP, USHORT tpeerPort, UCHAR* data, int length)
56 {
57   if (threadIsActive()) return 1;
58   log->log("TftpClient", Log::DEBUG, "Client handler started");
59
60   strncpy(peerIP, tpeerIP, 16);
61   peerPort = tpeerPort;
62
63   if (length > 599) return 0;
64   bufferLength = length;
65   memcpy(buffer, data, length);
66
67   if (!ds.init(0))
68   {
69     log->log("TftpClient", Log::DEBUG, "DSock init error");
70     shutdown();
71     return 0;
72   }
73
74   if (!threadStart())
75   {
76     log->log("TftpClient", Log::DEBUG, "Thread start error");
77     shutdown();
78     return 0;
79   }
80
81   return 1;
82 }
83
84 void TftpClient::threadMethod()
85 {
86   threadDetach();
87
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)) return;
91
92   int retval;
93
94   for(int counter = 0; counter < 10; counter++)
95   {
96 //    log->log("TftpClient", Log::DEBUG, "Starting wait");
97     // timer system to expire after x seconds
98     retval = ds.waitforMessage(1);
99 //    log->log("TftpClient", Log::DEBUG, "Wait finished");
100
101     if (retval == 0)
102     {
103       log->log("TftpClient", Log::CRIT, "Wait for packet error");
104       return;
105     }
106     else if (retval == 1)
107     {
108       // 1s timer expired
109       // see if we need to retransmit a data packet
110       if (((state == 1) || (state == 2)) && (lastCom < (time(NULL) - 3)))
111       {
112         log->log("TftpClient", Log::DEBUG, "Retransmitting buffer");
113         transmitBuffer();
114       }
115
116       continue;
117     }
118     else
119     {
120       if (strcmp(ds.getFromIPA(), peerIP)) continue; // not from my client's IP
121       if (ds.getFromPort() != peerPort) continue; // not from my client's port
122
123       if (!processMessage((UCHAR*)ds.getData(), ds.getDataLength()))
124       {
125         log->log("TftpClient", Log::INFO, "processMessage terminating connection");
126         return;
127       }
128
129       counter = 0; // that was a valid packet, reset the counter
130     }
131   }
132   log->log("TftpClient", Log::DEBUG, "Lost connection, exiting");
133 }
134
135 void TftpClient::threadPostStopCleanup()
136 {
137   log->log("TftpClient", Log::DEBUG, "Deleting tftpclient");
138   delete this; // careful
139 }
140
141 int TftpClient::processMessage(UCHAR* data, int length)
142 {
143 //  log->log("TftpClient", Log::DEBUG, "Got request");
144 //  dump(data, (USHORT)length);
145
146   if ((UINT)length < sizeof(USHORT)) return 0;
147   USHORT opcode = ntohs(*(USHORT*)data);
148   data += sizeof(USHORT);
149   length -= sizeof(USHORT);
150
151   switch(opcode)
152   {
153     case 1: // Read request
154     {
155       if (!processReadRequest(data, length)) return 0;
156       break;
157     }
158     case 2: // Write request
159     {
160       log->log("TftpClient", Log::ERR, "Client wanted to send us a file!");
161       return 0; // quit
162     }
163     case 3: // Data
164     {
165       break;
166     }
167     case 4: // Ack
168     {
169       if (!processAck(data, length)) return 0;
170       break;
171     }
172     case 5: // Error
173     {
174       break;
175     }
176
177     default:
178     {
179       return 0;
180     }
181   }
182
183   return 1;
184 }
185
186 int TftpClient::processReadRequest(UCHAR* data, int length)
187 {
188   if (state != 0) return 0;
189
190   // Safety checking - there should be two nulls in the data/length
191
192   int nullsFound = 0;
193   for(int i = 0; i < length; i++)
194   {
195     if (data[i] == '\0') nullsFound++;
196   }
197
198   if (nullsFound != 2) return 0;
199
200   char* filename = (char*)data;
201   char* mode = (char*)(data + strlen(filename) + 1);
202
203   log->log("TftpClient", Log::DEBUG, "RRQ received for %s", filename);
204
205   if (strcasecmp(mode, "octet")) return 0;
206   if (!openFile(filename)) return 0;
207   if (!sendBlock()) return 0;
208
209   lastCom = time(NULL);
210   state = 1;
211
212   return 1;
213 }
214
215 int TftpClient::processAck(UCHAR* data, int length)
216 {
217   if ((state != 1) && (state != 2)) return 0;
218
219   if (length != 2) return 0;
220
221   USHORT ackBlock = ntohs(*(USHORT*)data);
222
223   if (ackBlock == (blockNumber - 1))
224   {
225     // successful incoming packet
226     lastCom = time(NULL);
227
228     log->log("TftpClient", Log::DEBUG, "Ack received for block %i - success", ackBlock);
229
230     if (state == 1) // it wasn't the final block
231     {
232       sendBlock();
233     }
234     else
235     {
236       // state == 2, end of transfer. kill connection
237       log->log("TftpClient", Log::INFO, "File transfer finished");
238       return 0;
239     }
240   }
241   else
242   {
243     log->log("TftpClient", Log::DEBUG, "Ack received for block %i - rejected\n", ackBlock);
244   }
245
246   return 1;
247 }
248
249 int TftpClient::openFile(char* filename)
250 {
251   file = fopen("/opt/dvb/vomp-dongle-0.1.1", "r");
252   if (!file) return 0;
253   return 1;
254 }
255
256 int TftpClient::sendBlock()
257 {
258   *(USHORT*)&buffer[0] = htons(3);
259   *(USHORT*)&buffer[2] = htons(blockNumber++);
260   bufferLength = 4 + fread(&buffer[4], 1, 512, file);
261
262   if (bufferLength < 516) // 512 + 4 header
263   {
264     // end of file
265     state = 2;
266     fclose(file);
267     file = NULL;
268   }
269   else
270   {
271     state = 1;
272   }
273
274   transmitBuffer();
275
276   return 1;
277 }
278
279 void TftpClient::transmitBuffer()
280 {
281   ds.send(peerIP, peerPort, (char*)buffer, bufferLength);
282 //  dump(buffer, bufferLength);
283   log->log("TftpClient", Log::DEBUG, "Sent block number %i", blockNumber - 1);
284 }
285
286 void dump(unsigned char* data, USHORT size)
287 {
288   printf("Size = %u\n", size);
289
290   USHORT c = 0;
291   while(c < size)
292   {
293     if ((size - c) > 15)
294     {
295       printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
296         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
297         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
298         dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
299         dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]), dcc(data[c+15]));
300       c += 16;
301     }
302     else
303     {
304       switch (size - c)
305       {
306         case 15:
307           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X     %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
308             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
309             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
310             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
311             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]));
312           c += 15;
313           break;
314         case 14:
315           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X        %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
316             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
317             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
318             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
319             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
320           c += 14;
321           break;
322         case 13:
323           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X           %c%c%c%c%c%c%c%c%c%c%c%c%c\n",
324             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
325             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
326             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
327             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
328           c += 13;
329           break;
330         case 12:
331           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X               %c%c%c%c%c%c%c%c%c%c%c%c\n",
332             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
333             data[c+8], data[c+9], data[c+10], data[c+11],
334             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
335             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
336           c += 12;
337           break;
338         case 11:
339           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
340             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
341             data[c+8], data[c+9], data[c+10],
342             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
343             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
344           c += 11;
345           break;
346         case 10:
347           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
348             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
349             data[c+8], data[c+9],
350             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
351             dcc(data[c+8]), dcc(data[c+9]));
352           c += 10;
353           break;
354         case 9:
355           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
356             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
357             data[c+8],
358             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
359             dcc(data[c+8]));
360           c += 9;
361           break;
362         case 8:
363           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
364             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
365             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]));
366           c += 8;
367           break;
368         case 7:
369           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
370             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
371             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]));
372           c += 7;
373           break;
374         case 6:
375           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
376             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
377             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
378           c += 6;
379           break;
380         case 5:
381           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
382             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
383             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
384           c += 5;
385           break;
386         case 4:
387           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
388             data[c], data[c+1], data[c+2], data[c+3],
389             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
390           c += 4;
391           break;
392         case 3:
393           printf(" %02X %02X %02X                                            %c%c%c\n",
394             data[c], data[c+1], data[c+2],
395             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
396           c += 3;
397           break;
398         case 2:
399           printf(" %02X %02X                                               %c%c\n",
400             data[c], data[c+1],
401             dcc(data[c]), dcc(data[c+1]));
402           c += 2;
403           break;
404         case 1:
405           printf(" %02X                                                  %c\n",
406             data[c],
407             dcc(data[c]));
408           c += 1;
409           break;
410       }
411     }
412   }
413 }
414
415 unsigned char dcc(UCHAR c)
416 {
417   if (isspace(c)) return ' ';
418   if (isprint(c)) return c;
419   return '.';
420 }
421