]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/clients/FtpClient.cc
2 * DEBUG: section 09 File Transfer Protocol (FTP)
7 #include "acl/FilledChecklist.h"
8 #include "client_side.h"
9 #include "clients/FtpClient.h"
10 #include "comm/ConnOpener.h"
11 #include "comm/Read.h"
12 #include "comm/TcpAcceptor.h"
13 #include "comm/Write.h"
14 #include "errorpage.h"
16 #include "ftp/Parsing.h"
19 #include "SquidConfig.h"
20 #include "SquidString.h"
21 #include "StatCounters.h"
30 const char *const crlf
= "\r\n";
33 escapeIAC(const char *buf
)
37 unsigned const char *p
;
40 for (p
= (unsigned const char *)buf
, n
= 1; *p
; ++n
, ++p
)
44 ret
= (char *)xmalloc(n
);
46 for (p
= (unsigned const char *)buf
, r
=(unsigned char *)ret
; *p
; ++p
) {
58 assert((r
- (unsigned char *)ret
) == n
);
64 /// configures the channel with a descriptor and registers a close handler
66 Ftp::Channel::opened(const Comm::ConnectionPointer
&newConn
,
67 const AsyncCall::Pointer
&aCloser
)
69 assert(!Comm::IsConnOpen(conn
));
70 assert(closer
== NULL
);
72 assert(Comm::IsConnOpen(newConn
));
73 assert(aCloser
!= NULL
);
77 comm_add_close_handler(conn
->fd
, closer
);
80 /// planned close: removes the close handler and calls comm_close
84 // channels with active listeners will be closed when the listener handler dies.
85 if (Comm::IsConnOpen(conn
)) {
86 comm_remove_close_handler(conn
->fd
, closer
);
87 conn
->close(); // we do not expect to be called back
93 Ftp::Channel::forget()
95 if (Comm::IsConnOpen(conn
)) {
96 commUnsetConnTimeout(conn
);
97 comm_remove_close_handler(conn
->fd
, closer
);
103 Ftp::Channel::clear()
109 /* Ftp::CtrlChannel */
111 Ftp::CtrlChannel::CtrlChannel():
120 buf
= static_cast<char*>(memAllocBuf(4096, &size
));
123 Ftp::CtrlChannel::~CtrlChannel()
125 memFreeBuf(size
, buf
);
127 wordlistDestroy(&message
);
128 safe_free(last_command
);
129 safe_free(last_reply
);
132 /* Ftp::DataChannel */
134 Ftp::DataChannel::DataChannel():
142 Ftp::DataChannel::~DataChannel()
148 Ftp::DataChannel::addr(const Ip::Address
&import
)
150 static char addrBuf
[MAX_IPSTRLEN
];
151 import
.toStr(addrBuf
, sizeof(addrBuf
));
153 host
= xstrdup(addrBuf
);
154 port
= import
.port();
159 Ftp::Client::Client(FwdState
*fwdState
):
160 AsyncJob("Ftp::Client"),
161 ::ServerStateData(fwdState
),
167 shortenReadTimeout(false)
169 ++statCounter
.server
.all
.requests
;
170 ++statCounter
.server
.ftp
.requests
;
172 ctrl
.last_command
= xstrdup("Connect to server");
174 typedef CommCbMemFunT
<Client
, CommCloseCbParams
> Dialer
;
175 const AsyncCall::Pointer closer
= JobCallback(9, 5, Dialer
, this,
176 Ftp::Client::ctrlClosed
);
177 ctrl
.opened(fwdState
->serverConnection(), closer
);
180 Ftp::Client::~Client()
182 if (data
.opener
!= NULL
) {
183 data
.opener
->cancel("Ftp::Client destructed");
188 safe_free(old_request
);
189 safe_free(old_reply
);
190 fwd
= NULL
; // refcounted
196 scheduleReadControlReply(0);
200 Ftp::Client::initReadBuf()
202 if (data
.readBuf
== NULL
) {
203 data
.readBuf
= new MemBuf
;
204 data
.readBuf
->init(4096, SQUID_TCP_SO_RCVBUF
);
209 * Close the FTP server connection(s). Used by serverComplete().
212 Ftp::Client::closeServer()
214 if (Comm::IsConnOpen(ctrl
.conn
)) {
215 debugs(9, 3, "closing FTP server FD " << ctrl
.conn
->fd
<< ", this " << this);
216 fwd
->unregister(ctrl
.conn
);
220 if (Comm::IsConnOpen(data
.conn
)) {
221 debugs(9, 3, "closing FTP data FD " << data
.conn
->fd
<< ", this " << this);
225 debugs(9, 3, "FTP ctrl and data connections closed. this " << this);
229 * Did we close all FTP server connection(s)?
231 \retval true Both server control and data channels are closed. And not waiting for a new data connection to open.
232 \retval false Either control channel or data is still active.
235 Ftp::Client::doneWithServer() const
237 return !Comm::IsConnOpen(ctrl
.conn
) && !Comm::IsConnOpen(data
.conn
);
241 Ftp::Client::failed(err_type error
, int xerrno
)
243 debugs(9, 3, "entry-null=" << (entry
?entry
->isEmpty():0) << ", entry=" << entry
);
245 const char *command
, *reply
;
246 const Http::StatusCode httpStatus
= failedHttpStatus(error
);
247 ErrorState
*const ftperr
= new ErrorState(error
, httpStatus
, fwd
->request
);
248 ftperr
->xerrno
= xerrno
;
250 ftperr
->ftp
.server_msg
= ctrl
.message
;
254 command
= old_request
;
256 command
= ctrl
.last_command
;
258 if (command
&& strncmp(command
, "PASS", 4) == 0)
259 command
= "PASS <yourpassword>";
264 reply
= ctrl
.last_reply
;
267 ftperr
->ftp
.request
= xstrdup(command
);
270 ftperr
->ftp
.reply
= xstrdup(reply
);
272 fwd
->request
->detailError(error
, xerrno
);
275 closeServer(); // we failed, so no serverComplete()
279 Ftp::Client::failedHttpStatus(err_type
&error
)
281 if (error
== ERR_NONE
)
282 error
= ERR_FTP_FAILURE
;
283 return error
== ERR_READ_TIMEOUT
? Http::scGatewayTimeout
:
289 * Looks like there are no longer anymore callers that set
290 * buffered_ok=1. Perhaps it can be removed at some point.
293 Ftp::Client::scheduleReadControlReply(int buffered_ok
)
295 debugs(9, 3, ctrl
.conn
);
297 if (buffered_ok
&& ctrl
.offset
> 0) {
298 /* We've already read some reply data */
299 handleControlReply();
302 * Cancel the timeout on the Data socket (if any) and
303 * establish one on the control socket.
305 if (Comm::IsConnOpen(data
.conn
)) {
306 commUnsetConnTimeout(data
.conn
);
309 const time_t tout
= shortenReadTimeout
?
310 min(Config
.Timeout
.connect
, Config
.Timeout
.read
):
312 shortenReadTimeout
= false; // we only need to do this once, after PASV
314 typedef CommCbMemFunT
<Client
, CommTimeoutCbParams
> TimeoutDialer
;
315 AsyncCall::Pointer timeoutCall
= JobCallback(9, 5, TimeoutDialer
, this, Ftp::Client::timeout
);
316 commSetConnTimeout(ctrl
.conn
, tout
, timeoutCall
);
318 typedef CommCbMemFunT
<Client
, CommIoCbParams
> Dialer
;
319 AsyncCall::Pointer reader
= JobCallback(9, 5, Dialer
, this, Ftp::Client::readControlReply
);
320 comm_read(ctrl
.conn
, ctrl
.buf
+ ctrl
.offset
, ctrl
.size
- ctrl
.offset
, reader
);
325 Ftp::Client::readControlReply(const CommIoCbParams
&io
)
327 debugs(9, 3, "FD " << io
.fd
<< ", Read " << io
.size
<< " bytes");
330 kb_incr(&(statCounter
.server
.all
.kbytes_in
), io
.size
);
331 kb_incr(&(statCounter
.server
.ftp
.kbytes_in
), io
.size
);
334 if (io
.flag
== Comm::ERR_CLOSING
)
337 if (EBIT_TEST(entry
->flags
, ENTRY_ABORTED
)) {
338 abortTransaction("entry aborted during control reply read");
342 assert(ctrl
.offset
< ctrl
.size
);
344 if (io
.flag
== Comm::OK
&& io
.size
> 0) {
345 fd_bytes(io
.fd
, io
.size
, FD_READ
);
348 if (io
.flag
!= Comm::OK
) {
349 debugs(50, ignoreErrno(io
.xerrno
) ? 3 : DBG_IMPORTANT
,
350 "FTP control reply read error: " << xstrerr(io
.xerrno
));
352 if (ignoreErrno(io
.xerrno
)) {
353 scheduleReadControlReply(0);
355 failed(ERR_READ_ERROR
, io
.xerrno
);
356 /* failed closes ctrl.conn and frees ftpState */
362 if (entry
->store_status
== STORE_PENDING
) {
363 failed(ERR_FTP_FAILURE
, 0);
364 /* failed closes ctrl.conn and frees ftpState */
368 /* XXX this may end up having to be serverComplete() .. */
369 abortTransaction("zero control reply read");
373 unsigned int len
=io
.size
+ ctrl
.offset
;
375 assert(len
<= ctrl
.size
);
376 if (Comm::IsConnOpen(ctrl
.conn
))
377 commUnsetConnTimeout(ctrl
.conn
); // we are done waiting for ctrl reply
378 handleControlReply();
382 Ftp::Client::handleControlReply()
384 debugs(9, 3, status());
386 size_t bytes_used
= 0;
387 wordlistDestroy(&ctrl
.message
);
389 if (!parseControlReply(bytes_used
)) {
390 /* didn't get complete reply yet */
392 if (ctrl
.offset
== ctrl
.size
) {
393 ctrl
.buf
= static_cast<char*>(memReallocBuf(ctrl
.buf
, ctrl
.size
<< 1, &ctrl
.size
));
396 scheduleReadControlReply(0);
400 assert(ctrl
.message
); // the entire FTP server response, line by line
401 assert(ctrl
.replycode
>= 0); // FTP status code (from the last line)
402 assert(ctrl
.last_reply
); // FTP reason (from the last line)
404 if (ctrl
.offset
== bytes_used
) {
408 /* Got some data past the complete reply */
409 assert(bytes_used
< ctrl
.offset
);
410 ctrl
.offset
-= bytes_used
;
411 memmove(ctrl
.buf
, ctrl
.buf
+ bytes_used
, ctrl
.offset
);
414 debugs(9, 3, "state=" << state
<< ", code=" << ctrl
.replycode
);
418 Ftp::Client::handlePasvReply(Ip::Address
&srvAddr
)
420 int code
= ctrl
.replycode
;
422 debugs(9, 3, status());
425 debugs(9, 2, "PASV not supported by remote end");
429 /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
430 /* ANSI sez [^0-9] is undefined, it breaks on Watcom cc */
431 debugs(9, 5, "scanning: " << ctrl
.last_reply
);
433 buf
= ctrl
.last_reply
+ strcspn(ctrl
.last_reply
, "0123456789");
435 const char *forceIp
= Config
.Ftp
.sanitycheck
?
436 fd_table
[ctrl
.conn
->fd
].ipaddr
: NULL
;
437 if (!Ftp::ParseIpPort(buf
, forceIp
, srvAddr
)) {
438 debugs(9, DBG_IMPORTANT
, "Unsafe PASV reply from " <<
439 ctrl
.conn
->remote
<< ": " << ctrl
.last_reply
);
449 Ftp::Client::handleEpsvReply(Ip::Address
&remoteAddr
)
451 int code
= ctrl
.replycode
;
453 debugs(9, 3, status());
455 if (code
!= 229 && code
!= 522) {
457 /* handle broken servers (RFC 2428 says OK code for EPSV MUST be 229 not 200) */
458 /* vsftpd for one send '200 EPSV ALL ok.' without even port info.
459 * Its okay to re-send EPSV 1/2 but nothing else. */
460 debugs(9, DBG_IMPORTANT
, "Broken FTP Server at " << ctrl
.conn
->remote
<< ". Wrong accept code for EPSV");
462 debugs(9, 2, "EPSV not supported by remote end");
464 return sendPassive();
468 /* Peer responded with a list of supported methods:
469 * 522 Network protocol not supported, use (1)
470 * 522 Network protocol not supported, use (1,2)
471 * 522 Network protocol not supported, use (2)
472 * TODO: Handle the (1,2) case which may happen after EPSV ALL. Close
473 * data + control without self-destructing and re-open from scratch.
475 debugs(9, 5, "scanning: " << ctrl
.last_reply
);
476 buf
= ctrl
.last_reply
;
477 while (buf
!= NULL
&& *buf
!= '\0' && *buf
!= '\n' && *buf
!= '(')
479 if (buf
!= NULL
&& *buf
== '\n')
482 if (buf
== NULL
|| *buf
== '\0') {
483 /* handle broken server (RFC 2428 says MUST specify supported protocols in 522) */
484 debugs(9, DBG_IMPORTANT
, "Broken FTP Server at " << ctrl
.conn
->remote
<< ". 522 error missing protocol negotiation hints");
485 return sendPassive();
486 } else if (strcmp(buf
, "(1)") == 0) {
487 state
= SENT_EPSV_2
; /* simulate having sent and failed EPSV 2 */
488 return sendPassive();
489 } else if (strcmp(buf
, "(2)") == 0) {
490 if (Ip::EnableIpv6
) {
491 /* If server only supports EPSV 2 and we have already tried that. Go straight to EPRT */
492 if (state
== SENT_EPSV_2
) {
495 /* or try the next Passive mode down the chain. */
496 return sendPassive();
499 /* Server only accept EPSV in IPv6 traffic. */
500 state
= SENT_EPSV_1
; /* simulate having sent and failed EPSV 1 */
501 return sendPassive();
504 /* handle broken server (RFC 2428 says MUST specify supported protocols in 522) */
505 debugs(9, DBG_IMPORTANT
, "WARNING: Server at " << ctrl
.conn
->remote
<< " sent unknown protocol negotiation hint: " << buf
);
506 return sendPassive();
508 failed(ERR_FTP_FAILURE
, 0);
512 /* 229 Entering Extended Passive Mode (|||port|) */
513 /* ANSI sez [^0-9] is undefined, it breaks on Watcom cc */
514 debugs(9, 5, "scanning: " << ctrl
.last_reply
);
516 buf
= ctrl
.last_reply
+ strcspn(ctrl
.last_reply
, "(");
520 int n
= sscanf(buf
, "(%c%c%c%hu%c)", &h1
, &h2
, &h3
, &port
, &h4
);
522 if (n
< 4 || h1
!= h2
|| h1
!= h3
|| h1
!= h4
) {
523 debugs(9, DBG_IMPORTANT
, "Invalid EPSV reply from " <<
524 ctrl
.conn
->remote
<< ": " <<
527 return sendPassive();
531 debugs(9, DBG_IMPORTANT
, "Unsafe EPSV reply from " <<
532 ctrl
.conn
->remote
<< ": " <<
535 return sendPassive();
538 if (Config
.Ftp
.sanitycheck
) {
540 debugs(9, DBG_IMPORTANT
, "Unsafe EPSV reply from " <<
541 ctrl
.conn
->remote
<< ": " <<
544 return sendPassive();
548 remoteAddr
= ctrl
.conn
->remote
;
549 remoteAddr
.port(port
);
550 data
.addr(remoteAddr
);
554 // FTP clients do not support EPRT and PORT commands yet.
555 // The Ftp::Client::sendEprt() will fail because of the unimplemented
556 // openListenSocket() or sendPort() methods
558 Ftp::Client::sendEprt()
560 if (!Config
.Ftp
.eprt
) {
561 /* Disabled. Switch immediately to attempting old PORT command. */
562 debugs(9, 3, "EPRT disabled by local administrator");
566 debugs(9, 3, status());
568 if (!openListenSocket()) {
569 failed(ERR_FTP_FAILURE
, 0);
573 debugs(9, 3, "Listening for FTP data connection with FD " << data
.conn
);
574 if (!Comm::IsConnOpen(data
.conn
)) {
575 // TODO: Set error message.
576 failed(ERR_FTP_FAILURE
, 0);
582 char buf
[MAX_IPSTRLEN
];
583 /* RFC 2428 defines EPRT as IPv6 equivalent to IPv4 PORT command. */
584 /* Which can be used by EITHER protocol. */
585 debugs(9, 3, "Listening for FTP data connection on port" << comm_local_port(data
.conn
->fd
) << " or port?" << data
.conn
->local
.port());
586 mb
.Printf("EPRT |%d|%s|%d|%s",
587 ( data
.conn
->local
.isIPv6() ? 2 : 1 ),
588 data
.conn
->local
.toStr(buf
,MAX_IPSTRLEN
),
589 comm_local_port(data
.conn
->fd
), Ftp::crlf
);
592 writeCommand(mb
.content());
597 Ftp::Client::sendPort()
599 failed(ERR_FTP_FAILURE
, 0);
604 Ftp::Client::sendPassive()
606 debugs(9, 3, status());
609 * Checks for EPSV ALL special conditions:
610 * If enabled to be sent, squid MUST NOT request any other connect methods.
611 * If 'ALL' is sent and fails the entire FTP Session fails.
612 * NP: By my reading exact EPSV protocols maybe attempted, but only EPSV method. */
613 if (Config
.Ftp
.epsv_all
&& state
== SENT_EPSV_1
) {
614 // We are here because the last "EPSV 1" failed, but because of epsv_all
615 // no other method allowed.
616 debugs(9, DBG_IMPORTANT
, "FTP does not allow PASV method after 'EPSV ALL' has been sent.");
617 failed(ERR_FTP_FAILURE
, 0);
621 /// Closes any old FTP-Data connection which may exist. */
625 * Checks for previous EPSV/PASV failures on this server/session.
626 * Diverts to EPRT immediately if they are not working. */
627 if (!Config
.Ftp
.passive
|| state
== SENT_PASV
) {
635 * Send EPSV (ALL,2,1) or PASV on the control channel.
637 * - EPSV ALL is used if enabled.
638 * - EPSV 2 is used if ALL is disabled and IPv6 is available and ctrl channel is IPv6.
639 * - EPSV 1 is used if EPSV 2 (IPv6) fails or is not available or ctrl channel is IPv4.
640 * - PASV is used if EPSV 1 fails.
643 case SENT_EPSV_ALL
: /* EPSV ALL resulted in a bad response. Try ther EPSV methods. */
644 if (ctrl
.conn
->local
.isIPv6()) {
645 debugs(9, 5, "FTP Channel is IPv6 (" << ctrl
.conn
->remote
<< ") attempting EPSV 2 after EPSV ALL has failed.");
646 mb
.Printf("EPSV 2%s", Ftp::crlf
);
650 // else fall through to skip EPSV 2
652 case SENT_EPSV_2
: /* EPSV IPv6 failed. Try EPSV IPv4 */
653 if (ctrl
.conn
->local
.isIPv4()) {
654 debugs(9, 5, "FTP Channel is IPv4 (" << ctrl
.conn
->remote
<< ") attempting EPSV 1 after EPSV ALL has failed.");
655 mb
.Printf("EPSV 1%s", Ftp::crlf
);
658 } else if (Config
.Ftp
.epsv_all
) {
659 debugs(9, DBG_IMPORTANT
, "FTP does not allow PASV method after 'EPSV ALL' has been sent.");
660 failed(ERR_FTP_FAILURE
, 0);
663 // else fall through to skip EPSV 1
665 case SENT_EPSV_1
: /* EPSV options exhausted. Try PASV now. */
666 debugs(9, 5, "FTP Channel (" << ctrl
.conn
->remote
<< ") rejects EPSV connection attempts. Trying PASV instead.");
667 mb
.Printf("PASV%s", Ftp::crlf
);
673 if (Config
.accessList
.ftp_epsv
) {
674 ACLFilledChecklist
checklist(Config
.accessList
.ftp_epsv
, fwd
->request
, NULL
);
675 doEpsv
= (checklist
.fastCheck() == ACCESS_ALLOWED
);
678 debugs(9, 5, "EPSV support manually disabled. Sending PASV for FTP Channel (" << ctrl
.conn
->remote
<<")");
679 mb
.Printf("PASV%s", Ftp::crlf
);
681 } else if (Config
.Ftp
.epsv_all
) {
682 debugs(9, 5, "EPSV ALL manually enabled. Attempting with FTP Channel (" << ctrl
.conn
->remote
<<")");
683 mb
.Printf("EPSV ALL%s", Ftp::crlf
);
684 state
= SENT_EPSV_ALL
;
686 if (ctrl
.conn
->local
.isIPv6()) {
687 debugs(9, 5, "FTP Channel (" << ctrl
.conn
->remote
<< "). Sending default EPSV 2");
688 mb
.Printf("EPSV 2%s", Ftp::crlf
);
691 if (ctrl
.conn
->local
.isIPv4()) {
692 debugs(9, 5, "Channel (" << ctrl
.conn
->remote
<<"). Sending default EPSV 1");
693 mb
.Printf("EPSV 1%s", Ftp::crlf
);
702 wordlistDestroy(&ctrl
.message
);
703 ctrl
.message
= NULL
; //No message to return to client.
704 ctrl
.offset
= 0; //reset readed response, to make room read the next response
706 writeCommand(mb
.content());
708 shortenReadTimeout
= true;
713 Ftp::Client::connectDataChannel()
715 safe_free(ctrl
.last_command
);
717 safe_free(ctrl
.last_reply
);
719 ctrl
.last_command
= xstrdup("Connect to server data port");
721 // Generate a new data channel descriptor to be opened.
722 Comm::ConnectionPointer conn
= new Comm::Connection
;
723 conn
->setAddrs(ctrl
.conn
->local
, data
.host
);
725 conn
->remote
.port(data
.port
);
726 conn
->tos
= ctrl
.conn
->tos
;
727 conn
->nfmark
= ctrl
.conn
->nfmark
;
729 debugs(9, 3, "connecting to " << conn
->remote
);
731 typedef CommCbMemFunT
<Client
, CommConnectCbParams
> Dialer
;
732 data
.opener
= JobCallback(9, 3, Dialer
, this, Ftp::Client::dataChannelConnected
);
733 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, data
.opener
, Config
.Timeout
.connect
);
734 cs
->setHost(data
.host
);
739 Ftp::Client::openListenSocket()
744 /// creates a data channel Comm close callback
746 Ftp::Client::dataCloser()
748 typedef CommCbMemFunT
<Client
, CommCloseCbParams
> Dialer
;
749 return JobCallback(9, 5, Dialer
, this, Ftp::Client::dataClosed
);
752 /// handler called by Comm when FTP data channel is closed unexpectedly
754 Ftp::Client::dataClosed(const CommCloseCbParams
&io
)
756 debugs(9, 4, status());
757 if (data
.listenConn
!= NULL
) {
758 data
.listenConn
->close();
759 data
.listenConn
= NULL
;
760 // NP clear() does the: data.fd = -1;
766 Ftp::Client::writeCommand(const char *buf
)
769 /* trace FTP protocol communications at level 2 */
770 debugs(9, 2, "ftp<< " << buf
);
772 if (Config
.Ftp
.telnet
)
773 ebuf
= escapeIAC(buf
);
777 safe_free(ctrl
.last_command
);
779 safe_free(ctrl
.last_reply
);
781 ctrl
.last_command
= ebuf
;
783 if (!Comm::IsConnOpen(ctrl
.conn
)) {
784 debugs(9, 2, "cannot send to closing ctrl " << ctrl
.conn
);
785 // TODO: assert(ctrl.closer != NULL);
789 typedef CommCbMemFunT
<Client
, CommIoCbParams
> Dialer
;
790 AsyncCall::Pointer call
= JobCallback(9, 5, Dialer
, this,
791 Ftp::Client::writeCommandCallback
);
792 Comm::Write(ctrl
.conn
, ctrl
.last_command
, strlen(ctrl
.last_command
), call
, NULL
);
794 scheduleReadControlReply(0);
798 Ftp::Client::writeCommandCallback(const CommIoCbParams
&io
)
801 debugs(9, 5, "wrote " << io
.size
<< " bytes");
804 fd_bytes(io
.fd
, io
.size
, FD_WRITE
);
805 kb_incr(&(statCounter
.server
.all
.kbytes_out
), io
.size
);
806 kb_incr(&(statCounter
.server
.ftp
.kbytes_out
), io
.size
);
809 if (io
.flag
== Comm::ERR_CLOSING
)
813 debugs(9, DBG_IMPORTANT
, "FTP command write error: " << io
.conn
<< ": " << xstrerr(io
.xerrno
));
814 failed(ERR_WRITE_ERROR
, io
.xerrno
);
815 /* failed closes ctrl.conn and frees ftpState */
820 /// handler called by Comm when FTP control channel is closed unexpectedly
822 Ftp::Client::ctrlClosed(const CommCloseCbParams
&io
)
824 debugs(9, 4, status());
826 mustStop("Ftp::Client::ctrlClosed");
830 Ftp::Client::timeout(const CommTimeoutCbParams
&io
)
832 debugs(9, 4, io
.conn
<< ": '" << entry
->url() << "'" );
834 if (abortOnBadEntry("entry went bad while waiting for a timeout"))
837 failed(ERR_READ_TIMEOUT
, 0);
838 /* failed() closes ctrl.conn and frees ftpState */
841 const Comm::ConnectionPointer
&
842 Ftp::Client::dataConnection() const
848 Ftp::Client::maybeReadVirginBody()
851 if (!Comm::IsConnOpen(data
.conn
) || fd_table
[data
.conn
->fd
].closing())
854 if (data
.read_pending
)
859 const int read_sz
= replyBodySpace(*data
.readBuf
, 0);
861 debugs(9, 9, "FTP may read up to " << read_sz
<< " bytes");
863 if (read_sz
< 2) // see http.cc
866 data
.read_pending
= true;
868 typedef CommCbMemFunT
<Client
, CommTimeoutCbParams
> TimeoutDialer
;
869 AsyncCall::Pointer timeoutCall
= JobCallback(9, 5,
870 TimeoutDialer
, this, Ftp::Client::timeout
);
871 commSetConnTimeout(data
.conn
, Config
.Timeout
.read
, timeoutCall
);
873 debugs(9,5,"queueing read on FD " << data
.conn
->fd
);
875 typedef CommCbMemFunT
<Client
, CommIoCbParams
> Dialer
;
876 entry
->delayAwareRead(data
.conn
, data
.readBuf
->space(), read_sz
,
877 JobCallback(9, 5, Dialer
, this, Ftp::Client::dataRead
));
881 Ftp::Client::dataRead(const CommIoCbParams
&io
)
886 data
.read_pending
= false;
888 debugs(9, 3, "FD " << io
.fd
<< " Read " << io
.size
<< " bytes");
891 kb_incr(&(statCounter
.server
.all
.kbytes_in
), io
.size
);
892 kb_incr(&(statCounter
.server
.ftp
.kbytes_in
), io
.size
);
895 if (io
.flag
== Comm::ERR_CLOSING
)
898 assert(io
.fd
== data
.conn
->fd
);
900 if (EBIT_TEST(entry
->flags
, ENTRY_ABORTED
)) {
901 abortTransaction("entry aborted during dataRead");
905 if (io
.flag
== Comm::OK
&& io
.size
> 0) {
906 debugs(9, 5, "appended " << io
.size
<< " bytes to readBuf");
907 data
.readBuf
->appended(io
.size
);
909 DelayId delayId
= entry
->mem_obj
->mostBytesAllowed();
910 delayId
.bytesIn(io
.size
);
912 ++ IOStats
.Ftp
.reads
;
914 for (j
= io
.size
- 1, bin
= 0; j
; ++bin
)
917 ++ IOStats
.Ftp
.read_hist
[bin
];
920 if (io
.flag
!= Comm::OK
) {
921 debugs(50, ignoreErrno(io
.xerrno
) ? 3 : DBG_IMPORTANT
,
922 "FTP data read error: " << xstrerr(io
.xerrno
));
924 if (ignoreErrno(io
.xerrno
)) {
925 maybeReadVirginBody();
927 failed(ERR_READ_ERROR
, 0);
928 /* failed closes ctrl.conn and frees ftpState */
931 } else if (io
.size
== 0) {
932 debugs(9, 3, "Calling dataComplete() because io.size == 0");
935 * Dangerous curves ahead. This call to dataComplete was
936 * calling scheduleReadControlReply, handleControlReply,
937 * and then ftpReadTransferDone. If ftpReadTransferDone
938 * gets unexpected status code, it closes down the control
939 * socket and our FtpStateData object gets destroyed. As
940 * a workaround we no longer set the 'buffered_ok' flag in
941 * the scheduleReadControlReply call.
950 Ftp::Client::dataComplete()
952 debugs(9, 3,status());
954 /* Connection closed; transfer done. */
956 /// Close data channel, if any, to conserve resources while we wait.
959 /* expect the "transfer complete" message on the control socket */
962 * Previously, this was the only place where we set the
963 * 'buffered_ok' flag when calling scheduleReadControlReply().
964 * It caused some problems if the FTP server returns an unexpected
965 * status code after the data command. FtpStateData was being
966 * deleted in the middle of dataRead().
968 /* AYJ: 2011-01-13: Bug 2581.
969 * 226 status is possibly waiting in the ctrl buffer.
970 * The connection will hang if we DONT send buffered_ok.
971 * This happens on all transfers which can be completly sent by the
972 * server before the 150 started status message is read in by Squid.
973 * ie all transfers of about one packet hang.
975 scheduleReadControlReply(1);
979 * Quickly abort the transaction
981 \todo destruction should be sufficient as the destructor should cleanup,
982 * including canceling close handlers
985 Ftp::Client::abortTransaction(const char *reason
)
987 debugs(9, 3, "aborting transaction for " << reason
<<
988 "; FD " << (ctrl
.conn
!=NULL
?ctrl
.conn
->fd
:-1) << ", Data FD " << (data
.conn
!=NULL
?data
.conn
->fd
:-1) << ", this " << this);
989 if (Comm::IsConnOpen(ctrl
.conn
)) {
994 fwd
->handleUnregisteredServerEnd();
995 mustStop("Ftp::Client::abortTransaction");
999 * Cancel the timeout on the Control socket and establish one
1000 * on the data socket
1003 Ftp::Client::switchTimeoutToDataChannel()
1005 commUnsetConnTimeout(ctrl
.conn
);
1007 typedef CommCbMemFunT
<Client
, CommTimeoutCbParams
> TimeoutDialer
;
1008 AsyncCall::Pointer timeoutCall
= JobCallback(9, 5, TimeoutDialer
, this,
1009 Ftp::Client::timeout
);
1010 commSetConnTimeout(data
.conn
, Config
.Timeout
.read
, timeoutCall
);
1014 Ftp::Client::sentRequestBody(const CommIoCbParams
&io
)
1017 kb_incr(&(statCounter
.server
.ftp
.kbytes_out
), io
.size
);
1018 ::ServerStateData::sentRequestBody(io
);
1022 * called after we wrote the last byte of the request body
1025 Ftp::Client::doneSendingRequestBody()
1027 ::ServerStateData::doneSendingRequestBody();
1028 debugs(9, 3, status());
1030 /* NP: RFC 959 3.3. DATA CONNECTION MANAGEMENT
1031 * if transfer type is 'stream' call dataComplete()
1032 * otherwise leave open. (reschedule control channel read?)
1036 /// Parses FTP server control response into ctrl structure fields,
1037 /// setting bytesUsed and returning true on success.
1039 Ftp::Client::parseControlReply(size_t &bytesUsed
)
1046 wordlist
*head
= NULL
;
1048 wordlist
**tail
= &head
;
1050 debugs(9, 3, status());
1052 * We need a NULL-terminated buffer for scanning, ick
1054 const size_t len
= ctrl
.offset
;
1055 sbuf
= (char *)xmalloc(len
+ 1);
1056 xstrncpy(sbuf
, ctrl
.buf
, len
+ 1);
1057 end
= sbuf
+ len
- 1;
1059 while (*end
!= '\r' && *end
!= '\n' && end
> sbuf
)
1062 usable
= end
- sbuf
;
1064 debugs(9, 3, "usable = " << usable
);
1067 debugs(9, 3, "didn't find end of line");
1072 debugs(9, 3, len
<< " bytes to play with");
1075 s
+= strspn(s
, crlf
);
1077 for (; s
< end
; s
+= strcspn(s
, crlf
), s
+= strspn(s
, crlf
)) {
1081 debugs(9, 5, "s = {" << s
<< "}");
1083 linelen
= strcspn(s
, crlf
) + 1;
1089 complete
= (*s
>= '0' && *s
<= '9' && *(s
+ 3) == ' ');
1091 list
= new wordlist();
1093 list
->key
= (char *)xmalloc(linelen
);
1095 xstrncpy(list
->key
, s
, linelen
);
1097 /* trace the FTP communication chat at level 2 */
1098 debugs(9, 2, "ftp>> " << list
->key
);
1101 // use list->key for last_reply because s contains the new line
1102 ctrl
.last_reply
= xstrdup(list
->key
+ 4);
1103 ctrl
.replycode
= atoi(list
->key
);
1111 bytesUsed
= static_cast<size_t>(s
- sbuf
);
1115 wordlistDestroy(&head
);
1119 ctrl
.message
= head
;
1120 assert(ctrl
.replycode
>= 0);
1121 assert(ctrl
.last_reply
);
1122 assert(ctrl
.message
);