2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2004 Net Integration Technologies, Inc.
5 #include "wvtftpbase.h"
7 #include "wvtimeutils.h"
10 PktTime::PktTime(int _pktclump
)
13 times
= new struct timeval
[pktclump
];
22 void PktTime::set(int pktnum
, struct timeval
&tv
)
24 assert(pktnum
>= idx
);
25 if ((pktnum
- idx
) >= pktclump
)
27 int d
= pktnum
- pktclump
- idx
+ 1;
29 if (d
< pktclump
&& d
> 0)
31 memmove(times
, times
+ d
, (pktclump
- d
) * sizeof(struct
33 memset(times
+ pktclump
- d
, 0, d
* sizeof(struct timeval
));
35 else if (d
>= pktclump
)
36 memset(times
, 0, pktclump
* sizeof(struct timeval
));
38 times
[pktnum
- idx
].tv_sec
= tv
.tv_sec
;
39 times
[pktnum
- idx
].tv_usec
= tv
.tv_usec
;
42 struct timeval
*PktTime::get(int pktnum
)
44 if (pktnum
< idx
|| pktnum
> (idx
+ pktclump
))
46 return ×
[pktnum
- idx
];
49 WvTFTPBase::WvTFTPBase(int _tftp_tick
, int port
)
50 : WvUDPStream(port
, WvIPPortAddr()), conns(5), log("WvTFTP", WvLog::Debug
),
55 WvTFTPBase::~WvTFTPBase()
59 void WvTFTPBase::dump_pkt()
61 //log(WvLog::Debug5, "Packet:\n");
62 //log(WvLog::Debug5, hexdump_buffer(packet, packetsize));
65 void WvTFTPBase::handle_packet()
67 log(WvLog::Debug4
, "Handling packet from %s\n", remaddr
);
69 TFTPConn
*c
= conns
[remaddr
];
70 TFTPOpcode opcode
= (TFTPOpcode
)(packet
[0] * 256 + packet
[1]);
74 log(WvLog::Warning
, "Received error packet; aborting.\n");
79 if (c
->direction
== tftpread
)
81 // Packet should be an ack.
84 log(WvLog::Warning
, "Expected ACK (read); aborting.\n");
91 int small_blocknum
= (unsigned char)(packet
[2]) * 256 +
92 (unsigned char)(packet
[3]);
93 int mult
= c
->unack
/ 65536;
94 int blocknum
= mult
* 65536 + small_blocknum
;
95 if (blocknum
> c
->unack
+ 32000)
96 blocknum
= (mult
- 1) * 65536 + small_blocknum
;
98 "handle: got small_blocknum %s; unack is %s; lastsent is %s; "
100 small_blocknum
, c
->unack
, c
->lastsent
, blocknum
);
102 if (blocknum
== 0 && c
->send_oack
)
104 // treat the first block specially if we need to send an option
106 c
->send_oack
= false;
107 log(WvLog::Debug5
, "last sent: %s unack: %s pktclump: %s\n",
108 c
->lastsent
, c
->unack
, c
->pktclump
);
109 int pktsremain
= c
->lastsent
- c
->unack
;
110 while (pktsremain
< c
->pktclump
- 1)
112 log(WvLog::Debug5
, "result is %s\n", pktsremain
);
113 log(WvLog::Debug5
, "send\n");
117 pktsremain
= c
->lastsent
- c
->unack
;
122 else if (blocknum
!= (c
->unack
- 1)) // ignore duplicate ACK
124 // Add rtt to cumulative sum.
125 if (blocknum
== c
->unack
&& blocknum
> c
->timed_out_ignore
)
127 struct timeval tv
= wvtime();
129 time_t rtt
= msecdiff(tv
, *(c
->pkttimes
->get(blocknum
)));
130 log(WvLog::Debug4
, "rtt is %s.\n", rtt
);
136 if (blocknum
== c
->unack
&& blocknum
== c
->lastsent
139 // transfer completed if we haven't sent any packets last
140 // time we acked, and this is the right ack.
141 log(WvLog::Info
, "File transferred successfully.\n");
142 log(WvLog::Info
, "Average rtt was %s ms.\n", c
->rtt
/
151 else if (blocknum
== c
->unack
)
153 // send the next packet if the first unacked packet is the
155 c
->unack
= blocknum
+ 1;
157 while ((c
->lastsent
- c
->unack
) < c
->pktclump
- 1)
167 // 'c' might be invalid here if it was deleted!
171 // Packet should be data.
174 log(WvLog::Warning
, "Badly formed packet (write); aborting.\n");
181 int small_blocknum
= (unsigned char)(packet
[2]) * 256 +
182 (unsigned char)(packet
[3]);
183 int mult
= c
->lastsent
/ 65536;
184 int blocknum
= mult
* 65536 + small_blocknum
;
185 if (blocknum
< c
->lastsent
- 32000)
186 blocknum
= (mult
+ 1) * 65536 + small_blocknum
;
188 if (blocknum
== c
->lastsent
+ 1)
190 unsigned int data_packetsize
= packetsize
;
191 fwrite(&packet
[4], sizeof(char), data_packetsize
-4, c
->tftpfile
);
193 // Add rtt to cumulative sum.
194 if (blocknum
> c
->timed_out_ignore
)
196 struct timeval tv
= wvtime();
197 time_t rtt
= msecdiff(tv
, *(c
->pkttimes
->get(blocknum
- 1)));
198 log("rtt is %s.\n", rtt
);
205 if (data_packetsize
< c
->blksize
+ 4)
207 log(WvLog::Info
, "File transferred successfully.\n");
208 log(WvLog::Info
, "Average rtt was %s ms.\n", c
->rtt
/
217 // Send out the next packet, unless resend is true, in which case
218 // send out packets unack through lastsent.
219 void WvTFTPBase::send_data(TFTPConn
*c
, bool resend
)
221 // log("Sending data.\n");
222 int firstpkt
, lastpkt
;
227 lastpkt
= c
->lastsent
;
228 fseek(c
->tftpfile
, (firstpkt
- 1) * c
->blksize
, SEEK_SET
);
233 firstpkt
= c
->lastsent
;
234 lastpkt
= c
->lastsent
;
237 log(WvLog::Debug5
, "send_data: sending packets %s->%s\n",
240 for (int pktcount
= firstpkt
; pktcount
<= lastpkt
; pktcount
++)
249 packet
[2] = (pktcount
% 65536) / 256;
250 packet
[3] = (pktcount
% 65536) % 256;
252 datalen
= fread(&packet
[4], sizeof(char), c
->blksize
, c
->tftpfile
);
253 log(WvLog::Debug5
, "send_data: read %s bytes from file.\n", datalen
);
254 if (datalen
< c
->blksize
)
256 packetsize
+= datalen
;
257 // log(WvLog::Debug5, "Sending ");
259 setdest(c
->remote
); // often redundant (after reading), but safer
260 write(packet
, packetsize
);
262 struct timeval tv
= wvtime();
263 c
->pkttimes
->set(pktcount
, tv
);
267 // Send an acknowledgement.
268 void WvTFTPBase::send_ack(TFTPConn
*c
, bool resend
)
276 packet
[2] = (c
->lastsent
% 65536) / 256;
277 packet
[3] = (c
->lastsent
% 65536) % 256;
278 // log(WvLog::Debug5, "Sending ");
280 write(packet
, packetsize
);
282 struct timeval tv
= wvtime();
283 log(WvLog::Debug4
, "Setting %s\n", c
->lastsent
);
284 c
->pkttimes
->set(c
->lastsent
, tv
);
287 void WvTFTPBase::send_err(char errcode
, WvString errmsg
)
300 case 1: errmsg
= "File not found.";
302 case 2: errmsg
= "Access violation.";
304 case 3: errmsg
= "Disk full or allocation exceeded.";
306 case 4: errmsg
= "Illegal TFTP operation.";
308 case 5: errmsg
= "Unknown transfer ID.";
310 case 6: errmsg
= "File already exists.";
312 case 7: errmsg
= "No such user.";
315 strcpy(&packet
[4],errmsg
.edit());
316 packetsize
+= errmsg
.len() + 1;
317 // log(WvLog::Debug5, "Sending Error ");
319 write(packet
, packetsize
);