Zoltan Hudak / TFTPServer

Dependents:   TFTPServerTest

Fork of TFTPServer by Jaap Vermaas

Committer:
hudakz
Date:
Fri Mar 16 19:22:10 2018 +0000
Revision:
1:9c973065a97e
Parent:
0:3b0027b76acf
Child:
2:f7c0fbc8c5aa
Updated for MBED-OS5.

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