/[H8]/trunk/docs/MCHPStack2.20/Source/TFTPc.c
ViewVC logotype

Contents of /trunk/docs/MCHPStack2.20/Source/TFTPc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations) (download)
Tue May 1 08:17:39 2007 UTC (17 years, 1 month ago) by hedin
File MIME type: text/plain
File size: 30897 byte(s)
Removed tcpip stack 4.02 and added tcpip stack 2.20.
1 /*********************************************************************
2 *
3 * TFTP Client module for Microchip TCP/IP Stack
4 *
5 *********************************************************************
6 * FileName: TFTPc.c
7 * Dependencies: TFTPc.h
8 * UDP.h
9 * Processor: PIC18
10 * Complier: MCC18 v1.00.50 or higher
11 * HITECH PICC-18 V8.10PL1 or higher
12 * Company: Microchip Technology, Inc.
13 *
14 * Software License Agreement
15 *
16 * The software supplied herewith by Microchip Technology Incorporated
17 * (the “Company”) for its PICmicro® Microcontroller is intended and
18 * supplied to you, the Company’s customer, for use solely and
19 * exclusively on Microchip PICmicro Microcontroller products. The
20 * software is owned by the Company and/or its supplier, and is
21 * protected under applicable copyright laws. All rights are reserved.
22 * Any use in violation of the foregoing restrictions may subject the
23 * user to criminal sanctions under applicable laws, as well as to
24 * civil liability for the breach of the terms and conditions of this
25 * license.
26 *
27 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
28 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
29 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
30 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
31 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
32 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
33 *
34 * Author Date Comment
35 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36 * Nilesh Rajbharti 8/5/03 Original (Rev 1.0)
37 ********************************************************************/
38 #if defined(WIN32)
39 #include <stdio.h>
40 #define TFTP_DEBUG
41 #endif
42
43 #include "tftpc.h"
44 #include "arptsk.h"
45 #include "tick.h"
46
47 #if !defined(STACK_USE_TFTP_CLIENT)
48 #error TFTP Client module is not enabled.
49 #error If you do not want TFTP Client module, remove this file from your
50 #error project to reduce your code size.
51 #error If you do want TFTP Client module, make sure that STACK_USE_TFTP_CLIENT
52 #error is defined in StackTsk.h file.
53 #endif
54
55
56 #define TFTP_CLIENT_PORT 65352L // Some unique port on this
57 // device.
58 #define TFTP_SERVER_PORT (69L)
59 #define TFTP_BLOCK_SIZE (0x200L) // 512 bytes
60 #define TFTP_BLOCK_SIZE_MSB (0x02)
61
62 typedef enum _TFTP_STATE
63 {
64 SM_TFTP_WAIT = 0,
65 SM_TFTP_READY,
66 SM_TFTP_WAIT_FOR_DATA,
67 SM_TFTP_WAIT_FOR_ACK,
68 SM_TFTP_DUPLICATE_ACK,
69 SM_TFTP_SEND_ACK,
70 SM_TFTP_SEND_LAST_ACK
71 } TFTP_STATE;
72
73 typedef enum _TFTP_OPCODE
74 {
75 TFTP_OPCODE_RRQ = 1, // Get
76 TFTP_OPCODE_WRQ, // Put
77 TFTP_OPCODE_DATA, // Actual data
78 TFTP_OPCODE_ACK, // Ack for Get/Put
79 TFTP_OPCODE_ERROR // Error
80 } TFTP_OPCODE;
81
82
83
84 UDP_SOCKET _tftpSocket; // TFTP Socket for TFTP server link
85 WORD _tftpError;
86
87 static union _MutExVar
88 {
89 struct
90 {
91 NODE_INFO _hostInfo;
92 } group1;
93
94 struct
95 {
96 WORD_VAL _tftpBlockNumber;
97 WORD_VAL _tftpDuplicateBlock;
98 WORD_VAL _tftpBlockLength;
99 } group2;
100 } MutExVar; // Mutually Exclusive variable groups to conserve RAM.
101
102
103 static TFTP_STATE _tftpState;
104 static BYTE _tftpRetries;
105 static TICK _tftpStartTick;
106 static union
107 {
108 struct
109 {
110 unsigned int bIsFlushed : 1;
111 unsigned int bIsAcked : 1;
112 unsigned int bIsClosed : 1;
113 unsigned int bIsClosing : 1;
114 unsigned int bIsReading : 1;
115 } bits;
116 BYTE Val;
117 } _tftpFlags;
118
119
120 // Private helper functions
121 static void _TFTPSendFileName(TFTP_OPCODE command, char *fileName);
122 static void _TFTPSendAck(WORD_VAL blockNumber);
123
124 // Blank out DEBUG statements if not enabled.
125 #if defined(TFTP_DEBUG)
126 #define DEBUG(a) a
127 #else
128 #define DEBUG(a)
129 #endif
130
131
132 /*********************************************************************
133 * Function: void TFTPOpen(IP_ADDR *host)
134 *
135 * PreCondition: UDP module is already initialized
136 * and at least one UDP socket is available.
137 *
138 * Input: host - IP address of remote TFTP server
139 *
140 * Output: None
141 *
142 * Side Effects: None
143 *
144 * Overview: Initiates ARP for given host and prepares
145 * TFTP module for next sequence of function calls.
146 *
147 * Note: Use TFTPIsOpened() to check if a connection was
148 * successfully opened or not.
149 *
150 ********************************************************************/
151 void TFTPOpen(IP_ADDR *host)
152 {
153 DEBUG(printf("Opening a connection..."));
154
155 // Remember this address locally.
156 MutExVar.group1._hostInfo.IPAddr.Val = host->Val;
157
158 // Initiate ARP resolution.
159 ARPResolve(&MutExVar.group1._hostInfo.IPAddr);
160
161 // Wait for ARP to get resolved.
162 _tftpState = SM_TFTP_WAIT;
163
164 // Mark this as start tick to detect timeout condition.
165 _tftpStartTick = TickGet();
166
167 // Forget about all previous attempts.
168 _tftpRetries = 1;
169
170 }
171
172
173
174 /*********************************************************************
175 * Function: TFTP_RESULT TFTPIsOpened(void)
176 *
177 * PreCondition: TFTPOpen() is already called.
178 *
179 * Input: None
180 *
181 * Output: TFTP_OK if previous call to TFTPOpen is complete
182 *
183 * TFTP_TIMEOUT if remote host did not respond to
184 * previous ARP request.
185 *
186 * TFTP_NOT_READY if remote has still not responded
187 * and timeout has not expired.
188 *
189 * Side Effects: None
190 *
191 * Overview: Waits for ARP reply and opens a UDP socket
192 * to perform further TFTP operations.
193 *
194 * Note: Once opened, application may keep TFTP socket
195 * open and future TFTP operations.
196 * If TFTPClose() is called to close the connection
197 * TFTPOpen() must be called again before performing
198 * any other TFTP operations.
199 ********************************************************************/
200 TFTP_RESULT TFTPIsOpened(void)
201 {
202 switch(_tftpState)
203 {
204 default:
205 DEBUG(printf("Resolving remote IP...\n"));
206
207 // Check to see if adddress is resolved.
208 if ( ARPIsResolved(&MutExVar.group1._hostInfo.IPAddr,
209 &MutExVar.group1._hostInfo.MACAddr) )
210 {
211 _tftpSocket = UDPOpen(TFTP_CLIENT_PORT,
212 &MutExVar.group1._hostInfo,
213 TFTP_SERVER_PORT);
214 _tftpState = SM_TFTP_READY;
215 }
216 else
217 break;
218
219 case SM_TFTP_READY:
220 // Wait for UDP to be ready. Immediately after this user will
221 // may TFTPGetFile or TFTPPutFile and we have to make sure that
222 // UDP is read to transmit. These functions do not check for
223 // UDP to get ready.
224 if ( UDPIsPutReady(_tftpSocket) )
225 return TFTP_OK;
226 }
227
228 // Make sure that we do not do this forever.
229 if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_ARP_TIMEOUT_VAL )
230 {
231 _tftpStartTick = TickGet();
232
233 // Forget about all previous attempts.
234 _tftpRetries = 1;
235
236 return TFTP_TIMEOUT;
237 }
238
239 return TFTP_NOT_READY;
240 }
241
242
243
244 /*********************************************************************
245 * Function: void TFTPOpenFile(char *fileName,
246 * TFTP_FILE_MODE mode)
247 *
248 * PreCondition: TFPTIsFileOpenReady() = TRUE
249 *
250 * Input: fileName - File name that is to be opened.
251 * mode - Mode of file access
252 * Must be
253 * TFTP_FILE_MODE_READ for read
254 * TFTP_FILE_MODE_WRITE for write
255 *
256 * Output: None
257 *
258 * Side Effects: None
259 *
260 * Overview: Prepares and sends TFTP file name and mode packet.
261 *
262 * Note: By default, this funciton uses "octet" or binary
263 * mode of file transfer.
264 * Use TFTPIsFileOpened() to check if file is
265 * ready to be read or written.
266 ********************************************************************/
267 void TFTPOpenFile(char *fileName, TFTP_FILE_MODE mode)
268 {
269 DEBUG(printf("Opening file...\n"));
270
271 // Set TFTP Server port. If this is the first call, remotePort
272 // must have been set by TFTPOpen(). But if caller does not do
273 // TFTPOpen for every transfer, we must reset remote port.
274 // Most TFTP servers accept connection TFTP port. but once
275 // connection is established, they use other temp. port,
276 UDPSocketInfo[_tftpSocket].remotePort = TFTP_SERVER_PORT;
277
278 // Tell remote server about our intention.
279 _TFTPSendFileName(mode, fileName);
280
281 // Clear all flags.
282 _tftpFlags.Val = 0;
283
284 // Remember start tick for this operation.
285 _tftpStartTick = TickGet();
286
287 // Depending on mode of operation, remote server will respond with
288 // specific block number.
289 if ( mode == TFTP_FILE_MODE_READ )
290 {
291 // Remember that we are reading a file.
292 _tftpFlags.bits.bIsReading = TRUE;
293
294
295 // For read operation, server would respond with data block of 1.
296 MutExVar.group2._tftpBlockNumber.Val = 1;
297
298 // Next packet would be the data packet.
299 _tftpState = SM_TFTP_WAIT_FOR_DATA;
300 }
301
302 else
303 {
304 // Remember that we are writing a file.
305 _tftpFlags.bits.bIsReading = FALSE;
306
307 // For write operation, server would respond with data block of 0.
308 MutExVar.group2._tftpBlockNumber.Val = 0;
309
310 // Next packet would be the ACK packet.
311 _tftpState = SM_TFTP_WAIT_FOR_ACK;
312 }
313
314
315 }
316
317
318
319
320 /*********************************************************************
321 * Function: TFTP_RESULT TFTPIsFileOpened(void)
322 *
323 * PreCondition: TFTPOpenFile() is called.
324 *
325 * Input: None
326 *
327 * Output: TFTP_OK if file is ready to be read or written
328 *
329 * TFTP_RETRY if previous attempt was timed out
330 * needs to be retried.
331 *
332 * TFTP_TIMEOUT if all attempts were exhausted.
333 *
334 * TFTP_NOT_ERROR if remote server responded with
335 * error
336 *
337 * TFTP_NOT_READY if file is not yet opened.
338 *
339 * Side Effects: None
340 *
341 * Overview: Waits for remote server response regarding
342 * previous attempt to open file.
343 * If no response is received within specified
344 * timeout, fnction returns with TFTP_RETRY
345 * and application logic must issue another
346 * TFTPFileOpen().
347 *
348 * Note: None
349 ********************************************************************/
350 TFTP_RESULT TFTPIsFileOpened(void)
351 {
352 if ( _tftpFlags.bits.bIsReading )
353 return TFTPIsGetReady();
354
355 else
356 return TFTPIsPutReady();
357 }
358
359
360
361
362 /*********************************************************************
363 * Function: TFTP_RESULT TFTPIsGetReady(void)
364 *
365 * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_READ
366 * and TFTPIsFileOpened() returned with TRUE.
367 *
368 * Input: None
369 *
370 * Output: TFTP_OK if it there is more data byte available
371 * to read
372 *
373 * TFTP_TIMEOUT if timeout occurred waiting for
374 * new data.
375 *
376 * TFTP_END_OF_FILE if end of file has reached.
377 *
378 * TFTP_ERROR if remote server returned ERROR.
379 * Actual error code may be read by calling
380 * TFTPGetError()
381 *
382 * TFTP_NOT_READY if still waiting for new data.
383 *
384 * Side Effects: None
385 *
386 * Overview: Waits for data block. If data block does not
387 * arrive within specified timeout, it automatically
388 * sends out ack for previous block to remind
389 * server to send next data block.
390 * If all attempts are exhausted, it returns with
391 * TFTP_TIMEOUT.
392 *
393 * Note: By default, this funciton uses "octet" or binary
394 * mode of file transfer.
395 ********************************************************************/
396 TFTP_RESULT TFTPIsGetReady(void)
397 {
398 WORD_VAL opCode;
399 WORD_VAL blockNumber;
400 BOOL bTimeOut;
401
402
403 // Check to see if timeout has occurred.
404 bTimeOut = FALSE;
405 if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_GET_TIMEOUT_VAL )
406 {
407 bTimeOut = TRUE;
408 _tftpStartTick = TickGet();
409 }
410
411
412 switch(_tftpState)
413 {
414 case SM_TFTP_WAIT_FOR_DATA:
415 // If timeout occurs in this state, it may be because, we have not
416 // even received very first data block or some in between block.
417 if ( bTimeOut == TRUE )
418 {
419 bTimeOut = FALSE;
420
421 if ( _tftpRetries++ > (TFTP_MAX_RETRIES-1) )
422 {
423 DEBUG(printf("TFTPIsGetReady(): Timeout.\n"));
424
425 // Forget about all previous attempts.
426 _tftpRetries = 1;
427
428 return TFTP_TIMEOUT;
429 }
430
431 // If we have not even received first block, ask application
432 // retry.
433 if ( MutExVar.group2._tftpBlockNumber.Val == 1 )
434 {
435 DEBUG(printf("TFTPIsGetReady(): TFTPOpen Retry.\n"));
436 return TFTP_RETRY;
437 }
438 else
439 {
440 DEBUG(printf("TFTPIsGetReady(): ACK Retry #%d...,\n", _tftpRetries));
441
442 // Block number was already incremented in last ACK attempt,
443 // so decrement it.
444 MutExVar.group2._tftpBlockNumber.Val--;
445
446 // Do it.
447 _tftpState = SM_TFTP_SEND_ACK;
448 break;
449 }
450 }
451
452 // For Read operation, server will respond with data block.
453 if ( !UDPIsGetReady(_tftpSocket) )
454 break;
455
456 // Get opCode
457 UDPGet(&opCode.byte.MSB);
458 UDPGet(&opCode.byte.LSB);
459
460 // Get block number.
461 UDPGet(&blockNumber.byte.MSB);
462 UDPGet(&blockNumber.byte.LSB);
463
464 // In order to read file, this must be data with block number of 0.
465 if ( opCode.Val == TFTP_OPCODE_DATA )
466 {
467 // Make sure that this is not a duplicate block.
468 if ( MutExVar.group2._tftpBlockNumber.Val == blockNumber.Val )
469 {
470 // Mark that we have not acked this block.
471 _tftpFlags.bits.bIsAcked = FALSE;
472
473 // Since we have a packet, forget about previous retry count.
474 _tftpRetries = 1;
475
476 _tftpState = SM_TFTP_READY;
477 return TFTP_OK;
478 }
479
480 // If received block has already been received, simply ack it
481 // so that Server can "get over" it and send next block.
482 else if ( MutExVar.group2._tftpBlockNumber.Val > blockNumber.Val )
483 {
484 DEBUG(printf("TFTPIsGetReady(): "\
485 "Duplicate block %d received - droping it...\n", \
486 blockNumber.Val));
487 MutExVar.group2._tftpDuplicateBlock.Val = blockNumber.Val;
488 _tftpState = SM_TFTP_DUPLICATE_ACK;
489 }
490 #if defined(TFTP_DEBUG)
491 else
492 {
493 DEBUG(printf("TFTPIsGetReady(): "\
494 "Unexpected block %d received - droping it...\n", \
495 blockNumber.Val));
496 }
497 #endif
498 }
499 // Discard all unexpected and error blocks.
500 UDPDiscard();
501
502 // If this was an error, remember error code for later delivery.
503 if ( opCode.Val == TFTP_OPCODE_ERROR )
504 {
505 _tftpError = blockNumber.Val;
506 return TFTP_ERROR;
507 }
508
509 break;
510
511 case SM_TFTP_DUPLICATE_ACK:
512 if ( UDPIsPutReady(_tftpSocket) )
513 {
514 _TFTPSendAck(MutExVar.group2._tftpDuplicateBlock);
515 _tftpState = SM_TFTP_WAIT_FOR_DATA;
516 }
517 break;
518
519 case SM_TFTP_READY:
520 if ( UDPIsGetReady(_tftpSocket) )
521 {
522 _tftpStartTick = TickGet();
523 return TFTP_OK;
524 }
525
526 // End of file is reached when data block is less than 512 bytes long.
527 // To reduce code, only MSB compared against 0x02 (of 0x200 = 512) to
528 // determine if block is less than 512 bytes long or not.
529 else if ( MutExVar.group2._tftpBlockLength.Val == 0 ||
530 MutExVar.group2._tftpBlockLength.byte.MSB < TFTP_BLOCK_SIZE_MSB )
531 _tftpState = SM_TFTP_SEND_LAST_ACK;
532 else
533 break;
534
535
536 case SM_TFTP_SEND_LAST_ACK:
537 case SM_TFTP_SEND_ACK:
538 if ( UDPIsPutReady(_tftpSocket) )
539 {
540 _TFTPSendAck(MutExVar.group2._tftpBlockNumber);
541
542 // This is the next block we are expecting.
543 MutExVar.group2._tftpBlockNumber.Val++;
544
545 // Remember that we have already acked current block.
546 _tftpFlags.bits.bIsAcked = TRUE;
547
548 if ( _tftpState == SM_TFTP_SEND_LAST_ACK )
549 return TFTP_END_OF_FILE;
550
551 _tftpState = SM_TFTP_WAIT_FOR_DATA;
552 }
553 break;
554 }
555
556
557
558 return TFTP_NOT_READY;
559 }
560
561
562
563 /*********************************************************************
564 * Function: BYTE TFTPGet(void)
565 *
566 * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_READ
567 * and TFTPIsGetReady() = TRUE
568 *
569 * Input: None
570 *
571 * Output: data byte as received from remote server.
572 *
573 * Side Effects: None
574 *
575 * Overview: Fetches next data byte from TFTP socket.
576 * If end of data block is reached, it issues
577 * ack to server so that next data block can be
578 * received.
579 *
580 * Note: Use this function to read file from server.
581 ********************************************************************/
582 BYTE TFTPGet(void)
583 {
584 BYTE v;
585
586 // Read byte from UDP
587 UDPGet(&v);
588
589 // Update block length
590 MutExVar.group2._tftpBlockLength.Val++;
591
592 // Check to see if entire data block is fetched.
593 // To reduce code, MSB is compared for 0x02 (of 0x200 = 512).
594 if ( MutExVar.group2._tftpBlockLength.byte.MSB == TFTP_BLOCK_SIZE_MSB )
595 {
596 // Entire block was fetched. Discard everything else.
597 UDPDiscard();
598
599 // Remember that we have flushed this block.
600 _tftpFlags.bits.bIsFlushed = TRUE;
601
602 // Reset block length.
603 MutExVar.group2._tftpBlockLength.Val = 0;
604
605 // Must send ACK to receive next block.
606 _tftpState = SM_TFTP_SEND_ACK;
607 }
608
609 return v;
610 }
611
612
613
614
615 /*********************************************************************
616 * Function: void TFTPCloseFile(void)
617 *
618 * PreCondition: TFTPOpenFile() was called and TFTPIsFileOpened()
619 * had returned with TFTP_OK.
620 *
621 * Input: None
622 *
623 * Output: None
624 *
625 * Side Effects: None
626 *
627 * Overview: If file is opened in read mode, it makes sure
628 * that last ACK is sent to server
629 * If file is opened in write mode, it makes sure
630 * that last block is sent out to server and
631 * waits for server to respond with ACK.
632 *
633 * Note: TFTPIsFileClosed() must be called to confirm
634 * if file was really closed.
635 ********************************************************************/
636 void TFTPCloseFile(void)
637 {
638 // If a file was opened for read, we can close it immediately.
639 if ( _tftpFlags.bits.bIsReading )
640 {
641 // If this was premature close, make sure that we discard
642 // current block.
643 if ( !_tftpFlags.bits.bIsFlushed )
644 {
645 _tftpFlags.bits.bIsFlushed = TRUE;
646 UDPDiscard();
647 }
648
649 if ( _tftpFlags.bits.bIsAcked )
650 {
651 _tftpFlags.bits.bIsClosed = TRUE;
652 _tftpFlags.bits.bIsClosing = FALSE;
653 return;
654 }
655
656 else
657 {
658 _tftpState = SM_TFTP_SEND_LAST_ACK;
659 _tftpFlags.bits.bIsClosing = TRUE;
660 }
661 return;
662 }
663
664 // For write mode, if we have not flushed last block, do it now.
665 if ( !_tftpFlags.bits.bIsFlushed )
666 {
667 _tftpFlags.bits.bIsFlushed = TRUE;
668 UDPFlush();
669 }
670
671 // For write mode, if our last block was ack'ed by remote server,
672 // file is said to be closed.
673 if ( _tftpFlags.bits.bIsAcked )
674 {
675 _tftpFlags.bits.bIsClosed = TRUE;
676 _tftpFlags.bits.bIsClosing = FALSE;
677 return;
678 }
679
680 _tftpState = SM_TFTP_WAIT_FOR_ACK;
681 _tftpFlags.bits.bIsClosing = TRUE;
682
683 }
684
685
686
687 /*********************************************************************
688 * Function: TFTP_RESULT TFPTIsFileClosed(void)
689 *
690 * PreCondition: TFTPCloseFile() is already called.
691 *
692 * Input: None
693 *
694 * Output: TFTP_OK if file was successfully closdd
695 *
696 * TFTP_RETRY if file mode was Write and remote
697 * server did not receive last packet.
698 * Application must retry with last block.
699 *
700 * TFTP_TIMEOUT if all attempts were exhausted
701 * in closing file.
702 *
703 * TFTP_ERROR if remote server sent an error
704 * in response to last block.
705 * Actual error code may be read by calling
706 * TFTPGetError()
707 *
708 * TFTP_NOT_READY if file is not closed yet.
709 *
710 * Side Effects: None
711 *
712 * Overview: If file mode is Read, it simply makes that
713 * last block is acknowledged.
714 * If file mode is Write, it waits for server ack.
715 * If no ack was received within specified timeout
716 * instructs appliaction to resend last block.
717 * It keeps track of retries and declares timeout
718 * all attempts were exhausted.
719 *
720 * Note: None
721 ********************************************************************/
722 TFTP_RESULT TFTPIsFileClosed(void)
723 {
724 if ( _tftpFlags.bits.bIsReading )
725 return TFTPIsGetReady();
726
727 else
728 return TFTPIsPutReady();
729 }
730
731
732
733
734 /*********************************************************************
735 * Function: TFTP_RESULT TFTPIsPutReady(void)
736 *
737 * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_WRITE
738 * and TFTPIsFileOpened() returned with TRUE.
739 *
740 * Input: None
741 *
742 * Output: TFTP_OK if it is okay to write more data byte.
743 *
744 * TFTP_TIMEOUT if timeout occurred waiting for
745 * ack from server
746 *
747 * TFTP_RETRY if all server did not send ack
748 * on time and application needs to resend
749 * last block.
750 *
751 * TFTP_ERROR if remote server returned ERROR.
752 * Actual error code may be read by calling
753 * TFTPGetError()
754 *
755 * TFTP_NOT_READY if still waiting...
756 *
757 * Side Effects: None
758 *
759 * Overview: Waits for ack from server. If ack does not
760 * arrive within specified timeout, it it instructs
761 * application to retry last block by returning
762 * TFTP_RETRY.
763 *
764 * If all attempts are exhausted, it returns with
765 * TFTP_TIMEOUT.
766 *
767 * Note: None
768 ********************************************************************/
769 TFTP_RESULT TFTPIsPutReady(void)
770 {
771 WORD_VAL opCode;
772 WORD_VAL blockNumber;
773 BOOL bTimeOut;
774
775 // Check to see if timeout has occurred.
776 bTimeOut = FALSE;
777 if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_GET_TIMEOUT_VAL )
778 {
779 bTimeOut = TRUE;
780 _tftpStartTick = TickGet();
781 }
782
783 switch(_tftpState)
784 {
785 case SM_TFTP_WAIT_FOR_ACK:
786 // When timeout occurs in this state, application must retry.
787 if ( bTimeOut )
788 {
789 if ( _tftpRetries++ > (TFTP_MAX_RETRIES-1) )
790 {
791 DEBUG(printf("TFTPIsPutReady(): Timeout.\n"));
792
793 // Forget about all previous attempts.
794 _tftpRetries = 1;
795
796 return TFTP_TIMEOUT;
797 }
798
799 else
800 {
801 DEBUG(printf("TFTPIsPutReady(): Retry.\n"));
802 return TFTP_RETRY;
803 }
804 }
805
806 // Must wait for ACK from server before we transmit next block.
807 if ( !UDPIsGetReady(_tftpSocket) )
808 break;
809
810 // Get opCode.
811 UDPGet(&opCode.byte.MSB);
812 UDPGet(&opCode.byte.LSB);
813
814 // Get block number.
815 UDPGet(&blockNumber.byte.MSB);
816 UDPGet(&blockNumber.byte.LSB);
817
818 // Discard everything else.
819 UDPDiscard();
820
821 // This must be ACK or else there is a problem.
822 if ( opCode.Val == TFTP_OPCODE_ACK )
823 {
824 // Also the block number must match with what we are expecting.
825 if ( MutExVar.group2._tftpBlockNumber.Val == blockNumber.Val )
826 {
827 // Mark that block we sent previously has been ack'ed.
828 _tftpFlags.bits.bIsAcked = TRUE;
829
830 // Since we have ack, forget about previous retry count.
831 _tftpRetries = 1;
832
833 // If this file is being closed, this must be last ack.
834 // Declare it as closed.
835 if ( _tftpFlags.bits.bIsClosing )
836 {
837 _tftpFlags.bits.bIsClosed = TRUE;
838 return TFTP_OK;
839 }
840
841 // Or else, wait for put to become ready so that caller
842 // can transfer more data blocks.
843 _tftpState = SM_TFTP_WAIT;
844 }
845
846 else
847 {
848 DEBUG(printf("TFTPIsPutReady(): "\
849 "Unexpected block %d received - droping it...\n", \
850 blockNumber.Val));
851 return TFTP_NOT_READY;
852 }
853 }
854
855 else if ( opCode.Val == TFTP_OPCODE_ERROR )
856 {
857 // For error opCode, remember error code so that application
858 // can read it later.
859 _tftpError = blockNumber.Val;
860
861 // Declare error.
862 return TFTP_ERROR;
863 }
864 else
865 break;
866
867
868 case SM_TFTP_WAIT:
869 // Wait for UDP is to be ready to transmit.
870 if ( UDPIsPutReady(_tftpSocket) )
871 {
872 // Put next block of data.
873 MutExVar.group2._tftpBlockNumber.Val++;
874 UDPPut(0);
875 UDPPut(TFTP_OPCODE_DATA);
876
877 UDPPut(MutExVar.group2._tftpBlockNumber.byte.MSB);
878 UDPPut(MutExVar.group2._tftpBlockNumber.byte.LSB);
879
880 // Remember that this block is not yet flushed.
881 _tftpFlags.bits.bIsFlushed = FALSE;
882
883 // Remember that this block is not acknowledged.
884 _tftpFlags.bits.bIsAcked = FALSE;
885
886 // Now, TFTP module is ready to put more data.
887 _tftpState = SM_TFTP_READY;
888
889 return TFTP_OK;
890 }
891 break;
892
893 case SM_TFTP_READY:
894 // TFTP module is said to be ready only when underlying UDP
895 // is ready to transmit.
896 if ( UDPIsPutReady(_tftpSocket) )
897 return TFTP_OK;
898 }
899
900 return TFTP_NOT_READY;
901 }
902
903
904
905 /*********************************************************************
906 * Function: void TFTPPut(BYTE c)
907 *
908 * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_WRITE
909 * and TFTPIsPutReady() = TRUE
910 *
911 * Input: c - Data byte that is to be written
912 *
913 * Output: None
914 *
915 * Side Effects: None
916 *
917 * Overview: Puts given data byte into TFTP socket.
918 * If end of data block is reached, it
919 * transmits entire block.
920 *
921 * Note: Use this function to write file to server.
922 ********************************************************************/
923 void TFTPPut(BYTE c)
924 {
925 // Put given byte directly to UDP
926 UDPPut(c);
927
928 // One more byte in data block.
929 ++MutExVar.group2._tftpBlockLength.Val;
930
931 // Check to see if data block is full.
932 if ( MutExVar.group2._tftpBlockLength.byte.MSB == TFTP_BLOCK_SIZE_MSB )
933 {
934 // If it is, then transmit this block.
935 UDPFlush();
936
937 // Remember that current block is already flushed.
938 _tftpFlags.bits.bIsFlushed = TRUE;
939
940 // Prepare for next block.
941 MutExVar.group2._tftpBlockLength.Val = 0;
942
943 // Need to wait for ACK from server before putting
944 // next block of data.
945 _tftpState = SM_TFTP_WAIT_FOR_ACK;
946 }
947 }
948
949
950
951
952 static void _TFTPSendFileName(TFTP_OPCODE opcode, char *fileName)
953 {
954 BYTE c;
955
956 // Write opCode
957 UDPPut(0);
958 UDPPut(opcode);
959
960 // write file name, including NULL.
961 do
962 {
963 c = *fileName++;
964 UDPPut(c);
965 } while ( c != '\0' );
966
967 // Write mode - always use octet or binay mode to transmit files.
968 UDPPut('o');
969 UDPPut('c');
970 UDPPut('t');
971 UDPPut('e');
972 UDPPut('t');
973 UDPPut(0);
974
975 // Transmit it.
976 UDPFlush();
977
978 // Reset data block length.
979 MutExVar.group2._tftpBlockLength.Val = 0;
980
981 }
982
983 static void _TFTPSendAck(WORD_VAL blockNumber)
984 {
985 // Write opCode.
986 UDPPut(0);
987 UDPPut(TFTP_OPCODE_ACK);
988
989 // Write block number for this ack.
990 UDPPut(blockNumber.byte.MSB);
991 UDPPut(blockNumber.byte.LSB);
992
993 // Transmit it.
994 UDPFlush();
995 }

  ViewVC Help
Powered by ViewVC 1.1.20