This is a simple but complete TFTP server capable to run on MBED-OS5. It can receive and send files and listens on port 69. Please notice that it supports only octet (raw 8 bit bytes) mode transfers. It is part of the LaOS (Laser Open Source) project: http://www.laoslaser.org/

Dependents:   TFTPServerTest

Fork of TFTPServer by Jaap Vermaas

Import programTFTPServerTest

This is an example code for using the TFTPServer library.

A simple TFTP server. NOTE: Supports only octet (raw 8 bit bytes) mode transfers.

Committer:
hudakz
Date:
Tue Mar 20 17:31:42 2018 +0000
Revision:
2:f7c0fbc8c5aa
Parent:
1:9c973065a97e
Updated.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tuxic 0:3b0027b76acf 1 /*
tuxic 0:3b0027b76acf 2 * TFTPServer.cpp
tuxic 0:3b0027b76acf 3 * Simple TFTP server
tuxic 0:3b0027b76acf 4 *
tuxic 0:3b0027b76acf 5 * Copyright (c) 2011 Jaap Vermaas
hudakz 2:f7c0fbc8c5aa 6 * Modified by Zoltan Hudak 2018 for MBED-OS5
tuxic 0:3b0027b76acf 7 *
tuxic 0:3b0027b76acf 8 * This file is part of the LaOS project (see: http://wiki.laoslaser.org)
tuxic 0:3b0027b76acf 9 *
tuxic 0:3b0027b76acf 10 * LaOS is free software: you can redistribute it and/or modify
tuxic 0:3b0027b76acf 11 * it under the terms of the GNU General Public License as published by
tuxic 0:3b0027b76acf 12 * the Free Software Foundation, either version 3 of the License, or
tuxic 0:3b0027b76acf 13 * (at your option) any later version.
tuxic 0:3b0027b76acf 14 *
tuxic 0:3b0027b76acf 15 * LaOS is distributed in the hope that it will be useful,
tuxic 0:3b0027b76acf 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
tuxic 0:3b0027b76acf 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
tuxic 0:3b0027b76acf 18 * GNU General Public License for more details.
tuxic 0:3b0027b76acf 19 *
tuxic 0:3b0027b76acf 20 * You should have received a copy of the GNU General Public License
tuxic 0:3b0027b76acf 21 * along with LaOS. If not, see <http://www.gnu.org/licenses/>.
tuxic 0:3b0027b76acf 22 *
hudakz 2:f7c0fbc8c5aa 23 * Minimal TFTP Server
hudakz 2:f7c0fbc8c5aa 24 * * Receive and send files via TFTP
hudakz 2:f7c0fbc8c5aa 25 * * Server handles only one transfer at a time
hudakz 2:f7c0fbc8c5aa 26 * * Supports only octet (raw 8 bit bytes) mode transfers
hudakz 2:f7c0fbc8c5aa 27 * * fixed block size: 512 bytes
hudakz 2:f7c0fbc8c5aa 28 *
tuxic 0:3b0027b76acf 29 */
tuxic 0:3b0027b76acf 30 #include "TFTPServer.h"
hudakz 1:9c973065a97e 31 #include "EthernetInterface.h"
tuxic 0:3b0027b76acf 32
hudakz 1:9c973065a97e 33 //#define TFTP_DEBUG
hudakz 1:9c973065a97e 34
hudakz 1:9c973065a97e 35 /**
hudakz 1:9c973065a97e 36 * @brief Creates a new TFTP server listening on myPort.
hudakz 1:9c973065a97e 37 * @note
hudakz 1:9c973065a97e 38 * @param net A pointer to EthernetInterface object.
hudakz 1:9c973065a97e 39 * @param port A port to listen on (defaults to 69).
hudakz 1:9c973065a97e 40 * @retval
hudakz 1:9c973065a97e 41 */
hudakz 2:f7c0fbc8c5aa 42 TFTPServer::TFTPServer(EthernetInterface* net, uint16_t myPort /* = 69 */ )
hudakz 1:9c973065a97e 43 {
hudakz 1:9c973065a97e 44 port = myPort;
hudakz 1:9c973065a97e 45 #ifdef TFTP_DEBUG
hudakz 1:9c973065a97e 46 printf("TFTPServer(): port=%d\r\n", myPort);
hudakz 1:9c973065a97e 47 #endif
hudakz 1:9c973065a97e 48 socket = new UDPSocket(net);
hudakz 1:9c973065a97e 49 state = LISTENING;
hudakz 1:9c973065a97e 50 if (socket->bind(port))
hudakz 1:9c973065a97e 51 {
hudakz 1:9c973065a97e 52 socketAddr = SocketAddress(0, port);
hudakz 1:9c973065a97e 53 state = ERROR;
hudakz 1:9c973065a97e 54 }
hudakz 1:9c973065a97e 55
hudakz 1:9c973065a97e 56 #ifdef TFTP_DEBUG
hudakz 1:9c973065a97e 57 printf("FTP server state = %d\r\n", getState());
hudakz 1:9c973065a97e 58 #endif
hudakz 1:9c973065a97e 59 socket->set_blocking(false);
hudakz 1:9c973065a97e 60 fileCounter = 0;
tuxic 0:3b0027b76acf 61 }
tuxic 0:3b0027b76acf 62
hudakz 1:9c973065a97e 63 /**
hudakz 1:9c973065a97e 64 * @brief Destroys this instance of the TFTP server.
hudakz 1:9c973065a97e 65 * @note
hudakz 1:9c973065a97e 66 * @param
hudakz 1:9c973065a97e 67 * @retval
hudakz 1:9c973065a97e 68 */
hudakz 1:9c973065a97e 69 TFTPServer::~TFTPServer()
hudakz 1:9c973065a97e 70 {
hudakz 1:9c973065a97e 71 socket->close();
hudakz 1:9c973065a97e 72 delete(socket);
hudakz 1:9c973065a97e 73 strcpy(remoteIP, "");
hudakz 1:9c973065a97e 74 state = DELETED;
tuxic 0:3b0027b76acf 75 }
tuxic 0:3b0027b76acf 76
hudakz 1:9c973065a97e 77 /**
hudakz 1:9c973065a97e 78 * @brief Resets the TFTP server.
hudakz 1:9c973065a97e 79 * @note
hudakz 1:9c973065a97e 80 * @param
hudakz 1:9c973065a97e 81 * @retval
hudakz 1:9c973065a97e 82 */
hudakz 1:9c973065a97e 83 void TFTPServer::reset()
hudakz 1:9c973065a97e 84 {
hudakz 1:9c973065a97e 85 socket->close();
hudakz 1:9c973065a97e 86 delete(socket);
hudakz 1:9c973065a97e 87 strcpy(remoteIP, "");
hudakz 1:9c973065a97e 88 socket = new UDPSocket();
hudakz 1:9c973065a97e 89 state = LISTENING;
hudakz 1:9c973065a97e 90 if (socket->bind(port))
hudakz 1:9c973065a97e 91 {
hudakz 1:9c973065a97e 92 socketAddr = SocketAddress(0, port);
hudakz 1:9c973065a97e 93 state = ERROR;
hudakz 1:9c973065a97e 94 }
hudakz 1:9c973065a97e 95
hudakz 1:9c973065a97e 96 socket->set_blocking(false);
hudakz 1:9c973065a97e 97 strcpy(fileName, "");
hudakz 1:9c973065a97e 98 fileCounter = 0;
tuxic 0:3b0027b76acf 99 }
tuxic 0:3b0027b76acf 100
hudakz 1:9c973065a97e 101 /**
hudakz 1:9c973065a97e 102 * @brief Gets current TFTP status.
hudakz 1:9c973065a97e 103 * @note
hudakz 1:9c973065a97e 104 * @param
hudakz 1:9c973065a97e 105 * @retval
hudakz 1:9c973065a97e 106 */
hudakz 1:9c973065a97e 107 TFTPServer::State TFTPServer::getState()
hudakz 1:9c973065a97e 108 {
tuxic 0:3b0027b76acf 109 return state;
tuxic 0:3b0027b76acf 110 }
tuxic 0:3b0027b76acf 111
hudakz 1:9c973065a97e 112 /**
hudakz 1:9c973065a97e 113 * @brief Temporarily disables incoming TFTP connections.
hudakz 1:9c973065a97e 114 * @note
hudakz 1:9c973065a97e 115 * @param
hudakz 1:9c973065a97e 116 * @retval
hudakz 1:9c973065a97e 117 */
hudakz 1:9c973065a97e 118 void TFTPServer::suspend()
hudakz 1:9c973065a97e 119 {
hudakz 1:9c973065a97e 120 state = SUSPENDED;
tuxic 0:3b0027b76acf 121 }
tuxic 0:3b0027b76acf 122
hudakz 1:9c973065a97e 123 /**
hudakz 1:9c973065a97e 124 * @brief Resumes incoming TFTP connection after suspension.
hudakz 1:9c973065a97e 125 * @note
hudakz 1:9c973065a97e 126 * @param
hudakz 1:9c973065a97e 127 * @retval
hudakz 1:9c973065a97e 128 */
hudakz 1:9c973065a97e 129 void TFTPServer::resume()
hudakz 1:9c973065a97e 130 {
hudakz 1:9c973065a97e 131 if (state == SUSPENDED)
hudakz 1:9c973065a97e 132 state = LISTENING;
tuxic 0:3b0027b76acf 133 }
tuxic 0:3b0027b76acf 134
hudakz 1:9c973065a97e 135 /**
hudakz 1:9c973065a97e 136 * @brief Polls for data or new connection.
hudakz 1:9c973065a97e 137 * @note
hudakz 1:9c973065a97e 138 * @param
hudakz 1:9c973065a97e 139 * @retval
hudakz 1:9c973065a97e 140 */
hudakz 1:9c973065a97e 141 void TFTPServer::poll()
hudakz 1:9c973065a97e 142 {
hudakz 1:9c973065a97e 143 if ((state == SUSPENDED) || (state == DELETED) || (state == ERROR))
hudakz 1:9c973065a97e 144 return;
hudakz 1:9c973065a97e 145
hudakz 1:9c973065a97e 146 socket->set_blocking(false);
hudakz 1:9c973065a97e 147
hudakz 1:9c973065a97e 148 char buff[516];
hudakz 1:9c973065a97e 149 int len = socket->recvfrom(&socketAddr, buff, sizeof(buff));
hudakz 1:9c973065a97e 150
hudakz 1:9c973065a97e 151 if (len <= 0)
hudakz 1:9c973065a97e 152 return;
hudakz 1:9c973065a97e 153
hudakz 1:9c973065a97e 154 #ifdef TFTP_DEBUG
hudakz 1:9c973065a97e 155 printf("Got block with size %d.\n\r", len);
hudakz 1:9c973065a97e 156 #endif
hudakz 1:9c973065a97e 157 switch (state) {
hudakz 1:9c973065a97e 158 case LISTENING:
hudakz 1:9c973065a97e 159 {
hudakz 1:9c973065a97e 160 switch (buff[1]) {
hudakz 1:9c973065a97e 161 case 0x01: // RRQ
hudakz 1:9c973065a97e 162 connectRead(buff);
hudakz 1:9c973065a97e 163 break;
hudakz 1:9c973065a97e 164
hudakz 1:9c973065a97e 165 case 0x02: // WRQ
hudakz 1:9c973065a97e 166 connectWrite(buff);
hudakz 1:9c973065a97e 167 break;
hudakz 1:9c973065a97e 168
hudakz 1:9c973065a97e 169 case 0x03: // DATA before connection established
hudakz 1:9c973065a97e 170 sendError("No data expected.\r\n");
hudakz 1:9c973065a97e 171 break;
hudakz 1:9c973065a97e 172
hudakz 1:9c973065a97e 173 case 0x04: // ACK before connection established
hudakz 1:9c973065a97e 174 sendError("No ack expected.\r\n");
hudakz 1:9c973065a97e 175 break;
hudakz 1:9c973065a97e 176
hudakz 1:9c973065a97e 177 case 0x05: // ERROR packet received
hudakz 1:9c973065a97e 178 #ifdef TFTP_DEBUG
hudakz 1:9c973065a97e 179 printf("TFTP Eror received.\r\n");
hudakz 1:9c973065a97e 180 #endif
hudakz 1:9c973065a97e 181 break;
hudakz 1:9c973065a97e 182
hudakz 1:9c973065a97e 183 default: // unknown TFTP packet type
hudakz 1:9c973065a97e 184 sendError("Unknown TFTP packet type.\r\n");
hudakz 1:9c973065a97e 185 break;
hudakz 1:9c973065a97e 186 } // switch buff[1]
hudakz 1:9c973065a97e 187 break; // case listening
hudakz 1:9c973065a97e 188 }
hudakz 1:9c973065a97e 189
hudakz 1:9c973065a97e 190 case READING:
hudakz 1:9c973065a97e 191 {
hudakz 1:9c973065a97e 192 if (cmpHost())
hudakz 1:9c973065a97e 193 {
hudakz 1:9c973065a97e 194 switch (buff[1]) {
hudakz 1:9c973065a97e 195 case 0x01:
hudakz 1:9c973065a97e 196 // if this is the receiving host, send first packet again
hudakz 1:9c973065a97e 197 if (blockCounter == 1)
hudakz 1:9c973065a97e 198 {
hudakz 1:9c973065a97e 199 ack(0);
hudakz 1:9c973065a97e 200 dupCounter++;
hudakz 1:9c973065a97e 201 }
hudakz 1:9c973065a97e 202
hudakz 1:9c973065a97e 203 if (dupCounter > 10)
hudakz 1:9c973065a97e 204 { // too many dups, stop sending
hudakz 1:9c973065a97e 205 sendError("Too many dups");
hudakz 1:9c973065a97e 206 fclose(file);
hudakz 1:9c973065a97e 207 state = LISTENING;
hudakz 1:9c973065a97e 208 strcpy(remoteIP, "");
hudakz 1:9c973065a97e 209 }
hudakz 1:9c973065a97e 210 break;
hudakz 1:9c973065a97e 211
hudakz 1:9c973065a97e 212 case 0x02:
hudakz 1:9c973065a97e 213 // this should never happen, ignore
hudakz 1:9c973065a97e 214 sendError("WRQ received on open read socket");
hudakz 1:9c973065a97e 215 fclose(file);
hudakz 1:9c973065a97e 216 state = LISTENING;
hudakz 1:9c973065a97e 217 strcpy(remoteIP, "");
hudakz 1:9c973065a97e 218 break;
hudakz 1:9c973065a97e 219
hudakz 1:9c973065a97e 220 case 0x03:
hudakz 1:9c973065a97e 221 // we are the sending side, ignore
hudakz 1:9c973065a97e 222 sendError("Received data package on sending socket");
hudakz 1:9c973065a97e 223 fclose(file);
hudakz 1:9c973065a97e 224 state = LISTENING;
hudakz 1:9c973065a97e 225 strcpy(remoteIP, "");
hudakz 1:9c973065a97e 226 break;
hudakz 1:9c973065a97e 227
hudakz 1:9c973065a97e 228 case 0x04:
hudakz 1:9c973065a97e 229 // last packet received, send next if there is one
hudakz 1:9c973065a97e 230 dupCounter = 0;
hudakz 1:9c973065a97e 231 if (blockSize == 516)
hudakz 1:9c973065a97e 232 {
hudakz 1:9c973065a97e 233 getBlock();
hudakz 1:9c973065a97e 234 sendBlock();
hudakz 1:9c973065a97e 235 }
hudakz 1:9c973065a97e 236 else
hudakz 1:9c973065a97e 237 { //EOF
hudakz 1:9c973065a97e 238 fclose(file);
hudakz 1:9c973065a97e 239 state = LISTENING;
hudakz 1:9c973065a97e 240 strcpy(remoteIP, "");
hudakz 1:9c973065a97e 241 }
hudakz 1:9c973065a97e 242 break;
hudakz 1:9c973065a97e 243
hudakz 1:9c973065a97e 244 default: // this includes 0x05 errors
hudakz 1:9c973065a97e 245 sendError("Received 0x05 error message");
hudakz 1:9c973065a97e 246 fclose(file);
hudakz 1:9c973065a97e 247 state = LISTENING;
hudakz 1:9c973065a97e 248 strcpy(remoteIP, "");
hudakz 1:9c973065a97e 249 break;
hudakz 1:9c973065a97e 250 } // switch (buff[1])
hudakz 1:9c973065a97e 251 }
hudakz 1:9c973065a97e 252
hudakz 1:9c973065a97e 253 #ifdef TFTP_DEBUG
hudakz 1:9c973065a97e 254 else
hudakz 1:9c973065a97e 255 printf("Ignoring package from other remote client during RRQ.\r\n");
hudakz 1:9c973065a97e 256 #endif
hudakz 1:9c973065a97e 257 break; // reading
hudakz 1:9c973065a97e 258 }
hudakz 1:9c973065a97e 259
hudakz 1:9c973065a97e 260 case WRITING:
hudakz 1:9c973065a97e 261 {
hudakz 1:9c973065a97e 262 if (cmpHost())
hudakz 1:9c973065a97e 263 {
hudakz 1:9c973065a97e 264 switch (buff[1]) {
hudakz 1:9c973065a97e 265 case 0x02:
hudakz 1:9c973065a97e 266 {
hudakz 1:9c973065a97e 267 // if this is a returning host, send ack again
hudakz 1:9c973065a97e 268 ack(0);
hudakz 1:9c973065a97e 269 #ifdef TFTP_DEBUG
hudakz 1:9c973065a97e 270 TFTP_DEBUG("Resending Ack on WRQ.\r\n");
hudakz 1:9c973065a97e 271 #endif
hudakz 1:9c973065a97e 272 break; // case 0x02
hudakz 1:9c973065a97e 273 }
tuxic 0:3b0027b76acf 274
hudakz 1:9c973065a97e 275 case 0x03:
hudakz 1:9c973065a97e 276 {
hudakz 1:9c973065a97e 277 int block = (buff[2] << 8) + buff[3];
hudakz 1:9c973065a97e 278 if ((blockCounter + 1) == block)
hudakz 1:9c973065a97e 279 {
hudakz 1:9c973065a97e 280 ack(block);
hudakz 1:9c973065a97e 281 // new packet
hudakz 1:9c973065a97e 282 char* data = &buff[4];
hudakz 1:9c973065a97e 283 fwrite(data, 1, len - 4, file);
hudakz 1:9c973065a97e 284 blockCounter++;
hudakz 1:9c973065a97e 285 dupCounter = 0;
hudakz 1:9c973065a97e 286 }
hudakz 1:9c973065a97e 287 else
hudakz 1:9c973065a97e 288 { // mismatch in block nr
hudakz 1:9c973065a97e 289 if ((blockCounter + 1) < block)
hudakz 1:9c973065a97e 290 { // too high
hudakz 1:9c973065a97e 291 sendError("Packet count mismatch");
hudakz 1:9c973065a97e 292 fclose(file);
hudakz 1:9c973065a97e 293 state = LISTENING;
hudakz 1:9c973065a97e 294 remove(fileName);
hudakz 1:9c973065a97e 295 strcpy(remoteIP, "");
hudakz 1:9c973065a97e 296 }
hudakz 1:9c973065a97e 297 else
hudakz 1:9c973065a97e 298 { // duplicate packet, send ACK again
hudakz 1:9c973065a97e 299 if (dupCounter > 10)
hudakz 1:9c973065a97e 300 {
hudakz 1:9c973065a97e 301 sendError("Too many dups");
hudakz 1:9c973065a97e 302 fclose(file);
hudakz 1:9c973065a97e 303 remove(fileName);
hudakz 1:9c973065a97e 304 state = LISTENING;
hudakz 1:9c973065a97e 305 }
hudakz 1:9c973065a97e 306 else
hudakz 1:9c973065a97e 307 {
hudakz 1:9c973065a97e 308 ack(blockCounter);
hudakz 1:9c973065a97e 309 dupCounter++;
hudakz 1:9c973065a97e 310 }
hudakz 1:9c973065a97e 311 }
hudakz 1:9c973065a97e 312 }
hudakz 1:9c973065a97e 313
hudakz 1:9c973065a97e 314 if (len < 516)
hudakz 1:9c973065a97e 315 {
hudakz 1:9c973065a97e 316 ack(blockCounter);
hudakz 1:9c973065a97e 317 fclose(file);
hudakz 1:9c973065a97e 318 state = LISTENING;
hudakz 1:9c973065a97e 319 strcpy(remoteIP, "");
hudakz 1:9c973065a97e 320 fileCounter++;
hudakz 1:9c973065a97e 321 #ifdef TFTP_DEBUG
hudakz 1:9c973065a97e 322 printf("File receive finished.\r\n");
hudakz 1:9c973065a97e 323 #endif
hudakz 1:9c973065a97e 324 }
hudakz 1:9c973065a97e 325 break; // case 0x03
hudakz 1:9c973065a97e 326 }
hudakz 1:9c973065a97e 327
hudakz 1:9c973065a97e 328 default:
hudakz 1:9c973065a97e 329 {
hudakz 1:9c973065a97e 330 sendError("No idea why you're sending me this!");
hudakz 1:9c973065a97e 331 break; // default
hudakz 1:9c973065a97e 332 }
hudakz 1:9c973065a97e 333 } // switch (buff[1])
hudakz 1:9c973065a97e 334 }
hudakz 1:9c973065a97e 335
hudakz 1:9c973065a97e 336 #ifdef TFTP_DEBUG
hudakz 1:9c973065a97e 337 else
hudakz 1:9c973065a97e 338 printf("Ignoring packege from other remote client during WRQ.\r\n");
hudakz 1:9c973065a97e 339 #endif
hudakz 1:9c973065a97e 340 break; // writing
hudakz 1:9c973065a97e 341 }
hudakz 1:9c973065a97e 342
hudakz 1:9c973065a97e 343 case ERROR:
hudakz 1:9c973065a97e 344 case SUSPENDED:
hudakz 1:9c973065a97e 345 case DELETED:
hudakz 2:f7c0fbc8c5aa 346 default:
hudakz 1:9c973065a97e 347 { }
hudakz 1:9c973065a97e 348 } // state
hudakz 1:9c973065a97e 349 }
hudakz 1:9c973065a97e 350
hudakz 1:9c973065a97e 351 /**
hudakz 1:9c973065a97e 352 * @brief Gets the file name during read and write.
hudakz 1:9c973065a97e 353 * @note
hudakz 1:9c973065a97e 354 * @param name A pointer to C-style string to be filled with file name.
hudakz 1:9c973065a97e 355 * @retval
hudakz 1:9c973065a97e 356 */
hudakz 1:9c973065a97e 357 void TFTPServer::getFileName(char* name)
hudakz 1:9c973065a97e 358 {
hudakz 1:9c973065a97e 359 sprintf(name, "%s", fileName);
hudakz 1:9c973065a97e 360 }
hudakz 1:9c973065a97e 361
hudakz 1:9c973065a97e 362 /**
hudakz 1:9c973065a97e 363 * @brief Returns number of received files.
hudakz 1:9c973065a97e 364 * @note
hudakz 1:9c973065a97e 365 * @param
hudakz 1:9c973065a97e 366 * @retval
hudakz 1:9c973065a97e 367 */
hudakz 1:9c973065a97e 368 int TFTPServer::fileCount()
hudakz 1:9c973065a97e 369 {
hudakz 1:9c973065a97e 370 return fileCounter;
hudakz 1:9c973065a97e 371 }
hudakz 1:9c973065a97e 372
hudakz 1:9c973065a97e 373 /**
hudakz 1:9c973065a97e 374 * @brief Creates a new connection reading a file from server.
hudakz 1:9c973065a97e 375 * @note Sends the file to the remote client.
hudakz 1:9c973065a97e 376 * Sends en error message to the remote client in case of failure.
hudakz 2:f7c0fbc8c5aa 377 * @param buff A char array to pass data.
hudakz 1:9c973065a97e 378 * @retval
hudakz 1:9c973065a97e 379 */
hudakz 1:9c973065a97e 380 void TFTPServer::connectRead(char* buff)
hudakz 1:9c973065a97e 381 {
hudakz 1:9c973065a97e 382 remoteIP = const_cast<char*>(socketAddr.get_ip_address());
hudakz 1:9c973065a97e 383 remotePort = socketAddr.get_port();
hudakz 1:9c973065a97e 384 blockCounter = 0;
hudakz 1:9c973065a97e 385 dupCounter = 0;
hudakz 1:9c973065a97e 386
hudakz 1:9c973065a97e 387 sprintf(fileName, "%s", &buff[2]);
hudakz 1:9c973065a97e 388
hudakz 1:9c973065a97e 389 if (modeOctet(buff))
hudakz 1:9c973065a97e 390 file = fopen(fileName, "rb");
hudakz 1:9c973065a97e 391 else
hudakz 1:9c973065a97e 392 file = fopen(fileName, "r");
hudakz 1:9c973065a97e 393
hudakz 1:9c973065a97e 394 if (!file)
hudakz 1:9c973065a97e 395 {
hudakz 1:9c973065a97e 396 state = LISTENING;
hudakz 1:9c973065a97e 397
hudakz 1:9c973065a97e 398 char msg[123] = { "Could not read file: " };
hudakz 1:9c973065a97e 399
hudakz 1:9c973065a97e 400 strcat(msg, fileName);
hudakz 1:9c973065a97e 401 strcat(msg, "\r\n");
hudakz 1:9c973065a97e 402 sendError(msg);
hudakz 1:9c973065a97e 403 }
hudakz 1:9c973065a97e 404 else
hudakz 1:9c973065a97e 405 {
tuxic 0:3b0027b76acf 406 // file ready for reading
hudakz 1:9c973065a97e 407 state = READING;
hudakz 1:9c973065a97e 408 #ifdef TFTP_DEBUG
hudakz 1:9c973065a97e 409 printf
hudakz 1:9c973065a97e 410 (
hudakz 1:9c973065a97e 411 "Listening: Requested file %s from TFTP connection %d.%d.%d.%d port %d\r\n",
hudakz 1:9c973065a97e 412 fileName,
hudakz 1:9c973065a97e 413 clientIp[0],
hudakz 1:9c973065a97e 414 clientIp[1],
hudakz 1:9c973065a97e 415 clientIp[2],
hudakz 1:9c973065a97e 416 clientIp[3],
hudakz 1:9c973065a97e 417 clientPort
hudakz 1:9c973065a97e 418 );
hudakz 1:9c973065a97e 419 #endif
tuxic 0:3b0027b76acf 420 getBlock();
tuxic 0:3b0027b76acf 421 sendBlock();
tuxic 0:3b0027b76acf 422 }
tuxic 0:3b0027b76acf 423 }
tuxic 0:3b0027b76acf 424
hudakz 1:9c973065a97e 425 /**
hudakz 1:9c973065a97e 426 * @brief Creates a new connection for writing a file to the server.
hudakz 1:9c973065a97e 427 * @note Sends the file to the TFTP server.
hudakz 1:9c973065a97e 428 * Sends error message to the remote client in case of failure.
hudakz 2:f7c0fbc8c5aa 429 * @param buff A char array to pass data.
hudakz 1:9c973065a97e 430 * @retval
hudakz 1:9c973065a97e 431 */
hudakz 1:9c973065a97e 432 void TFTPServer::connectWrite(char* buff)
hudakz 1:9c973065a97e 433 {
hudakz 1:9c973065a97e 434 remoteIP = const_cast<char*>(socketAddr.get_ip_address());
hudakz 1:9c973065a97e 435 remotePort = socketAddr.get_port();
hudakz 1:9c973065a97e 436 ack(0);
hudakz 1:9c973065a97e 437 blockCounter = 0;
hudakz 1:9c973065a97e 438 dupCounter = 0;
hudakz 1:9c973065a97e 439 sprintf(fileName, "%s", &buff[2]);
tuxic 0:3b0027b76acf 440
hudakz 1:9c973065a97e 441 if (modeOctet(buff))
hudakz 1:9c973065a97e 442 file = fopen(fileName, "wb");
hudakz 1:9c973065a97e 443 else
hudakz 1:9c973065a97e 444 file = fopen(fileName, "w");
tuxic 0:3b0027b76acf 445
hudakz 1:9c973065a97e 446 if (file == NULL)
hudakz 1:9c973065a97e 447 {
hudakz 1:9c973065a97e 448 sendError("Could not open file to write.\r\n");
hudakz 1:9c973065a97e 449 state = LISTENING;
hudakz 1:9c973065a97e 450 strcpy(remoteIP, "");
hudakz 1:9c973065a97e 451 }
hudakz 1:9c973065a97e 452 else
hudakz 1:9c973065a97e 453 {
tuxic 0:3b0027b76acf 454 // file ready for writing
hudakz 1:9c973065a97e 455 blockCounter = 0;
hudakz 1:9c973065a97e 456 state = WRITING;
hudakz 1:9c973065a97e 457 #ifdef TFTP_DEBUG
hudakz 1:9c973065a97e 458 printf
hudakz 1:9c973065a97e 459 (
hudakz 1:9c973065a97e 460 "Listening: Incoming file %s on TFTP connection from %d.%d.%d.%d clientPort %d\r\n",
hudakz 1:9c973065a97e 461 fileName,
hudakz 1:9c973065a97e 462 clientIp[0],
hudakz 1:9c973065a97e 463 clientIp[1],
hudakz 1:9c973065a97e 464 clientIp[2],
hudakz 1:9c973065a97e 465 clientIp[3],
hudakz 1:9c973065a97e 466 clientPort
hudakz 1:9c973065a97e 467 );
hudakz 1:9c973065a97e 468 #endif
tuxic 0:3b0027b76acf 469 }
tuxic 0:3b0027b76acf 470 }
tuxic 0:3b0027b76acf 471
hudakz 1:9c973065a97e 472 /**
hudakz 1:9c973065a97e 473 * @brief Gets DATA block from file on disk into memory.
hudakz 1:9c973065a97e 474 * @note
hudakz 1:9c973065a97e 475 * @param
hudakz 1:9c973065a97e 476 * @retval
hudakz 1:9c973065a97e 477 */
hudakz 1:9c973065a97e 478 void TFTPServer::getBlock()
hudakz 1:9c973065a97e 479 {
hudakz 1:9c973065a97e 480 blockCounter++;
hudakz 1:9c973065a97e 481
hudakz 1:9c973065a97e 482 blockBuff[0] = 0x00;
hudakz 1:9c973065a97e 483 blockBuff[1] = 0x03;
hudakz 1:9c973065a97e 484 blockBuff[2] = blockCounter >> 8;
hudakz 1:9c973065a97e 485 blockBuff[3] = blockCounter & 255;
hudakz 1:9c973065a97e 486 blockSize = 4 + fread((void*) &blockBuff[4], 1, 512, file);
tuxic 0:3b0027b76acf 487 }
tuxic 0:3b0027b76acf 488
hudakz 1:9c973065a97e 489 /**
hudakz 1:9c973065a97e 490 * @brief Sends DATA block to remote client.
hudakz 1:9c973065a97e 491 * @note
hudakz 1:9c973065a97e 492 * @param
hudakz 1:9c973065a97e 493 * @retval
hudakz 1:9c973065a97e 494 */
hudakz 1:9c973065a97e 495 void TFTPServer::sendBlock()
hudakz 1:9c973065a97e 496 {
hudakz 1:9c973065a97e 497 socket->sendto(socketAddr, blockBuff, blockSize);
tuxic 0:3b0027b76acf 498 }
tuxic 0:3b0027b76acf 499
hudakz 1:9c973065a97e 500 /**
hudakz 1:9c973065a97e 501 * @brief Compares host's IP and Port with connected remote machine.
hudakz 1:9c973065a97e 502 * @note
hudakz 1:9c973065a97e 503 * @param
hudakz 1:9c973065a97e 504 * @retval
hudakz 1:9c973065a97e 505 */
hudakz 1:9c973065a97e 506 int TFTPServer::cmpHost()
hudakz 1:9c973065a97e 507 {
hudakz 1:9c973065a97e 508 char ip[17];
hudakz 1:9c973065a97e 509 strcpy(ip, socketAddr.get_ip_address());
hudakz 1:9c973065a97e 510
hudakz 1:9c973065a97e 511 int port = socketAddr.get_port();
hudakz 1:9c973065a97e 512 return((strcmp(ip, remoteIP) == 0) && (port == remotePort));
tuxic 0:3b0027b76acf 513 }
tuxic 0:3b0027b76acf 514
hudakz 1:9c973065a97e 515 /**
hudakz 1:9c973065a97e 516 * @brief Sends ACK to remote client.
hudakz 1:9c973065a97e 517 * @note
hudakz 1:9c973065a97e 518 * @param
hudakz 1:9c973065a97e 519 * @retval
hudakz 1:9c973065a97e 520 */
hudakz 1:9c973065a97e 521 void TFTPServer::ack(int val)
hudakz 1:9c973065a97e 522 {
hudakz 1:9c973065a97e 523 char ack[4];
hudakz 1:9c973065a97e 524 ack[0] = 0x00;
hudakz 1:9c973065a97e 525 ack[1] = 0x04;
hudakz 1:9c973065a97e 526 if ((val > 603135) || (val < 0))
hudakz 1:9c973065a97e 527 val = 0;
hudakz 1:9c973065a97e 528 ack[2] = val >> 8;
hudakz 1:9c973065a97e 529 ack[3] = val & 255;
hudakz 1:9c973065a97e 530 socket->sendto(socketAddr, ack, 4);
hudakz 1:9c973065a97e 531 }
hudakz 1:9c973065a97e 532
hudakz 1:9c973065a97e 533 /**
hudakz 1:9c973065a97e 534 * @brief Sends ERROR message to remote client.
hudakz 1:9c973065a97e 535 * @note msg A C-style string with error message to be sent.
hudakz 1:9c973065a97e 536 * @param
hudakz 1:9c973065a97e 537 * @retval
hudakz 1:9c973065a97e 538 */
hudakz 1:9c973065a97e 539 void TFTPServer::sendError(const char* msg)
hudakz 1:9c973065a97e 540 {
hudakz 1:9c973065a97e 541 errorBuff[0] = 0x00;
hudakz 1:9c973065a97e 542 errorBuff[1] = 0x05;
hudakz 1:9c973065a97e 543 errorBuff[2] = 0x00;
hudakz 1:9c973065a97e 544 errorBuff[3] = 0x00;
hudakz 1:9c973065a97e 545 errorBuff[4] = '\0'; // termination char
hudakz 1:9c973065a97e 546 strcat(&errorBuff[4], msg);
hudakz 1:9c973065a97e 547
hudakz 1:9c973065a97e 548 int len = 4 + strlen(&errorBuff[4]) + 1;
hudakz 1:9c973065a97e 549 socket->sendto(socketAddr, errorBuff, len);
hudakz 2:f7c0fbc8c5aa 550 #ifdef TFTP_DEBUG
hudakz 2:f7c0fbc8c5aa 551 printf("Error: %s\r\n", msg);
hudakz 2:f7c0fbc8c5aa 552 #endif
tuxic 0:3b0027b76acf 553 }
tuxic 0:3b0027b76acf 554
hudakz 1:9c973065a97e 555 /**
hudakz 1:9c973065a97e 556 * @brief Checks if connection mode of client is octet/binary.
hudakz 1:9c973065a97e 557 * @note buff A char array.
hudakz 1:9c973065a97e 558 * @param
hudakz 1:9c973065a97e 559 * @retval
hudakz 1:9c973065a97e 560 */
hudakz 1:9c973065a97e 561 int TFTPServer::modeOctet(char* buff)
hudakz 1:9c973065a97e 562 {
tuxic 0:3b0027b76acf 563 int x = 2;
hudakz 1:9c973065a97e 564
hudakz 1:9c973065a97e 565 while (buff[x++] != 0);
hudakz 1:9c973065a97e 566 // get beginning of mode field
tuxic 0:3b0027b76acf 567 int y = x;
hudakz 1:9c973065a97e 568 while (buff[y] != 0)
hudakz 1:9c973065a97e 569 {
tuxic 0:3b0027b76acf 570 buff[y] = tolower(buff[y]);
tuxic 0:3b0027b76acf 571 y++;
hudakz 1:9c973065a97e 572 } // make mode field lowercase
tuxic 0:3b0027b76acf 573
hudakz 1:9c973065a97e 574 return(strcmp(&buff[x++], "octet") == 0);
tuxic 0:3b0027b76acf 575 }