TFTPServer.Mod 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. MODULE TFTPServer; (** AUTHOR "be"; PURPOSE "TFTP server"; *)
  2. IMPORT IP, UDP, Files, Kernel, KernelLog, Random;
  3. CONST
  4. Ok = UDP.Ok;
  5. (* General Settings *)
  6. TFTPPort = 69;
  7. MaxSocketRetries = 64;
  8. MaxRetries = 5;
  9. MaxWait = 3;
  10. BlockSize = 512;
  11. DataTimeout = 3000; (* ms *)
  12. AckTimeout = 3000; (* ms *)
  13. (* Packet Types *)
  14. RRQ = 1;
  15. WRQ = 2;
  16. DATA = 3;
  17. ACK = 4;
  18. ERROR = 5;
  19. RRQId = "TFTP RRQ: ";
  20. WRQId = "TFTP WRQ: ";
  21. TFTPId = "TFTP Server: ";
  22. TYPE
  23. ErrorMsg = ARRAY 32 OF CHAR;
  24. TFTP = OBJECT
  25. VAR socket: UDP.Socket;
  26. fip: IP.Adr;
  27. lport, fport: LONGINT;
  28. res: WORD;
  29. dead: BOOLEAN;
  30. buf: ARRAY BlockSize + 4 OF CHAR;
  31. timer: Kernel.Timer;
  32. (* Log functions *)
  33. PROCEDURE LogEnter(level: LONGINT);
  34. BEGIN IF (TraceLevel >= level) THEN KernelLog.Enter END
  35. END LogEnter;
  36. PROCEDURE LogExit(level: LONGINT);
  37. BEGIN IF (TraceLevel >= level) THEN KernelLog.Exit END
  38. END LogExit;
  39. PROCEDURE Log(level: LONGINT; CONST s: ARRAY OF CHAR);
  40. BEGIN IF (TraceLevel >= level) THEN KernelLog.String(s) END
  41. END Log;
  42. PROCEDURE LogInt(level, i: LONGINT);
  43. BEGIN IF (TraceLevel >= level) THEN KernelLog.Int(i, 0) END
  44. END LogInt;
  45. (* Get2 - reads a (big endian) 16bit value from 'buf' at position 'ofs'..'ofs'+1 *)
  46. PROCEDURE Get2(CONST buf: ARRAY OF CHAR; ofs: LONGINT): LONGINT;
  47. BEGIN RETURN ORD(buf[ofs])*100H + ORD(buf[ofs+1])
  48. END Get2;
  49. (* Put2 - writes a (big endian) 16bit value to 'buf' at position 'ofs'..'ofs'+1 *)
  50. PROCEDURE Put2(VAR buf: ARRAY OF CHAR; ofs, value: LONGINT);
  51. BEGIN buf[ofs] := CHR(value DIV 100H MOD 100H); buf[ofs+1] := CHR(value MOD 100H)
  52. END Put2;
  53. (* PacketType - returns the type of a packet *)
  54. PROCEDURE PacketType(CONST buf: ARRAY OF CHAR): LONGINT;
  55. BEGIN RETURN Get2(buf, 0)
  56. END PacketType;
  57. (* ExtractString - extracts a 0X terminated 8bit string from a buffer *)
  58. PROCEDURE ExtractString(CONST buf: ARRAY OF CHAR; VAR ofs: LONGINT; VAR s: ARRAY OF CHAR);
  59. VAR pos: LONGINT;
  60. BEGIN
  61. WHILE (ofs < LEN(buf)) & (buf[ofs] # 0X) DO
  62. IF (pos < LEN(s)-1) THEN s[pos] := buf[ofs]; INC(pos) END;
  63. INC(ofs)
  64. END;
  65. s[pos] := 0X; INC(ofs)
  66. END ExtractString;
  67. (* SendAck - sends an ack packet *)
  68. PROCEDURE SendAck(blockNr: LONGINT; VAR res: WORD);
  69. VAR ackHdr: ARRAY 4 OF CHAR; retries: LONGINT;
  70. BEGIN
  71. Put2(ackHdr, 0, ACK); Put2(ackHdr, 2, blockNr);
  72. REPEAT
  73. INC(retries);
  74. socket.Send(fip, fport, ackHdr, 0, LEN(ackHdr), res);
  75. UNTIL (res = Ok) OR (retries > MaxRetries)
  76. END SendAck;
  77. (* SendError - sends an error packet *)
  78. PROCEDURE SendError(errNo: INTEGER; s: ErrorMsg; VAR res: WORD);
  79. VAR errHdr: ARRAY BlockSize+4 OF CHAR; p, retries: LONGINT;
  80. BEGIN
  81. Put2(errHdr, 0, ERROR); Put2(errHdr, 2, errNo);
  82. IF ((errNo = 0) & (s = "")) OR ((errNo > 0) & (errNo < 8)) THEN s := errorMsg[errNo] END;
  83. WHILE (p < BlockSize-1) & (s[p] # 0X) DO errHdr[4+p] := s[p]; INC(p) END;
  84. errHdr[4+p] := 0X;
  85. REPEAT
  86. INC(retries);
  87. socket.Send(fip, fport, errHdr, 0, p+4, res)
  88. UNTIL (res = Ok) OR (retries > MaxRetries)
  89. END SendError;
  90. PROCEDURE Die;
  91. BEGIN { EXCLUSIVE }
  92. dead := TRUE
  93. END Die;
  94. PROCEDURE AwaitDeath;
  95. BEGIN { EXCLUSIVE }
  96. AWAIT(dead)
  97. END AwaitDeath;
  98. END TFTP;
  99. TFTPRRQ = OBJECT(TFTP)
  100. VAR
  101. ip: IP.Adr;
  102. ack: ARRAY 4 OF CHAR;
  103. port, len, wait, retries, blockNr: LONGINT;
  104. acked: BOOLEAN;
  105. file: Files.File;
  106. r: Files.Rider;
  107. (* Init - constructor *)
  108. PROCEDURE &Init*(fip: IP.Adr; fport: LONGINT; CONST filename: Files.FileName; VAR res: WORD);
  109. VAR retries: LONGINT;
  110. BEGIN SELF.fip := fip; SELF.fport := fport;
  111. file := Files.Old(filename);
  112. IF (file # NIL) THEN
  113. REPEAT
  114. INC(retries); lport := 1024 + generator.Integer() MOD 64512;
  115. NEW(socket, lport, res);
  116. UNTIL (res # UDP.PortInUse) OR (retries > MaxSocketRetries)
  117. ELSE
  118. res := -1
  119. END
  120. END Init;
  121. BEGIN {ACTIVE}
  122. IF (socket = NIL) THEN RETURN END;
  123. LogEnter(2); Log(2, RRQId); Log(2, "sending file on port "); LogInt(2, lport); Log(2, "..."); LogExit(2);
  124. file.Set(r, 0);
  125. Put2(buf, 0, 3); (* DATA packet *)
  126. blockNr := 0; acked := TRUE;
  127. WHILE ~r.eof & acked DO
  128. INC(blockNr);
  129. buf[2] := CHR(blockNr DIV 100H); buf[3] := CHR(blockNr MOD 100H);
  130. file.ReadBytes(r, buf, 4, BlockSize);
  131. retries := 0;
  132. REPEAT
  133. INC(retries);
  134. LogEnter(3); Log(3, RRQId); Log(3, "sending block "); LogInt(3, blockNr);
  135. Log(3, " ("); LogInt(3, BlockSize-r.res); Log(3, " bytes) ");
  136. IF (retries > 1) THEN Log(3, "(retry "); LogInt(3, retries); Log(3, ")") END;
  137. LogExit(3);
  138. socket.Send(fip, fport, buf, 0, 4 + BlockSize - r.res, res);
  139. wait := 0;
  140. REPEAT
  141. INC(wait);
  142. LogEnter(3); Log(3, RRQId); Log(3, "waiting for ack... ");
  143. IF (wait > 1) THEN Log(3, "(retry "); LogInt(3, wait); Log(3, ")") END;
  144. LogExit(3);
  145. acked := FALSE;
  146. socket.Receive(ack, 0, 4, AckTimeout, ip, port, len, res);
  147. LogEnter(3); Log(3, RRQId);
  148. IF (res = UDP.Timeout) THEN Log(3, "timeout")
  149. ELSIF (res = Ok) THEN
  150. acked := (res = Ok) & (PacketType(ack) = ACK) & (Get2(ack, 2) = blockNr) & (IP.AdrsEqual(ip, fip)) & (fport = port);
  151. IF acked THEN Log(3, "got ack") ELSE Log(3, "ack failed") END
  152. ELSE
  153. Log(3, "unknown error "); LogInt(3, LONGINT(res))
  154. END;
  155. LogExit(3)
  156. UNTIL acked OR (res # Ok) OR (wait > MaxWait)
  157. UNTIL acked OR (retries > MaxRetries)
  158. END;
  159. LogEnter(2); Log(2, RRQId);
  160. IF ~acked THEN Log(2, "file not completely sent")
  161. ELSE Log(2, "file successfully sent")
  162. END;
  163. LogExit(2);
  164. NEW(timer);
  165. timer.Sleep(AckTimeout+500);
  166. Die
  167. END TFTPRRQ;
  168. TFTPWRQ = OBJECT(TFTP)
  169. VAR
  170. ip: IP.Adr;
  171. port, len, waitPacket, retries, blockNr: LONGINT;
  172. Abort: BOOLEAN;
  173. file: Files.File;
  174. r: Files.Rider;
  175. (* Init - constructor *)
  176. PROCEDURE &Init*(fip: IP.Adr; fport: LONGINT; CONST filename: Files.FileName; VAR res: WORD);
  177. VAR retries: LONGINT;
  178. BEGIN
  179. SELF.fip := fip; SELF.fport := fport; res := 0;
  180. file := Files.Old(filename);
  181. IF (file = NIL) THEN
  182. file := Files.New(filename);
  183. IF (file = NIL) THEN
  184. LogEnter(1); Log(1, TFTPId); Log(1, "unexpected error: can't create '"); Log(1, filename); Log(1, "'"); LogExit(1);
  185. res := -1;
  186. ELSE
  187. REPEAT
  188. INC(retries); lport := 1024 + generator.Integer() MOD 64512;
  189. NEW(socket, lport, res)
  190. UNTIL (res # UDP.PortInUse) OR (retries > MaxSocketRetries)
  191. END
  192. ELSE
  193. res := -1
  194. END
  195. END Init;
  196. BEGIN {ACTIVE}
  197. IF (socket = NIL) THEN RETURN END;
  198. LogEnter(2); Log(2, WRQId); Log(2, "receiving file on port "); LogInt(2, lport); Log(2, "..."); LogExit(2);
  199. file.Set(r, 0);
  200. Files.Register(file);
  201. blockNr := 0;
  202. SendAck(blockNr, res);
  203. IF (res = Ok) THEN
  204. REPEAT
  205. INC(blockNr);
  206. LogEnter(3); Log(3, WRQId); Log(3, " receiving block "); LogInt(3, blockNr);
  207. IF (retries > 1) THEN Log(3, " (retry "); LogInt(3, retries); Log(3, ")") END;
  208. LogExit(3);
  209. socket.Receive(buf, 0, LEN(buf), DataTimeout, ip, port, len, res);
  210. IF (res = Ok) THEN
  211. IF IP.AdrsEqual(ip, fip) & (fport = port) THEN
  212. IF (PacketType(buf) = DATA) THEN
  213. IF (Get2(buf, 2) = blockNr) THEN
  214. file.WriteBytes(r, buf, 4, len-4);
  215. file.Update();
  216. IF (r.res = 0) THEN
  217. SendAck(blockNr, res);
  218. Abort := res # Ok
  219. ELSE
  220. LogEnter(3); Log(3, WRQId); Log(3, errorMsg[3]); LogExit(3);
  221. SendError(3, "", res);
  222. Abort := TRUE
  223. END
  224. ELSE (* bad block number, client must send packet again *)
  225. INC(waitPacket); len := BlockSize;
  226. LogEnter(3); Log(3, WRQId); Log(3, "Bad block number ("); LogInt(3, waitPacket); Log(3, ")"); LogExit(3)
  227. END
  228. ELSE (* wrong packet type *)
  229. LogEnter(3); Log(3, WRQId); Log(3, errorMsg[4]); LogExit(3);
  230. SendError(4, "", res);
  231. Abort := TRUE
  232. END
  233. ELSE (* wrong client ip/port *)
  234. LogEnter(3); Log(3, WRQId); Log(3, errorMsg[5]); LogExit(3);
  235. SendError(5,"", res)
  236. END
  237. ELSIF (res = UDP.Timeout) THEN
  238. INC(waitPacket); len := BlockSize;
  239. LogEnter(3); Log(3, WRQId); Log(3, "Timeout ("); LogInt(3, waitPacket); Log(3, ")"); LogExit(3)
  240. ELSE (* unknown error (UDP/IP error) *)
  241. LogEnter(3); Log(3, WRQId); Log(3, errorMsg[0]); LogExit(3);
  242. SendError(0, "", res);
  243. Abort := TRUE
  244. END;
  245. UNTIL Abort OR (waitPacket > MaxWait) OR (len < BlockSize);
  246. LogEnter(2); Log(2, WRQId);
  247. IF (len < BlockSize) THEN
  248. file.Update();
  249. Log(2, "file successfully received")
  250. ELSE
  251. Log(2, "file transfer aborted");
  252. IF (waitPacket > MaxWait) THEN Log(2, " (timeout)") END
  253. END;
  254. LogExit(2)
  255. ELSE
  256. LogEnter(2); Log(2, WRQId); Log(2, "can't send initial ack"); LogExit(2);
  257. END;
  258. NEW(timer);
  259. timer.Sleep(AckTimeout+500);
  260. socket.Close;
  261. Die
  262. END TFTPWRQ;
  263. TFTPServer = OBJECT(TFTP)
  264. VAR
  265. ofs,len: LONGINT;
  266. ipstr, mode: ARRAY 16 OF CHAR;
  267. filename: Files.FileName;
  268. Stop, allowWrite: BOOLEAN;
  269. tftprrq: TFTPRRQ;
  270. tftpwrq: TFTPWRQ;
  271. PROCEDURE &Init*(port: LONGINT; VAR res: WORD);
  272. BEGIN NEW(socket, port, res); lport := port
  273. END Init;
  274. PROCEDURE WriteMode(allow: BOOLEAN);
  275. BEGIN allowWrite := allow
  276. END WriteMode;
  277. PROCEDURE Close;
  278. BEGIN { EXCLUSIVE }
  279. socket.Close; Stop := TRUE
  280. END Close;
  281. BEGIN { ACTIVE }
  282. IF (res = Ok) THEN
  283. LogEnter(1); Log(1, TFTPId); Log(1, "listening on port "); LogInt(1, lport); LogExit(1);
  284. REPEAT
  285. socket.Receive(buf, 0, LEN(buf), 1000, fip, fport, len, res);
  286. IF (res = Ok) THEN
  287. IP.AdrToStr(fip, ipstr);
  288. LogEnter(2);
  289. Log(2, TFTPId); Log(2, "connected to "); Log(2, ipstr); Log(2, " on port "); LogInt(2, fport);
  290. LogExit(2);
  291. CASE PacketType(buf) OF
  292. | RRQ:
  293. ofs := 2;
  294. ExtractString(buf, ofs, filename); ExtractString(buf, ofs, mode);
  295. LogEnter(2);
  296. Log(2, TFTPId); Log(2, "read request for '"); Log(2, filename); Log(2, "', mode '"); Log(2, mode); Log(2, "' ");
  297. LogExit(2);
  298. NEW(tftprrq, fip, fport, filename, res); tftprrq := NIL;
  299. IF (res = -1) THEN
  300. LogEnter(2); Log(2, TFTPId); Log(2, "read request: "); Log(2, errorMsg[1]); LogExit(2);
  301. SendError(1, "", res)
  302. ELSIF (res # Ok) THEN
  303. LogEnter(2); Log(2, TFTPId); Log(2, "read request: "); Log(2, ": error "); LogInt(2, LONGINT(res)); LogExit(2);
  304. SendError(0, "", res)
  305. ELSE
  306. LogEnter(2); Log(2, TFTPId); Log(2, "read request: "); Log(2, ": transfer started"); LogExit(2)
  307. END
  308. | WRQ:
  309. ofs := 2;
  310. ExtractString(buf, ofs, filename); ExtractString(buf, ofs, mode);
  311. LogEnter(2);
  312. Log(2, TFTPId); Log(2, "write request for '"); Log(2, filename); Log(2, "', mode '"); Log(2, mode); Log(2, "' ");
  313. LogExit(2);
  314. IF allowWrite THEN
  315. NEW(tftpwrq, fip, fport, filename, res); tftpwrq := NIL;
  316. IF (res = -1) THEN
  317. LogEnter(2); Log(2, TFTPId); Log(2, "write request: "); Log(2, errorMsg[6]); LogExit(2);
  318. SendError(6, "", res)
  319. ELSIF (res # Ok) THEN
  320. LogEnter(2); Log(2, TFTPId); Log(2, "write request: "); Log(2, ": error "); LogInt(2, LONGINT(res)); LogExit(2);
  321. SendError(0, "", res)
  322. ELSE
  323. LogEnter(2); Log(2, TFTPId); Log(2, "write request: "); Log(2, ": transfer started"); LogExit(2)
  324. END
  325. ELSE
  326. LogEnter(2); Log(2, TFTPId); Log(2, "write request: "); Log(2, errorMsg[2]); LogExit(2);
  327. SendError(2, "", res)
  328. END
  329. ELSE LogEnter(2); Log(2, TFTPId); Log(2, "Invalid request"); LogExit(2)
  330. END
  331. ELSIF (res = UDP.Timeout) THEN (* nothing *)
  332. ELSE
  333. Stop := TRUE;
  334. LogEnter(2); Log(2, TFTPId); Log(2, "socket error "); LogInt(2, LONGINT(res)); LogExit(2);
  335. END
  336. UNTIL Stop;
  337. END;
  338. Die
  339. END TFTPServer;
  340. VAR
  341. tftpserver: TFTPServer;
  342. TraceLevel: LONGINT;
  343. errorMsg: ARRAY 8 OF ErrorMsg;
  344. generator: Random.Generator;
  345. PROCEDURE Start*;
  346. VAR res: WORD;
  347. BEGIN
  348. IF (tftpserver = NIL) THEN
  349. KernelLog.Enter; KernelLog.String("Starting TFTP Server..."); KernelLog.Exit;
  350. NEW(tftpserver, TFTPPort, res);
  351. IF (res # UDP.Ok) THEN
  352. tftpserver := NIL;
  353. KernelLog.Enter; KernelLog.String("TFTP Server: UDP port not available"); KernelLog.Exit
  354. END
  355. ELSE
  356. KernelLog.Enter; KernelLog.String("TFTP Server: already running"); KernelLog.Exit
  357. END
  358. END Start;
  359. PROCEDURE Stop*;
  360. BEGIN
  361. IF (tftpserver # NIL) THEN
  362. tftpserver.Close; tftpserver.AwaitDeath; tftpserver := NIL;
  363. KernelLog.Enter; KernelLog.String("TFTP Server stopped"); KernelLog.Exit
  364. ELSE
  365. KernelLog.Enter; KernelLog.String("TFTP Server not running"); KernelLog.Exit
  366. END
  367. END Stop;
  368. PROCEDURE AllowWrite*;
  369. BEGIN
  370. IF (tftpserver # NIL) THEN
  371. tftpserver.WriteMode(TRUE);
  372. KernelLog.Enter; KernelLog.String("TFTP Server: writing allowed"); KernelLog.Exit
  373. ELSE
  374. KernelLog.Enter; KernelLog.String("TFTP Server: not running. use TFTPServer.Start"); KernelLog.Exit
  375. END
  376. END AllowWrite;
  377. PROCEDURE DenyWrite*;
  378. BEGIN
  379. IF (tftpserver # NIL) THEN
  380. tftpserver.WriteMode(FALSE);
  381. KernelLog.Enter; KernelLog.String("TFTP Server: writing denied"); KernelLog.Exit;
  382. ELSE
  383. KernelLog.Enter; KernelLog.String("TFTP Server: not running. use TFTPServer.Start"); KernelLog.Exit
  384. END
  385. END DenyWrite;
  386. PROCEDURE TraceLevel0*;
  387. BEGIN TraceLevel := 0
  388. END TraceLevel0;
  389. PROCEDURE TraceLevel1*;
  390. BEGIN TraceLevel := 1
  391. END TraceLevel1;
  392. PROCEDURE TraceLevel2*;
  393. BEGIN TraceLevel := 2
  394. END TraceLevel2;
  395. PROCEDURE TraceLevel3*;
  396. BEGIN TraceLevel := 3
  397. END TraceLevel3;
  398. BEGIN
  399. errorMsg[0] := "Undefined error.";
  400. errorMsg[1] := "File not found.";
  401. errorMsg[2] := "Access violation.";
  402. errorMsg[3] := "Disk full.";
  403. errorMsg[4] := "Illegal TFTP operation.";
  404. errorMsg[5] := "Unknown transfer ID.";
  405. errorMsg[6] := "File already exists.";
  406. errorMsg[7] := "No such user.";
  407. TraceLevel := 2;
  408. NEW(generator)
  409. END TFTPServer.
  410. System.Free TFTPServer ~
  411. TFTPServer.Start
  412. TFTPServer.Stop
  413. TFTPServer.AllowWrite
  414. TFTPServer.DenyWrite
  415. TFTPServer.TraceLevel0
  416. TFTPServer.TraceLevel1
  417. TFTPServer.TraceLevel2
  418. TFTPServer.TraceLevel3