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
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 }
Generated on Tue Jul 12 2022 21:03:04 by 1.7.2