This is a simple but complete TFTP server, It can receive and send files and listens on port 69. It is part of the LaOS (Laser Open Source) project: http://www.laoslaser.org/
Dependents: TFTPServerTest RMFWeb
TFTPServer.cpp@0:3b0027b76acf, 2011-12-26 (annotated)
- Committer:
- tuxic
- Date:
- Mon Dec 26 18:18:32 2011 +0000
- Revision:
- 0:3b0027b76acf
First version
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 |
tuxic | 0:3b0027b76acf | 6 | * |
tuxic | 0:3b0027b76acf | 7 | * This file is part of the LaOS project (see: http://wiki.laoslaser.org) |
tuxic | 0:3b0027b76acf | 8 | * |
tuxic | 0:3b0027b76acf | 9 | * LaOS is free software: you can redistribute it and/or modify |
tuxic | 0:3b0027b76acf | 10 | * it under the terms of the GNU General Public License as published by |
tuxic | 0:3b0027b76acf | 11 | * the Free Software Foundation, either version 3 of the License, or |
tuxic | 0:3b0027b76acf | 12 | * (at your option) any later version. |
tuxic | 0:3b0027b76acf | 13 | * |
tuxic | 0:3b0027b76acf | 14 | * LaOS is distributed in the hope that it will be useful, |
tuxic | 0:3b0027b76acf | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
tuxic | 0:3b0027b76acf | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
tuxic | 0:3b0027b76acf | 17 | * GNU General Public License for more details. |
tuxic | 0:3b0027b76acf | 18 | * |
tuxic | 0:3b0027b76acf | 19 | * You should have received a copy of the GNU General Public License |
tuxic | 0:3b0027b76acf | 20 | * along with LaOS. If not, see <http://www.gnu.org/licenses/>. |
tuxic | 0:3b0027b76acf | 21 | * |
tuxic | 0:3b0027b76acf | 22 | */ |
tuxic | 0:3b0027b76acf | 23 | #include "TFTPServer.h" |
tuxic | 0:3b0027b76acf | 24 | |
tuxic | 0:3b0027b76acf | 25 | // create a new tftp server, with file directory dir and |
tuxic | 0:3b0027b76acf | 26 | // listening on port |
tuxic | 0:3b0027b76acf | 27 | TFTPServer::TFTPServer(char* dir) { |
tuxic | 0:3b0027b76acf | 28 | ListenSock = new UDPSocket(); |
tuxic | 0:3b0027b76acf | 29 | ListenSock->setOnEvent(this, &TFTPServer::onListenUDPSocketEvent); |
tuxic | 0:3b0027b76acf | 30 | state = listen; |
tuxic | 0:3b0027b76acf | 31 | if (ListenSock->bind(Host(IpAddr(), TFTP_PORT))) |
tuxic | 0:3b0027b76acf | 32 | state = error; |
tuxic | 0:3b0027b76acf | 33 | TFTPServerTimer.attach(this, &TFTPServer::cleanUp, 5000); |
tuxic | 0:3b0027b76acf | 34 | sprintf(workdir, "%s", dir); |
tuxic | 0:3b0027b76acf | 35 | filecnt = 0; |
tuxic | 0:3b0027b76acf | 36 | } |
tuxic | 0:3b0027b76acf | 37 | |
tuxic | 0:3b0027b76acf | 38 | // destroy this instance of the tftp server |
tuxic | 0:3b0027b76acf | 39 | TFTPServer::~TFTPServer() { |
tuxic | 0:3b0027b76acf | 40 | ListenSock->resetOnEvent(); |
tuxic | 0:3b0027b76acf | 41 | delete(ListenSock); |
tuxic | 0:3b0027b76acf | 42 | delete(remote); |
tuxic | 0:3b0027b76acf | 43 | state = deleted; |
tuxic | 0:3b0027b76acf | 44 | } |
tuxic | 0:3b0027b76acf | 45 | |
tuxic | 0:3b0027b76acf | 46 | void TFTPServer::reset() { |
tuxic | 0:3b0027b76acf | 47 | ListenSock->resetOnEvent(); |
tuxic | 0:3b0027b76acf | 48 | delete(ListenSock); |
tuxic | 0:3b0027b76acf | 49 | delete(remote); |
tuxic | 0:3b0027b76acf | 50 | TFTPServerTimer.detach(); |
tuxic | 0:3b0027b76acf | 51 | ListenSock = new UDPSocket(); |
tuxic | 0:3b0027b76acf | 52 | ListenSock->setOnEvent(this, &TFTPServer::onListenUDPSocketEvent); |
tuxic | 0:3b0027b76acf | 53 | state = listen; |
tuxic | 0:3b0027b76acf | 54 | if (ListenSock->bind(Host(IpAddr(), TFTP_PORT))) |
tuxic | 0:3b0027b76acf | 55 | state = error; |
tuxic | 0:3b0027b76acf | 56 | TFTPServerTimer.attach(this, &TFTPServer::cleanUp, 5000); |
tuxic | 0:3b0027b76acf | 57 | sprintf(filename, ""); |
tuxic | 0:3b0027b76acf | 58 | filecnt = 0; |
tuxic | 0:3b0027b76acf | 59 | } |
tuxic | 0:3b0027b76acf | 60 | |
tuxic | 0:3b0027b76acf | 61 | // get current tftp status |
tuxic | 0:3b0027b76acf | 62 | TFTPServerState TFTPServer::State() { |
tuxic | 0:3b0027b76acf | 63 | return state; |
tuxic | 0:3b0027b76acf | 64 | } |
tuxic | 0:3b0027b76acf | 65 | |
tuxic | 0:3b0027b76acf | 66 | // Temporarily disable incoming TFTP connections |
tuxic | 0:3b0027b76acf | 67 | void TFTPServer::suspend() { |
tuxic | 0:3b0027b76acf | 68 | state = suspended; |
tuxic | 0:3b0027b76acf | 69 | } |
tuxic | 0:3b0027b76acf | 70 | |
tuxic | 0:3b0027b76acf | 71 | // Resume after suspension |
tuxic | 0:3b0027b76acf | 72 | void TFTPServer::resume() { |
tuxic | 0:3b0027b76acf | 73 | if (state == suspended) |
tuxic | 0:3b0027b76acf | 74 | state = listen; |
tuxic | 0:3b0027b76acf | 75 | } |
tuxic | 0:3b0027b76acf | 76 | |
tuxic | 0:3b0027b76acf | 77 | // During read and write, this gives you the filename |
tuxic | 0:3b0027b76acf | 78 | void TFTPServer::getFilename(char* name) { |
tuxic | 0:3b0027b76acf | 79 | sprintf(name, "%s", filename); |
tuxic | 0:3b0027b76acf | 80 | } |
tuxic | 0:3b0027b76acf | 81 | |
tuxic | 0:3b0027b76acf | 82 | // return number of received files |
tuxic | 0:3b0027b76acf | 83 | int TFTPServer::fileCnt() { |
tuxic | 0:3b0027b76acf | 84 | return filecnt; |
tuxic | 0:3b0027b76acf | 85 | } |
tuxic | 0:3b0027b76acf | 86 | |
tuxic | 0:3b0027b76acf | 87 | // create a new connection reading a file from server |
tuxic | 0:3b0027b76acf | 88 | void TFTPServer::ConnectRead(char* buff, Host* client) { |
tuxic | 0:3b0027b76acf | 89 | IpAddr clientIp = client->getIp(); |
tuxic | 0:3b0027b76acf | 90 | int clientPort = client->getPort(); |
tuxic | 0:3b0027b76acf | 91 | remote = new Host(clientIp, clientPort); |
tuxic | 0:3b0027b76acf | 92 | Ack(0); |
tuxic | 0:3b0027b76acf | 93 | blockcnt = 0; |
tuxic | 0:3b0027b76acf | 94 | dupcnt = 0; |
tuxic | 0:3b0027b76acf | 95 | |
tuxic | 0:3b0027b76acf | 96 | sprintf(filename, "%s%s", workdir, &buff[2]); |
tuxic | 0:3b0027b76acf | 97 | |
tuxic | 0:3b0027b76acf | 98 | fp = fopen(filename, "rb"); |
tuxic | 0:3b0027b76acf | 99 | if (fp == NULL) { |
tuxic | 0:3b0027b76acf | 100 | state = listen; |
tuxic | 0:3b0027b76acf | 101 | delete(remote); |
tuxic | 0:3b0027b76acf | 102 | Err("Could not read file", client); |
tuxic | 0:3b0027b76acf | 103 | } else { |
tuxic | 0:3b0027b76acf | 104 | // file ready for reading |
tuxic | 0:3b0027b76acf | 105 | blockcnt = 0; |
tuxic | 0:3b0027b76acf | 106 | state = reading; |
tuxic | 0:3b0027b76acf | 107 | #ifdef TFTP_DEBUG |
tuxic | 0:3b0027b76acf | 108 | char debugmsg[256]; |
tuxic | 0:3b0027b76acf | 109 | sprintf(debugmsg, "Listen: Requested file %s from TFTP connection %d.%d.%d.%d port %d", |
tuxic | 0:3b0027b76acf | 110 | filename, clientIp[0], clientIp[1], clientIp[2], clientIp[3], clientPort); |
tuxic | 0:3b0027b76acf | 111 | TFTP_DEBUG(debugmsg); |
tuxic | 0:3b0027b76acf | 112 | #endif |
tuxic | 0:3b0027b76acf | 113 | getBlock(); |
tuxic | 0:3b0027b76acf | 114 | sendBlock(); |
tuxic | 0:3b0027b76acf | 115 | } |
tuxic | 0:3b0027b76acf | 116 | } |
tuxic | 0:3b0027b76acf | 117 | |
tuxic | 0:3b0027b76acf | 118 | // create a new connection writing a file to the server |
tuxic | 0:3b0027b76acf | 119 | void TFTPServer::ConnectWrite(char* buff, Host* client) { |
tuxic | 0:3b0027b76acf | 120 | IpAddr clientIp = client->getIp(); |
tuxic | 0:3b0027b76acf | 121 | int clientPort = client->getPort(); |
tuxic | 0:3b0027b76acf | 122 | remote = new Host(clientIp, clientPort); |
tuxic | 0:3b0027b76acf | 123 | Ack(0); |
tuxic | 0:3b0027b76acf | 124 | blockcnt = 0; |
tuxic | 0:3b0027b76acf | 125 | dupcnt = 0; |
tuxic | 0:3b0027b76acf | 126 | |
tuxic | 0:3b0027b76acf | 127 | sprintf(filename, "%s%s", workdir, &buff[2]); |
tuxic | 0:3b0027b76acf | 128 | |
tuxic | 0:3b0027b76acf | 129 | fp = fopen(filename, "wb"); |
tuxic | 0:3b0027b76acf | 130 | if (fp == NULL) { |
tuxic | 0:3b0027b76acf | 131 | Err("Could not open file to write", client); |
tuxic | 0:3b0027b76acf | 132 | state = listen; |
tuxic | 0:3b0027b76acf | 133 | delete(remote); |
tuxic | 0:3b0027b76acf | 134 | } else { |
tuxic | 0:3b0027b76acf | 135 | // file ready for writing |
tuxic | 0:3b0027b76acf | 136 | blockcnt = 0; |
tuxic | 0:3b0027b76acf | 137 | state = writing; |
tuxic | 0:3b0027b76acf | 138 | #ifdef TFTP_DEBUG |
tuxic | 0:3b0027b76acf | 139 | char debugmsg[256]; |
tuxic | 0:3b0027b76acf | 140 | sprintf(debugmsg, "Listen: Incoming file %s on TFTP connection from %d.%d.%d.%d clientPort %d", |
tuxic | 0:3b0027b76acf | 141 | filename, clientIp[0], clientIp[1], clientIp[2], clientIp[3], clientPort); |
tuxic | 0:3b0027b76acf | 142 | TFTP_DEBUG(debugmsg); |
tuxic | 0:3b0027b76acf | 143 | #endif |
tuxic | 0:3b0027b76acf | 144 | } |
tuxic | 0:3b0027b76acf | 145 | } |
tuxic | 0:3b0027b76acf | 146 | |
tuxic | 0:3b0027b76acf | 147 | // get DATA block from file on disk into memory |
tuxic | 0:3b0027b76acf | 148 | void TFTPServer::getBlock() { |
tuxic | 0:3b0027b76acf | 149 | blockcnt++; |
tuxic | 0:3b0027b76acf | 150 | char *p; |
tuxic | 0:3b0027b76acf | 151 | p = &sendbuff[4]; |
tuxic | 0:3b0027b76acf | 152 | int len = fread(p, 1, 512, fp); |
tuxic | 0:3b0027b76acf | 153 | sendbuff[0] = 0x00; |
tuxic | 0:3b0027b76acf | 154 | sendbuff[1] = 0x03; |
tuxic | 0:3b0027b76acf | 155 | sendbuff[2] = blockcnt >> 8; |
tuxic | 0:3b0027b76acf | 156 | sendbuff[3] = blockcnt & 255; |
tuxic | 0:3b0027b76acf | 157 | blocksize = len+4; |
tuxic | 0:3b0027b76acf | 158 | } |
tuxic | 0:3b0027b76acf | 159 | |
tuxic | 0:3b0027b76acf | 160 | // send DATA block to the client |
tuxic | 0:3b0027b76acf | 161 | void TFTPServer::sendBlock() { |
tuxic | 0:3b0027b76acf | 162 | ListenSock->sendto(sendbuff, blocksize, remote); |
tuxic | 0:3b0027b76acf | 163 | } |
tuxic | 0:3b0027b76acf | 164 | |
tuxic | 0:3b0027b76acf | 165 | |
tuxic | 0:3b0027b76acf | 166 | // compare host IP and Port with connected remote machine |
tuxic | 0:3b0027b76acf | 167 | int TFTPServer::cmpHost(Host* client) { |
tuxic | 0:3b0027b76acf | 168 | IpAddr clientIp = client->getIp(); |
tuxic | 0:3b0027b76acf | 169 | IpAddr remoteIp = remote->getIp(); |
tuxic | 0:3b0027b76acf | 170 | int clientPort = client->getPort(); |
tuxic | 0:3b0027b76acf | 171 | int remotePort = remote->getPort(); |
tuxic | 0:3b0027b76acf | 172 | return ((clientIp == remoteIp) && (clientPort == remotePort)); |
tuxic | 0:3b0027b76acf | 173 | } |
tuxic | 0:3b0027b76acf | 174 | |
tuxic | 0:3b0027b76acf | 175 | // send ACK to remote |
tuxic | 0:3b0027b76acf | 176 | void TFTPServer::Ack(int val) { |
tuxic | 0:3b0027b76acf | 177 | char ack[4]; |
tuxic | 0:3b0027b76acf | 178 | ack[0] = 0x00; |
tuxic | 0:3b0027b76acf | 179 | ack[1] = 0x04; |
tuxic | 0:3b0027b76acf | 180 | if ((val>603135) || (val<0)) val = 0; |
tuxic | 0:3b0027b76acf | 181 | ack[2] = val >> 8; |
tuxic | 0:3b0027b76acf | 182 | ack[3] = val & 255; |
tuxic | 0:3b0027b76acf | 183 | ListenSock->sendto(ack, 4, remote); |
tuxic | 0:3b0027b76acf | 184 | } |
tuxic | 0:3b0027b76acf | 185 | |
tuxic | 0:3b0027b76acf | 186 | // send ERR message to named client |
tuxic | 0:3b0027b76acf | 187 | void TFTPServer::Err(char* msg, Host* client) { |
tuxic | 0:3b0027b76acf | 188 | char message[32]; |
tuxic | 0:3b0027b76acf | 189 | strncpy(message, msg, 32); |
tuxic | 0:3b0027b76acf | 190 | char err[37]; |
tuxic | 0:3b0027b76acf | 191 | sprintf(err, "0000%s0", message); |
tuxic | 0:3b0027b76acf | 192 | err[0] = 0x00; |
tuxic | 0:3b0027b76acf | 193 | err[1] = 0x05; |
tuxic | 0:3b0027b76acf | 194 | err[2]=0x00; |
tuxic | 0:3b0027b76acf | 195 | err[3]=0x00; |
tuxic | 0:3b0027b76acf | 196 | int len = strlen(err); |
tuxic | 0:3b0027b76acf | 197 | err[len-1] = 0x00; |
tuxic | 0:3b0027b76acf | 198 | ListenSock->sendto(err, len, client); |
tuxic | 0:3b0027b76acf | 199 | #ifdef TFTP_DEBUG |
tuxic | 0:3b0027b76acf | 200 | char debugmsg[256]; |
tuxic | 0:3b0027b76acf | 201 | sprintf(debugmsg, "Error: %s", message); |
tuxic | 0:3b0027b76acf | 202 | TFTP_DEBUG(debugmsg); |
tuxic | 0:3b0027b76acf | 203 | #endif |
tuxic | 0:3b0027b76acf | 204 | } |
tuxic | 0:3b0027b76acf | 205 | |
tuxic | 0:3b0027b76acf | 206 | // check if connection mode of client is octet/binary |
tuxic | 0:3b0027b76acf | 207 | int TFTPServer::modeOctet(char* buff) { |
tuxic | 0:3b0027b76acf | 208 | int x = 2; |
tuxic | 0:3b0027b76acf | 209 | while (buff[x++] != 0); // get beginning of mode field |
tuxic | 0:3b0027b76acf | 210 | int y = x; |
tuxic | 0:3b0027b76acf | 211 | while (buff[y] != 0) { |
tuxic | 0:3b0027b76acf | 212 | buff[y] = tolower(buff[y]); |
tuxic | 0:3b0027b76acf | 213 | y++; |
tuxic | 0:3b0027b76acf | 214 | } // make mode field lowercase |
tuxic | 0:3b0027b76acf | 215 | return (strcmp(&buff[x++], "octet") == 0); |
tuxic | 0:3b0027b76acf | 216 | } |
tuxic | 0:3b0027b76acf | 217 | |
tuxic | 0:3b0027b76acf | 218 | // timed routine to avoid hanging after interrupted transfers |
tuxic | 0:3b0027b76acf | 219 | void TFTPServer::cleanUp() { |
tuxic | 0:3b0027b76acf | 220 | static int lastcnt; |
tuxic | 0:3b0027b76acf | 221 | switch (state) { |
tuxic | 0:3b0027b76acf | 222 | case reading: |
tuxic | 0:3b0027b76acf | 223 | if (lastcnt == blockcnt) { |
tuxic | 0:3b0027b76acf | 224 | fclose(fp); |
tuxic | 0:3b0027b76acf | 225 | state=listen; |
tuxic | 0:3b0027b76acf | 226 | delete(remote); |
tuxic | 0:3b0027b76acf | 227 | } |
tuxic | 0:3b0027b76acf | 228 | break; |
tuxic | 0:3b0027b76acf | 229 | case writing: |
tuxic | 0:3b0027b76acf | 230 | if (lastcnt == blockcnt) { |
tuxic | 0:3b0027b76acf | 231 | fclose(fp); |
tuxic | 0:3b0027b76acf | 232 | state = listen; |
tuxic | 0:3b0027b76acf | 233 | remove(filename); |
tuxic | 0:3b0027b76acf | 234 | delete(remote); |
tuxic | 0:3b0027b76acf | 235 | } |
tuxic | 0:3b0027b76acf | 236 | break; |
tuxic | 0:3b0027b76acf | 237 | } // state |
tuxic | 0:3b0027b76acf | 238 | lastcnt = blockcnt; |
tuxic | 0:3b0027b76acf | 239 | } |
tuxic | 0:3b0027b76acf | 240 | |
tuxic | 0:3b0027b76acf | 241 | // event driven routines to handle incoming packets |
tuxic | 0:3b0027b76acf | 242 | void TFTPServer::onListenUDPSocketEvent(UDPSocketEvent e) { |
tuxic | 0:3b0027b76acf | 243 | extern SDFileSystem sd; |
tuxic | 0:3b0027b76acf | 244 | Host* client = new Host(); |
tuxic | 0:3b0027b76acf | 245 | char buff[516]; |
tuxic | 0:3b0027b76acf | 246 | if (e == UDPSOCKET_READABLE) { |
tuxic | 0:3b0027b76acf | 247 | switch (state) { |
tuxic | 0:3b0027b76acf | 248 | case listen: |
tuxic | 0:3b0027b76acf | 249 | if (int len = ListenSock->recvfrom(buff, 516, client)) { |
tuxic | 0:3b0027b76acf | 250 | switch (buff[1]) { |
tuxic | 0:3b0027b76acf | 251 | case 0x01: // RRQ |
tuxic | 0:3b0027b76acf | 252 | if (modeOctet(buff)) |
tuxic | 0:3b0027b76acf | 253 | ConnectRead(buff, client); |
tuxic | 0:3b0027b76acf | 254 | else |
tuxic | 0:3b0027b76acf | 255 | Err("Not in octet mode", client); |
tuxic | 0:3b0027b76acf | 256 | break; |
tuxic | 0:3b0027b76acf | 257 | case 0x02: // WRQ |
tuxic | 0:3b0027b76acf | 258 | if (modeOctet(buff)) |
tuxic | 0:3b0027b76acf | 259 | ConnectWrite(buff, client); |
tuxic | 0:3b0027b76acf | 260 | else |
tuxic | 0:3b0027b76acf | 261 | Err("Not in octet mode", client); |
tuxic | 0:3b0027b76acf | 262 | break; |
tuxic | 0:3b0027b76acf | 263 | case 0x03: // DATA before connection established |
tuxic | 0:3b0027b76acf | 264 | Err("No data expected", client); |
tuxic | 0:3b0027b76acf | 265 | break; |
tuxic | 0:3b0027b76acf | 266 | case 0x04: // ACK before connection established |
tuxic | 0:3b0027b76acf | 267 | Err("No ack expected", client); |
tuxic | 0:3b0027b76acf | 268 | break; |
tuxic | 0:3b0027b76acf | 269 | case 0x05: // ERROR packet received |
tuxic | 0:3b0027b76acf | 270 | #ifdef TFTP_DEBUG |
tuxic | 0:3b0027b76acf | 271 | TFTP_DEBUG("TFTP Eror received\n\r"); |
tuxic | 0:3b0027b76acf | 272 | #endif |
tuxic | 0:3b0027b76acf | 273 | break; |
tuxic | 0:3b0027b76acf | 274 | default: // unknown TFTP packet type |
tuxic | 0:3b0027b76acf | 275 | Err("Unknown TFTP packet type", client); |
tuxic | 0:3b0027b76acf | 276 | break; |
tuxic | 0:3b0027b76acf | 277 | } // switch buff[1] |
tuxic | 0:3b0027b76acf | 278 | } // recvfrom |
tuxic | 0:3b0027b76acf | 279 | break; // case listen |
tuxic | 0:3b0027b76acf | 280 | case reading: |
tuxic | 0:3b0027b76acf | 281 | while (int len = ListenSock->recvfrom(buff, 516, client) ) { |
tuxic | 0:3b0027b76acf | 282 | switch (buff[1]) { |
tuxic | 0:3b0027b76acf | 283 | case 0x01: |
tuxic | 0:3b0027b76acf | 284 | // if this is the receiving host, send first packet again |
tuxic | 0:3b0027b76acf | 285 | if ((cmpHost(client) && blockcnt==1)) { |
tuxic | 0:3b0027b76acf | 286 | sendBlock(); |
tuxic | 0:3b0027b76acf | 287 | dupcnt++; |
tuxic | 0:3b0027b76acf | 288 | } |
tuxic | 0:3b0027b76acf | 289 | if (dupcnt>10) { // too many dups, stop sending |
tuxic | 0:3b0027b76acf | 290 | fclose(fp); |
tuxic | 0:3b0027b76acf | 291 | state=listen; |
tuxic | 0:3b0027b76acf | 292 | delete(remote); |
tuxic | 0:3b0027b76acf | 293 | } |
tuxic | 0:3b0027b76acf | 294 | break; |
tuxic | 0:3b0027b76acf | 295 | case 0x02: |
tuxic | 0:3b0027b76acf | 296 | // this should never happen, ignore |
tuxic | 0:3b0027b76acf | 297 | break; // case 0x02 |
tuxic | 0:3b0027b76acf | 298 | case 0x03: |
tuxic | 0:3b0027b76acf | 299 | // we are the sending side, ignore |
tuxic | 0:3b0027b76acf | 300 | break; |
tuxic | 0:3b0027b76acf | 301 | case 0x04: |
tuxic | 0:3b0027b76acf | 302 | // last packet received, send next if there is one |
tuxic | 0:3b0027b76acf | 303 | dupcnt = 0; |
tuxic | 0:3b0027b76acf | 304 | if (blocksize == 516) { |
tuxic | 0:3b0027b76acf | 305 | getBlock(); |
tuxic | 0:3b0027b76acf | 306 | sendBlock(); |
tuxic | 0:3b0027b76acf | 307 | } else { //EOF |
tuxic | 0:3b0027b76acf | 308 | fclose(fp); |
tuxic | 0:3b0027b76acf | 309 | state = listen; |
tuxic | 0:3b0027b76acf | 310 | delete(remote); |
tuxic | 0:3b0027b76acf | 311 | } |
tuxic | 0:3b0027b76acf | 312 | break; |
tuxic | 0:3b0027b76acf | 313 | default: // this includes 0x05 errors |
tuxic | 0:3b0027b76acf | 314 | fclose(fp); |
tuxic | 0:3b0027b76acf | 315 | state = listen; |
tuxic | 0:3b0027b76acf | 316 | delete(remote); |
tuxic | 0:3b0027b76acf | 317 | break; |
tuxic | 0:3b0027b76acf | 318 | } // switch (buff[1]) |
tuxic | 0:3b0027b76acf | 319 | } // while |
tuxic | 0:3b0027b76acf | 320 | break; // reading |
tuxic | 0:3b0027b76acf | 321 | case writing: |
tuxic | 0:3b0027b76acf | 322 | while (int len = ListenSock->recvfrom(buff, 516, client) ) { |
tuxic | 0:3b0027b76acf | 323 | switch (buff[1]) { |
tuxic | 0:3b0027b76acf | 324 | case 0x02: |
tuxic | 0:3b0027b76acf | 325 | // if this is a returning host, send ack again |
tuxic | 0:3b0027b76acf | 326 | if (cmpHost(client)) { |
tuxic | 0:3b0027b76acf | 327 | Ack(0); |
tuxic | 0:3b0027b76acf | 328 | #ifdef TFTP_DEBUG |
tuxic | 0:3b0027b76acf | 329 | TFTP_DEBUG("Resending Ack on WRQ"); |
tuxic | 0:3b0027b76acf | 330 | #endif |
tuxic | 0:3b0027b76acf | 331 | } |
tuxic | 0:3b0027b76acf | 332 | break; // case 0x02 |
tuxic | 0:3b0027b76acf | 333 | case 0x03: |
tuxic | 0:3b0027b76acf | 334 | if (cmpHost(client)) { // check if this is our partner |
tuxic | 0:3b0027b76acf | 335 | int block = (buff[2] << 8) + buff[3]; |
tuxic | 0:3b0027b76acf | 336 | if ((blockcnt+1) == block) { |
tuxic | 0:3b0027b76acf | 337 | Ack(block); |
tuxic | 0:3b0027b76acf | 338 | // new packet |
tuxic | 0:3b0027b76acf | 339 | char *data = &buff[4]; |
tuxic | 0:3b0027b76acf | 340 | fwrite(data, 1,len-4, fp); |
tuxic | 0:3b0027b76acf | 341 | blockcnt++; |
tuxic | 0:3b0027b76acf | 342 | dupcnt = 0; |
tuxic | 0:3b0027b76acf | 343 | } else { |
tuxic | 0:3b0027b76acf | 344 | if ((blockcnt+1) < block) { // high block nr |
tuxic | 0:3b0027b76acf | 345 | // we missed a packet, error |
tuxic | 0:3b0027b76acf | 346 | #ifdef TFTP_DEBUG |
tuxic | 0:3b0027b76acf | 347 | TFTP_DEBUG("Missed packet!"); |
tuxic | 0:3b0027b76acf | 348 | #endif |
tuxic | 0:3b0027b76acf | 349 | fclose(fp); |
tuxic | 0:3b0027b76acf | 350 | state = listen; |
tuxic | 0:3b0027b76acf | 351 | remove(filename); |
tuxic | 0:3b0027b76acf | 352 | delete(remote); |
tuxic | 0:3b0027b76acf | 353 | } else { // duplicate packet, do nothing |
tuxic | 0:3b0027b76acf | 354 | #ifdef TFTP_DEBUG |
tuxic | 0:3b0027b76acf | 355 | char debugmsg[256]; |
tuxic | 0:3b0027b76acf | 356 | sprintf(debugmsg, "Dupblicate packet %d", blockcnt); |
tuxic | 0:3b0027b76acf | 357 | TFTP_DEBUG(debugmsg); |
tuxic | 0:3b0027b76acf | 358 | #endif |
tuxic | 0:3b0027b76acf | 359 | if (dupcnt > 10) { |
tuxic | 0:3b0027b76acf | 360 | Err("Too many dups", client); |
tuxic | 0:3b0027b76acf | 361 | fclose(fp); |
tuxic | 0:3b0027b76acf | 362 | remove(filename); |
tuxic | 0:3b0027b76acf | 363 | state = listen; |
tuxic | 0:3b0027b76acf | 364 | } else { |
tuxic | 0:3b0027b76acf | 365 | Ack(blockcnt); |
tuxic | 0:3b0027b76acf | 366 | } |
tuxic | 0:3b0027b76acf | 367 | dupcnt++; |
tuxic | 0:3b0027b76acf | 368 | } |
tuxic | 0:3b0027b76acf | 369 | } |
tuxic | 0:3b0027b76acf | 370 | //printf ("Read packet %d with blocksize = %d\n\r", blockcnt, len); |
tuxic | 0:3b0027b76acf | 371 | if (len<516) { |
tuxic | 0:3b0027b76acf | 372 | #ifdef TFTP_DEBUG |
tuxic | 0:3b0027b76acf | 373 | char debugmsg[256]; |
tuxic | 0:3b0027b76acf | 374 | sprintf(debugmsg, "Read last block %d", len); |
tuxic | 0:3b0027b76acf | 375 | TFTP_DEBUG(debugmsg); |
tuxic | 0:3b0027b76acf | 376 | #endif |
tuxic | 0:3b0027b76acf | 377 | fclose(fp); |
tuxic | 0:3b0027b76acf | 378 | state = listen; |
tuxic | 0:3b0027b76acf | 379 | delete(remote); |
tuxic | 0:3b0027b76acf | 380 | filecnt++; |
tuxic | 0:3b0027b76acf | 381 | } |
tuxic | 0:3b0027b76acf | 382 | break; // case 0x03 |
tuxic | 0:3b0027b76acf | 383 | } else // if cmpHost |
tuxic | 0:3b0027b76acf | 384 | Err("Wrong IP/Port: Not your connection!", client); |
tuxic | 0:3b0027b76acf | 385 | break; // case 0x03 |
tuxic | 0:3b0027b76acf | 386 | default: |
tuxic | 0:3b0027b76acf | 387 | Err("No idea why you're sending me this!", client); |
tuxic | 0:3b0027b76acf | 388 | break; // default |
tuxic | 0:3b0027b76acf | 389 | } // switch (buff[1]) |
tuxic | 0:3b0027b76acf | 390 | } // while |
tuxic | 0:3b0027b76acf | 391 | break; // writing |
tuxic | 0:3b0027b76acf | 392 | case suspended: |
tuxic | 0:3b0027b76acf | 393 | if (int len = ListenSock->recvfrom(buff, 516, client)) |
tuxic | 0:3b0027b76acf | 394 | Err("Packet received on suspended socket, discarded", client); |
tuxic | 0:3b0027b76acf | 395 | break; |
tuxic | 0:3b0027b76acf | 396 | } // state |
tuxic | 0:3b0027b76acf | 397 | } else { |
tuxic | 0:3b0027b76acf | 398 | #ifdef TFTP_DEBUG |
tuxic | 0:3b0027b76acf | 399 | TFTP_DEBUG("TFTP unknown UDP status"); |
tuxic | 0:3b0027b76acf | 400 | #endif |
tuxic | 0:3b0027b76acf | 401 | } |
tuxic | 0:3b0027b76acf | 402 | delete(client); |
tuxic | 0:3b0027b76acf | 403 | } |