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/
Fork of TFTPServer by
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.
TFTPServer.cpp@2:f7c0fbc8c5aa, 2018-03-20 (annotated)
- Committer:
- hudakz
- Date:
- Tue Mar 20 17:31:42 2018 +0000
- Revision:
- 2:f7c0fbc8c5aa
- Parent:
- 1:9c973065a97e
Updated.
Who changed what in which revision?
User | Revision | Line number | New 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 | } |