]> git.vomp.tv Git - vompserver.git/commitdiff
TFTP server (not quite finished)
authorChris Tallon <chris@vomp.tv>
Mon, 6 Feb 2006 21:45:43 +0000 (21:45 +0000)
committerChris Tallon <chris@vomp.tv>
Mon, 6 Feb 2006 21:45:43 +0000 (21:45 +0000)
12 files changed:
Makefile
config.c
dsock.c
mvpserver.c
mvpserver.h
tftpclient.c [new file with mode: 0644]
tftpclient.h [new file with mode: 0644]
tftpd.c [new file with mode: 0644]
tftpd.h [new file with mode: 0644]
thread.c
thread.h
vomp.conf.sample

index abe6ac220ea13fdcf1a882d6b0f365f4b3ad8fad..ff5138236f6b326286d6ef74eceb126a193e57ce 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -46,9 +46,9 @@ DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
 
 ### The object files (add further files here):
 
-OBJS = $(PLUGIN).o dsock.o mvpserver.o udpreplier.o bootpd.o mvpclient.o tcp.o \
+OBJS = $(PLUGIN).o dsock.o mvpserver.o udpreplier.o bootpd.o tftpd.o mvpclient.o tcp.o \
                    remux/ts2ps.o remux/ts2es.o remux/tsremux.o ringbuffer.o \
-                   recplayer.o config.o log.o thread.o mvpreceiver.o
+                   recplayer.o config.o log.o thread.o mvpreceiver.o tftpclient.o
 
 
 libdvbmpeg/libdvbmpegtools.a: libdvbmpeg/*.c libdvbmpeg/*.cc libdvbmpeg/*.h libdvbmpeg/*.hh
index dccf52403d66d9986f44d80a0aa00bdb7be4dacf..e4748c1894c8f79261293839c4ec4651adf8c64a 100644 (file)
--- a/config.c
+++ b/config.c
@@ -113,9 +113,9 @@ int Config::readLine()
   if (!initted || !file) { log->log("Config", Log::DEBUG, "1"); return 0; }
   if (!fgets(buffer, BUFFER_LENGTH-1, file)) { log->log("Config", Log::DEBUG, "2"); return 0; }
   lastLineLength = strlen(buffer);
-  log->log("Config", Log::DEBUG, "buffer before trim: '%s'", buffer);
+//  log->log("Config", Log::DEBUG, "buffer before trim: '%s'", buffer);
   trim(buffer);
-  log->log("Config", Log::DEBUG, "buffer after trim: '%s'", buffer);
+//  log->log("Config", Log::DEBUG, "buffer after trim: '%s'", buffer);
   return 1;
 }
 
@@ -317,7 +317,7 @@ int Config::findSection(char* section)
 
   while(readLine())
   {
-    log->log("Config", Log::DEBUG, "to find '%s' this line '%s'", toFind, buffer);
+//    log->log("Config", Log::DEBUG, "to find '%s' this line '%s'", toFind, buffer);
     if (!strcmp(toFind, buffer)) return 1;
   }
   return 0;
diff --git a/dsock.c b/dsock.c
index 80dc53204fcc331dbeda5e66bb48ce0bcd9713bf..885d9273db1e885c45238780efc0b356bd86b8ba 100644 (file)
--- a/dsock.c
+++ b/dsock.c
@@ -116,7 +116,7 @@ unsigned char DatagramSocket::waitforMessage(unsigned char how)
     memset(&buf[mlength], 0, MAXBUFLEN - mlength);
     strcpy(fromIPA, inet_ntoa(theirAddr.sin_addr));
     fromPort = ntohs(theirAddr.sin_port);
-    log->log("UDP", Log::DEBUG, "%s:%i received length %i", fromIPA, fromPort, mlength);
+//    log->log("UDP", Log::DEBUG, "%s:%i received length %i", fromIPA, fromPort, mlength);
     return 2;
   }
 
@@ -149,7 +149,7 @@ void DatagramSocket::send(char *ipa, short port, char *message, int length)
   sentLength = sendto(socketnum, message, length, 0, (struct sockaddr *)&theirAddr, addrlen);
   if (sentLength == length)
   {
-    log->log("UDP", Log::DEBUG, "%s:%i sent length %i", ipa, port, length);
+//    log->log("UDP", Log::DEBUG, "%s:%i sent length %i", ipa, port, length);
     return;
   }
 
index 98ff62f95bb916d33c96fba3b44b43b561ea64d3..c1063faa2cd02f8d7d5ba8aeebfd5181f562f636 100644 (file)
@@ -36,6 +36,7 @@ int MVPServer::stop()
 
   udpr.shutdown();
   bootpd.shutdown();
+  tftpd.shutdown();
 
   log.log("Main", Log::INFO, "Stopped main server thread");
   log.shutdown();
@@ -109,6 +110,7 @@ int MVPServer::run()
     return 0;
   }
 
+  // Start Bootpd
   if (config.getValueString("General", "Bootp server"))
   {
     if (!bootpd.run())
@@ -123,6 +125,21 @@ int MVPServer::run()
     log.log("Main", Log::INFO, "Not starting Bootpd");
   }
 
+  // Start Tftpd
+  if (config.getValueString("General", "TFTP server"))
+  {
+    if (!tftpd.run())
+    {
+      log.log("Main", Log::CRIT, "Could not start TFTPd");
+      stop();
+      return 0;
+    }
+  }
+  else
+  {
+    log.log("Main", Log::INFO, "Not starting TFTPd");
+  }
+
   // start thread here
   if (!threadStart())
   {
index 06f101ac05bc45bb4090a67b60cac3e4a8c5b83e..efb73b5ef34fda94ef688f1f1093762a4b740fff 100644 (file)
@@ -28,6 +28,7 @@
 #include "defines.h"
 #include "udpreplier.h"
 #include "bootpd.h"
+#include "tftpd.h"
 #include "mvpclient.h"
 #include "thread.h"
 #include "config.h"
@@ -48,6 +49,7 @@ class MVPServer : public Thread
     Config config;
     UDPReplier udpr;
     Bootpd bootpd;
+    Tftpd tftpd;
     int listeningSocket;
 };
 
diff --git a/tftpclient.c b/tftpclient.c
new file mode 100644 (file)
index 0000000..75d72df
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+    Copyright 2006 Chris Tallon
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "tftpclient.h"
+
+void dump(unsigned char* data, USHORT size);
+unsigned char dcc(UCHAR c);
+
+TftpClient::TftpClient()
+{
+  log = Log::getInstance();
+  state = 0;
+  blockNumber = 1;
+  lastCom = 0;
+}
+
+TftpClient::~TftpClient()
+{
+  shutdown();
+}
+
+int TftpClient::shutdown()
+{
+  if (threadIsActive()) threadCancel();
+  ds.shutdown();
+
+  if (file)
+  {
+    fclose(file);
+    file = NULL;
+  }
+
+  log->log("TftpClient", Log::DEBUG, "shutdown");
+
+  return 1;
+}
+
+int TftpClient::run(char* tpeerIP, USHORT tpeerPort, UCHAR* data, int length)
+{
+  if (threadIsActive()) return 1;
+  log->log("TftpClient", Log::DEBUG, "Client handler started");
+
+  strncpy(peerIP, tpeerIP, 16);
+  peerPort = tpeerPort;
+
+  if (length > 599) return 0;
+  bufferLength = length;
+  memcpy(buffer, data, length);
+
+  if (!ds.init(0))
+  {
+    log->log("TftpClient", Log::DEBUG, "DSock init error");
+    shutdown();
+    return 0;
+  }
+
+  if (!threadStart())
+  {
+    log->log("TftpClient", Log::DEBUG, "Thread start error");
+    shutdown();
+    return 0;
+  }
+
+  return 1;
+}
+
+void TftpClient::threadMethod()
+{
+  threadDetach();
+
+  // process the first message received by the parent listener
+  // the first incoming message is placed in buffer by above run method
+  if (!processMessage(buffer, bufferLength)) return;
+
+  int retval;
+
+  for(int counter = 0; counter < 10; counter++)
+  {
+//    log->log("TftpClient", Log::DEBUG, "Starting wait");
+    // timer system to expire after x seconds
+    retval = ds.waitforMessage(1);
+//    log->log("TftpClient", Log::DEBUG, "Wait finished");
+
+    if (retval == 0)
+    {
+      log->log("TftpClient", Log::CRIT, "Wait for packet error");
+      return;
+    }
+    else if (retval == 1)
+    {
+      // 1s timer expired
+      // see if we need to retransmit a data packet
+      if (((state == 1) || (state == 2)) && (lastCom < (time(NULL) - 3)))
+      {
+        log->log("TftpClient", Log::DEBUG, "Retransmitting buffer");
+        transmitBuffer();
+      }
+
+      continue;
+    }
+    else
+    {
+      if (strcmp(ds.getFromIPA(), peerIP)) continue; // not from my client's IP
+      if (ds.getFromPort() != peerPort) continue; // not from my client's port
+
+      if (!processMessage((UCHAR*)ds.getData(), ds.getDataLength()))
+      {
+        log->log("TftpClient", Log::INFO, "processMessage terminating connection");
+        return;
+      }
+
+      counter = 0; // that was a valid packet, reset the counter
+    }
+  }
+  log->log("TftpClient", Log::DEBUG, "Lost connection, exiting");
+}
+
+void TftpClient::threadPostStopCleanup()
+{
+  log->log("TftpClient", Log::DEBUG, "Deleting tftpclient");
+  delete this; // careful
+}
+
+int TftpClient::processMessage(UCHAR* data, int length)
+{
+//  log->log("TftpClient", Log::DEBUG, "Got request");
+//  dump(data, (USHORT)length);
+
+  if ((UINT)length < sizeof(USHORT)) return 0;
+  USHORT opcode = ntohs(*(USHORT*)data);
+  data += sizeof(USHORT);
+  length -= sizeof(USHORT);
+
+  switch(opcode)
+  {
+    case 1: // Read request
+    {
+      if (!processReadRequest(data, length)) return 0;
+      break;
+    }
+    case 2: // Write request
+    {
+      log->log("TftpClient", Log::ERR, "Client wanted to send us a file!");
+      return 0; // quit
+    }
+    case 3: // Data
+    {
+      break;
+    }
+    case 4: // Ack
+    {
+      if (!processAck(data, length)) return 0;
+      break;
+    }
+    case 5: // Error
+    {
+      break;
+    }
+
+    default:
+    {
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
+int TftpClient::processReadRequest(UCHAR* data, int length)
+{
+  if (state != 0) return 0;
+
+  // Safety checking - there should be two nulls in the data/length
+
+  int nullsFound = 0;
+  for(int i = 0; i < length; i++)
+  {
+    if (data[i] == '\0') nullsFound++;
+  }
+
+  if (nullsFound != 2) return 0;
+
+  char* filename = (char*)data;
+  char* mode = (char*)(data + strlen(filename) + 1);
+
+  log->log("TftpClient", Log::DEBUG, "RRQ received for %s", filename);
+
+  if (strcasecmp(mode, "octet")) return 0;
+  if (!openFile(filename)) return 0;
+  if (!sendBlock()) return 0;
+
+  lastCom = time(NULL);
+  state = 1;
+
+  return 1;
+}
+
+int TftpClient::processAck(UCHAR* data, int length)
+{
+  if ((state != 1) && (state != 2)) return 0;
+
+  if (length != 2) return 0;
+
+  USHORT ackBlock = ntohs(*(USHORT*)data);
+
+  if (ackBlock == (blockNumber - 1))
+  {
+    // successful incoming packet
+    lastCom = time(NULL);
+
+    log->log("TftpClient", Log::DEBUG, "Ack received for block %i - success", ackBlock);
+
+    if (state == 1) // it wasn't the final block
+    {
+      sendBlock();
+    }
+    else
+    {
+      // state == 2, end of transfer. kill connection
+      log->log("TftpClient", Log::INFO, "File transfer finished");
+      return 0;
+    }
+  }
+  else
+  {
+    log->log("TftpClient", Log::DEBUG, "Ack received for block %i - rejected\n", ackBlock);
+  }
+
+  return 1;
+}
+
+int TftpClient::openFile(char* filename)
+{
+  file = fopen("/opt/dvb/vomp-dongle-0.1.1", "r");
+  if (!file) return 0;
+  return 1;
+}
+
+int TftpClient::sendBlock()
+{
+  *(USHORT*)&buffer[0] = htons(3);
+  *(USHORT*)&buffer[2] = htons(blockNumber++);
+  bufferLength = 4 + fread(&buffer[4], 1, 512, file);
+
+  if (bufferLength < 516) // 512 + 4 header
+  {
+    // end of file
+    state = 2;
+    fclose(file);
+    file = NULL;
+  }
+  else
+  {
+    state = 1;
+  }
+
+  transmitBuffer();
+
+  return 1;
+}
+
+void TftpClient::transmitBuffer()
+{
+  ds.send(peerIP, peerPort, (char*)buffer, bufferLength);
+//  dump(buffer, bufferLength);
+  log->log("TftpClient", Log::DEBUG, "Sent block number %i", blockNumber - 1);
+}
+
+void dump(unsigned char* data, USHORT size)
+{
+  printf("Size = %u\n", size);
+
+  USHORT c = 0;
+  while(c < size)
+  {
+    if ((size - c) > 15)
+    {
+      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",
+        data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+        data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
+        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]),
+        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]));
+      c += 16;
+    }
+    else
+    {
+      switch (size - c)
+      {
+        case 15:
+          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",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+            data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
+            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]),
+            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]));
+          c += 15;
+          break;
+        case 14:
+          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",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+            data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
+            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]),
+            dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
+          c += 14;
+          break;
+        case 13:
+          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",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+            data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
+            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]),
+            dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
+          c += 13;
+          break;
+        case 12:
+          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",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+            data[c+8], data[c+9], data[c+10], data[c+11],
+            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]),
+            dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
+          c += 12;
+          break;
+        case 11:
+          printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+            data[c+8], data[c+9], data[c+10],
+            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]),
+            dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
+          c += 11;
+          break;
+        case 10:
+          printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+            data[c+8], data[c+9],
+            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]),
+            dcc(data[c+8]), dcc(data[c+9]));
+          c += 10;
+          break;
+        case 9:
+          printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+            data[c+8],
+            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]),
+            dcc(data[c+8]));
+          c += 9;
+          break;
+        case 8:
+          printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
+            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]));
+          c += 8;
+          break;
+        case 7:
+          printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
+            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]));
+          c += 7;
+          break;
+        case 6:
+          printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
+            dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
+          c += 6;
+          break;
+        case 5:
+          printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
+            data[c], data[c+1], data[c+2], data[c+3], data[c+4],
+            dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
+          c += 5;
+          break;
+        case 4:
+          printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
+            data[c], data[c+1], data[c+2], data[c+3],
+            dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
+          c += 4;
+          break;
+        case 3:
+          printf(" %02X %02X %02X                                            %c%c%c\n",
+            data[c], data[c+1], data[c+2],
+            dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
+          c += 3;
+          break;
+        case 2:
+          printf(" %02X %02X                                               %c%c\n",
+            data[c], data[c+1],
+            dcc(data[c]), dcc(data[c+1]));
+          c += 2;
+          break;
+        case 1:
+          printf(" %02X                                                  %c\n",
+            data[c],
+            dcc(data[c]));
+          c += 1;
+          break;
+      }
+    }
+  }
+}
+
+unsigned char dcc(UCHAR c)
+{
+  if (isspace(c)) return ' ';
+  if (isprint(c)) return c;
+  return '.';
+}
+
diff --git a/tftpclient.h b/tftpclient.h
new file mode 100644 (file)
index 0000000..2a1bdc6
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+    Copyright 2006 Chris Tallon
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef TFTPCLIENT_H
+#define TFTPCLIENT_H
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <vdr/plugin.h>
+
+#include "defines.h"
+#include "log.h"
+#include "dsock.h"
+#include "thread.h"
+
+class TftpClient : public Thread
+{
+  public:
+    TftpClient();
+    virtual ~TftpClient();
+
+    int run(char* ip, USHORT port, UCHAR* data, int length);
+    int shutdown();
+
+  private:
+    Log* log;
+    DatagramSocket ds;
+    char peerIP[17];
+    USHORT peerPort;
+    UCHAR buffer[600];
+    int bufferLength;
+    time_t lastCom;
+    FILE* file;
+    int state;
+    // 0 = start
+    // 1 = awaiting ack
+    // 2 = transfer finished, awaiting last ack
+    USHORT blockNumber;
+
+    void threadMethod();
+    void threadPostStopCleanup();
+
+    int processMessage(UCHAR* data, int length);
+    int processReadRequest(UCHAR* data, int length);
+    int processAck(UCHAR* data, int length);
+
+    int openFile(char* filename);
+    int sendBlock();
+    void transmitBuffer();
+};
+
+#endif
diff --git a/tftpd.c b/tftpd.c
new file mode 100644 (file)
index 0000000..564b2c5
--- /dev/null
+++ b/tftpd.c
@@ -0,0 +1,89 @@
+/*
+    Copyright 2006 Chris Tallon
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "tftpd.h"
+
+Tftpd::Tftpd()
+{
+  log = Log::getInstance();
+}
+
+Tftpd::~Tftpd()
+{
+  shutdown();
+}
+
+int Tftpd::shutdown()
+{
+  if (threadIsActive()) threadCancel();
+  ds.shutdown();
+
+  return 1;
+}
+
+int Tftpd::run()
+{
+  if (threadIsActive()) return 1;
+  log->log("Tftpd", Log::DEBUG, "Starting Tftpd");
+
+  if (!ds.init(16869))
+  {
+    log->log("Tftpd", Log::DEBUG, "DSock init error");
+    shutdown();
+    return 0;
+  }
+
+  if (!threadStart())
+  {
+    log->log("Tftpd", Log::DEBUG, "Thread start error");
+    shutdown();
+    return 0;
+  }
+
+  log->log("Tftpd", Log::DEBUG, "Bootp replier started");
+  return 1;
+}
+
+void Tftpd::threadMethod()
+{
+  int retval;
+  while(1)
+  {
+    log->log("Tftpd", Log::DEBUG, "Starting wait");
+    retval = ds.waitforMessage(0);
+    log->log("Tftpd", Log::DEBUG, "Wait finished");
+
+    if (retval == 0)
+    {
+      log->log("Tftpd", Log::CRIT, "Wait for packet error");
+      return;
+    }
+    else if (retval == 1)
+    {
+      continue;
+    }
+    else
+    {
+      TftpClient* t = new TftpClient();
+      t->run(ds.getFromIPA(), ds.getFromPort(), (UCHAR*)ds.getData(), ds.getDataLength());
+    }
+  }
+}
+
diff --git a/tftpd.h b/tftpd.h
new file mode 100644 (file)
index 0000000..f866feb
--- /dev/null
+++ b/tftpd.h
@@ -0,0 +1,51 @@
+/*
+    Copyright 2006 Chris Tallon
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef TFTPD_H
+#define TFTPD_H
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <vdr/plugin.h>
+
+#include "defines.h"
+#include "log.h"
+#include "dsock.h"
+#include "thread.h"
+#include "tftpclient.h"
+
+class Tftpd : public Thread
+{
+  public:
+    Tftpd();
+    virtual ~Tftpd();
+
+    int run();
+    int shutdown();
+
+  private:
+    void threadMethod();
+
+    DatagramSocket ds;
+    Log* log;
+};
+
+#endif
index fe5490a3fe03b4fc6230887615edd135edcf5874..0eadacb22b105bfae1008cf4d3cf00824623905c 100755 (executable)
--- a/thread.c
+++ b/thread.c
@@ -24,9 +24,9 @@
 void threadInternalStart(void *arg)
 {
   // I don't want signals
-  sigset_t sigset;
-  sigfillset(&sigset);
-  pthread_sigmask(SIG_BLOCK, &sigset, NULL);
+  sigset_t sigs;
+  sigfillset(&sigs);
+  pthread_sigmask(SIG_BLOCK, &sigs, NULL);
 
   Thread *t = (Thread *)arg;
   t->threadInternalStart2();
@@ -35,6 +35,7 @@ void threadInternalStart(void *arg)
 void Thread::threadInternalStart2()
 {
   threadMethod();
+  this->threadPostStopCleanup();
 }
 
 Thread::Thread()
@@ -58,6 +59,7 @@ void Thread::threadStop()
   // Signal thread here in case it's waiting
   threadSignal();
   pthread_join(pthread, NULL);
+  this->threadPostStopCleanup();
 }
 
 void Thread::threadCancel()
@@ -65,6 +67,7 @@ void Thread::threadCancel()
   threadActive = 0;
   pthread_cancel(pthread);
   pthread_join(pthread, NULL);
+  this->threadPostStopCleanup();
 }
 
 void Thread::threadCheckExit()
@@ -95,3 +98,8 @@ void Thread::threadWaitForSignal()
   pthread_cond_wait(&threadCond, &threadCondMutex);
   pthread_mutex_unlock(&threadCondMutex);
 }
+
+void Thread::threadDetach()
+{
+  pthread_detach(pthread);
+}
index bef94be0fed971fd0df61eea9727a84d5ffcdbfb..c48ea97a613301debccb7786ac81e65c486ac925 100755 (executable)
--- a/thread.h
+++ b/thread.h
@@ -27,9 +27,9 @@
 class Thread
 {
   protected:
-
     // Override this method in derived classes
     virtual void threadMethod()=0;
+    virtual void threadPostStopCleanup() {};
 
     // Methods to use from outside the thread
     int threadStart();    // start the thread. threadMethod() will be called in derived class
@@ -42,6 +42,7 @@ class Thread
     // Methods to use from inside the thread
     void threadCheckExit();      // terminates thread if threadStop() has been called
     void threadWaitForSignal();  // pauses thread until threadSignal() is called
+    void threadDetach();         // Detaches the thread
 
     // Internal bits and pieces
 
index 2cc51cc003c7d21b17a54513637634298099be45..c52e473935dd16193de299483fefb08a30336a06 100644 (file)
@@ -16,3 +16,9 @@
 ## name and server
 
 # Bootp server = 1
+
+## Enable this to start the built in TFTP server
+## Required to boot the MVP if you have not got a
+## TFTP server running elsewhere
+
+# TFTP server = 1