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