This is the firmware for the LaOS - Laser Open Source project. You can use it to drive a laser cutter. For hardware and more information, look at our wiki: http://wiki.laoslaser.org

Dependencies:   EthernetNetIf mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TFTPServer.cpp Source File

TFTPServer.cpp

00001 /*
00002  * TFTPServer.cpp
00003  * Simple TFTP server
00004  *
00005  * Copyright (c) 2011 Jaap Vermaas
00006  *
00007  *   This file is part of the LaOS project (see: http://wiki.laoslaser.org)
00008  *
00009  *   LaOS is free software: you can redistribute it and/or modify
00010  *   it under the terms of the GNU General Public License as published by
00011  *   the Free Software Foundation, either version 3 of the License, or
00012  *   (at your option) any later version.
00013  *
00014  *   LaOS is distributed in the hope that it will be useful,
00015  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *   GNU General Public License for more details.
00018  *
00019  *   You should have received a copy of the GNU General Public License
00020  *   along with LaOS.  If not, see <http://www.gnu.org/licenses/>.
00021  *
00022  */
00023 #include "TFTPServer.h"
00024 
00025 // create a new tftp server, with file directory dir and
00026 // listening on port
00027 
00028 
00029 
00030 TFTPServer::TFTPServer(char* dir, int myport) {
00031     port = myport;
00032     printf("TFTPServer(): port=%d\n", myport);
00033     ListenSock = new UDPSocket();
00034     ListenSock->setOnEvent(this, &TFTPServer::onListenUDPSocketEvent);
00035     state = listen;
00036     if (ListenSock->bind(Host(IpAddr(), port)))
00037         state = error;
00038     //TFTPServerTimer.attach(this, &TFTPServer::cleanUp, 5000);
00039     sprintf(workdir, "%s", dir);
00040     filecnt = 0;
00041 }
00042 
00043 // destroy this instance of the tftp server
00044 TFTPServer::~TFTPServer() {
00045     ListenSock->resetOnEvent();
00046     delete(ListenSock);
00047     delete(remote);
00048     state = deleted;
00049 }
00050 
00051 void TFTPServer::reset() {
00052     ListenSock->resetOnEvent();
00053     delete(ListenSock);
00054     delete(remote);
00055     //TFTPServerTimer.detach();
00056     ListenSock = new UDPSocket();
00057     ListenSock->setOnEvent(this, &TFTPServer::onListenUDPSocketEvent);
00058     state = listen;
00059     if (ListenSock->bind(Host(IpAddr(), port)))
00060         state = error;
00061     //TFTPServerTimer.attach(this, &TFTPServer::cleanUp, 5000);
00062     sprintf(filename, "");
00063     filecnt = 0;
00064 }
00065 
00066 // get current tftp status
00067 TFTPServerState TFTPServer::State() {
00068     return state;
00069 }
00070 
00071 // Temporarily disable incoming TFTP connections
00072 void TFTPServer::suspend() {
00073     state = suspended;
00074 }
00075 
00076 // Resume after suspension
00077 void TFTPServer::resume() {
00078     if (state == suspended)
00079         state = listen;
00080 }
00081 
00082 // During read and write, this gives you the filename
00083 void TFTPServer::getFilename(char* name) {
00084     sprintf(name, "%s", filename);
00085 }
00086 
00087 // return number of received files
00088 int TFTPServer::fileCnt() {
00089     return filecnt;
00090 }
00091 
00092 // create a new connection reading a file from server
00093 void TFTPServer::ConnectRead(char* buff, Host* client) {
00094     extern LaosFileSystem sd;
00095     IpAddr clientIp = client->getIp();
00096     int clientPort = client->getPort();
00097     remote = new Host(clientIp, clientPort);
00098     Ack(0);
00099     blockcnt = 0;
00100     dupcnt = 0;
00101 
00102     sprintf(filename, "%s", &buff[2]);
00103     
00104     fp = sd.openfile(filename, "rb");
00105     if (fp == NULL) {
00106         state  = listen;
00107         delete(remote);
00108         Err("Could not read file", client);
00109     } else {
00110         // file ready for reading
00111         blockcnt = 0;
00112         state = reading;
00113         #ifdef TFTP_DEBUG
00114             char debugmsg[256];
00115             sprintf(debugmsg, "Listen: Requested file %s from TFTP connection %d.%d.%d.%d port %d",
00116                 filename, clientIp[0], clientIp[1], clientIp[2], clientIp[3], clientPort);
00117             TFTP_DEBUG(debugmsg);
00118         #endif
00119         getBlock();
00120         sendBlock();
00121     }
00122 }
00123 
00124 // create a new connection writing a file to the server
00125 void TFTPServer::ConnectWrite(char* buff, Host* client) {
00126     extern LaosFileSystem sd;
00127     IpAddr clientIp = client->getIp();
00128     int clientPort = client->getPort();
00129     remote = new Host(clientIp, clientPort);
00130     Ack(0);
00131     blockcnt = 0;
00132     dupcnt = 0;
00133 
00134     sprintf(filename, "%s", &buff[2]);
00135     sd.shorten(filename, MAXFILESIZE);
00136     fp = sd.openfile(filename, "wb");
00137     if (fp == NULL) {
00138         Err("Could not open file to write", client);
00139         state  = listen;
00140         delete(remote);
00141     } else {
00142         // file ready for writing
00143         blockcnt = 0;
00144         state = writing;
00145         #ifdef TFTP_DEBUG 
00146             char debugmsg[256];
00147             sprintf(debugmsg, "Listen: Incoming file %s on TFTP connection from %d.%d.%d.%d clientPort %d",
00148                 filename, clientIp[0], clientIp[1], clientIp[2], clientIp[3], clientPort);
00149             TFTP_DEBUG(debugmsg);
00150         #endif
00151     }
00152 }
00153 
00154 // get DATA block from file on disk into memory
00155 void TFTPServer::getBlock() {
00156     blockcnt++;
00157     char *p;
00158     p = &sendbuff[4];
00159     int len = fread(p, 1, 512, fp);
00160     sendbuff[0] = 0x00;
00161     sendbuff[1] = 0x03;
00162     sendbuff[2] = blockcnt >> 8;
00163     sendbuff[3] = blockcnt & 255;
00164     blocksize = len+4;
00165 }
00166 
00167 // send DATA block to the client
00168 void TFTPServer::sendBlock() {
00169     ListenSock->sendto(sendbuff, blocksize, remote);
00170 }
00171 
00172 
00173 // compare host IP and Port with connected remote machine
00174 int TFTPServer::cmpHost(Host* client) {
00175     IpAddr clientIp = client->getIp();
00176     IpAddr remoteIp = remote->getIp();
00177     int clientPort = client->getPort();
00178     int remotePort = remote->getPort();
00179     return ((clientIp == remoteIp) && (clientPort == remotePort));
00180 }
00181 
00182 // send ACK to remote
00183 void TFTPServer::Ack(int val) {
00184     char ack[4];
00185     ack[0] = 0x00;
00186     ack[1] = 0x04;
00187     if ((val>603135) || (val<0)) val = 0;
00188     ack[2] = val >> 8;
00189     ack[3] = val & 255;
00190     ListenSock->sendto(ack, 4, remote);
00191 }
00192 
00193 // send ERR message to named client
00194 void TFTPServer::Err(char* msg, Host* client) {
00195     char message[32];
00196     strncpy(message, msg, 32);
00197     char err[37];
00198     sprintf(err, "0000%s0", message);
00199     err[0] = 0x00;
00200     err[1] = 0x05;
00201     err[2]=0x00;
00202     err[3]=0x00;
00203     int len = strlen(err);
00204     err[len-1] = 0x00;
00205     ListenSock->sendto(err, len, client);
00206     #ifdef TFTP_DEBUG
00207         char debugmsg[256];
00208         sprintf(debugmsg, "Error: %s", message);
00209         TFTP_DEBUG(debugmsg);
00210     #endif
00211 }
00212 
00213 // check if connection mode of client is octet/binary
00214 int TFTPServer::modeOctet(char* buff) {
00215     int x = 2;
00216     while (buff[x++] != 0); // get beginning of mode field
00217     int y = x;
00218     while (buff[y] != 0) {
00219         buff[y] = tolower(buff[y]);
00220         y++;
00221     } // make mode field lowercase
00222     return (strcmp(&buff[x++], "octet") == 0);
00223 }
00224 
00225 // timed routine to avoid hanging after interrupted transfers
00226 void TFTPServer::cleanUp() {
00227     extern Timer systime;
00228     static int lastblock;
00229     int now = systime.read();
00230     switch (state) {
00231         case reading:
00232             if (lastblock+5 < now) {
00233                 fclose(fp);
00234                 state=listen;
00235                 delete(remote);
00236             }
00237             lastblock = now;
00238             break;
00239         case writing:
00240             if (lastblock+5 < now) {
00241                 fclose(fp);
00242                 state = listen;
00243                 remove(filename);
00244                 delete(remote);
00245             }
00246             lastblock = now;
00247             break;
00248     } // state
00249     lastblock = now;
00250 }
00251 
00252 // event driven routines to handle incoming packets
00253 void TFTPServer::onListenUDPSocketEvent(UDPSocketEvent e) {
00254     cleanUp();
00255     extern LaosFileSystem sd;
00256     Host* client = new Host();
00257     char buff[516];
00258     if (e == UDPSOCKET_READABLE) {
00259         switch (state) {
00260             case listen:
00261                 if (int len = ListenSock->recvfrom(buff, 516, client)) {
00262                     switch (buff[1]) {
00263                         case 0x01: // RRQ
00264                             if (modeOctet(buff))
00265                                 ConnectRead(buff, client);
00266                             else
00267                                 Err("Not in octet mode", client);
00268                             break;
00269                         case 0x02: // WRQ
00270                             if (modeOctet(buff))
00271                                 ConnectWrite(buff, client);
00272                             else
00273                                 Err("Not in octet mode", client);
00274                             break;
00275                         case 0x03: // DATA before connection established
00276                             Err("No data expected", client);
00277                             break;
00278                         case 0x04:  // ACK before connection established
00279                             Err("No ack expected", client);
00280                             break;
00281                         case 0x05: // ERROR packet received
00282                             #ifdef TFTP_DEBUG
00283                                 TFTP_DEBUG("TFTP Eror received\n\r");
00284                             #endif
00285                             break;
00286                         default:    // unknown TFTP packet type
00287                             Err("Unknown TFTP packet type", client);
00288                             break;
00289                     } // switch buff[1]
00290                 } // recvfrom
00291                 break; // case listen
00292             case reading:
00293                 while (int len = ListenSock->recvfrom(buff, 516, client) ) {
00294                     switch (buff[1]) {
00295                         case 0x01:
00296                             // if this is the receiving host, send first packet again
00297                             if ((cmpHost(client) && blockcnt==1)) {
00298                                 sendBlock();
00299                                 dupcnt++;
00300                             }
00301                             if (dupcnt>10) { // too many dups, stop sending
00302                                 fclose(fp);
00303                                 state=listen;
00304                                 delete(remote);
00305                             }
00306                             break;
00307                         case 0x02:
00308                             // this should never happen, ignore
00309                             break; // case 0x02
00310                         case 0x03:
00311                             // we are the sending side, ignore
00312                             break;
00313                         case 0x04:
00314                             // last packet received, send next if there is one
00315                             dupcnt = 0;
00316                             if (blocksize == 516) {
00317                                 getBlock();
00318                                 sendBlock();
00319                             } else { //EOF
00320                                 fclose(fp);
00321                                 state = listen;
00322                                 delete(remote);
00323                             }
00324                             break;
00325                         default:  // this includes 0x05 errors
00326                             fclose(fp);
00327                             state = listen;
00328                             delete(remote);
00329                             break;
00330                     } // switch (buff[1])
00331                 } // while
00332                 break; // reading
00333             case writing:
00334                 while (int len = ListenSock->recvfrom(buff, 516, client) ) {
00335                     switch (buff[1]) {
00336                         case 0x02:
00337                             // if this is a returning host, send ack again
00338                             if (cmpHost(client)) {
00339                                 Ack(0);
00340                                 #ifdef TFTP_DEBUG
00341                                     TFTP_DEBUG("Resending Ack on WRQ");
00342                                 #endif
00343                             }
00344                             break; // case 0x02
00345                         case 0x03:
00346                             if (cmpHost(client)) { // check if this is our partner
00347                                 int block = (buff[2] << 8) + buff[3];
00348                                 if ((blockcnt+1) == block) {
00349                                     Ack(block);
00350                                     // new packet
00351                                     char *data = &buff[4];
00352                                     fwrite(data, 1,len-4, fp);
00353                                     blockcnt++;
00354                                     dupcnt = 0;
00355                                 } else {
00356                                     if ((blockcnt+1) < block) { // high block nr
00357                                         // we missed a packet, error
00358                                         #ifdef TFTP_DEBUG
00359                                             TFTP_DEBUG("Missed packet!");
00360                                         #endif
00361                                         fclose(fp);
00362                                         state = listen;
00363                                         remove(filename);
00364                                         delete(remote);
00365                                     } else { // duplicate packet, do nothing
00366                                         #ifdef TFTP_DEBUG
00367                                             char debugmsg[256];
00368                                             sprintf(debugmsg, "Dupblicate packet %d", blockcnt);
00369                                             TFTP_DEBUG(debugmsg);
00370                                         #endif
00371                                         if (dupcnt > 10) {
00372                                             Err("Too many dups", client);
00373                                             fclose(fp);
00374                                             remove(filename);
00375                                             state = listen;
00376                                         } else {
00377                                             Ack(blockcnt);
00378                                         }
00379                                         dupcnt++;
00380                                     }
00381                                 }
00382                                 //printf ("Read packet %d with blocksize = %d\n\r", blockcnt, len);
00383                                 if (len<516) {
00384                                     #ifdef TFTP_DEBUG
00385                                         char debugmsg[256];
00386                                         sprintf(debugmsg, "Read last block %d", len);
00387                                         TFTP_DEBUG(debugmsg);
00388                                     #endif
00389                                     fclose(fp);
00390                                     state = listen;
00391                                     delete(remote);
00392                                     filecnt++;
00393                                 }
00394                                 break; // case 0x03
00395                             }  else // if cmpHost
00396                                 Err("Wrong IP/Port: Not your connection!", client);
00397                             break; // case 0x03
00398                         default:
00399                             Err("No idea why you're sending me this!", client);
00400                             break; // default
00401                     } // switch (buff[1])
00402                 } // while
00403                 break; // writing
00404             case suspended:
00405                 if (int len = ListenSock->recvfrom(buff, 516, client))
00406                     Err("Packet received on suspended socket, discarded", client);
00407                 break;
00408         } // state
00409     } else {
00410         #ifdef TFTP_DEBUG
00411             TFTP_DEBUG("TFTP unknown UDP status");
00412         #endif
00413     }
00414     delete(client);
00415 }