Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of TFTPServer by
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 | } |
