/[H8]/trunk/docs/Microchip TCP_IP stack/TCPIP Stack/TFTPc.c
ViewVC logotype

Contents of /trunk/docs/Microchip TCP_IP stack/TCPIP Stack/TFTPc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20