post by tommy @ 17 六月, 2006 13:20
這個問題, 只會發生在下列的情形:
- 有限定 FileZilla 所使用的 port 的範圍.
- 同時產生 CFtpControlSocket 物件, 所以程式在呼叫 srand() 時, 會傳入同一個種子. 後頭產生的亂數會一樣. (非必要, 只不過因為這樣, 會在同時連線的情形發生問題)
- 有使用 SSL/TLS 或 GSS 或 Proxy 等額外的 layer, 非單經的 TCP/IP 連線.
- 在 bind socket 時, 因為有限制 port 的範圍, 所以並非傳入 0, 由系統選取任意 port, 而是程式會亂數取該範圍的值, 然後依序試著去 bind 看有沒有被使用掉.
- port 的選取, 如果剛好選到被用掉的 port 時, 在 bind() 會失敗, 接下去會做一些 Close() 的動作, 清除掉 CFtpControlSocket 物件的一些值, 然後... 再次嘗試下一個 port 時, 就失去這些額外的 layer 設定, 而變成一個單純的 TCP/IP 連線. 雖然連線會成功, 但是後續 layer 上頭的動作會失敗.
所以, 只要是用到不能用的 port, 就會發生這個問題. 就算不是同時使用, 就算亂數的種子是不同的, 仍有可能發生. 會變成一個隨機發生的問題.
我的這個 patch, 會在 bind 失敗時, 再重新設定那些原本在 Connect 所設定的值, 然後再試下一個 port. 目前看來, 在我這兒的運作是正常的.
diff -Nur source.orig/FtpControlSocket.cpp source/FtpControlSocket.cpp
--- source.orig/FtpControlSocket.cpp Fri May 26 14:24:30 2006
+++ source/FtpControlSocket.cpp Sat Jun 17 13:01:58 2006
@@ -198,7 +198,7 @@
#define CONNECT_OPTSUTF8 -15
#define CONNECT_CLNT -16
-void CFtpControlSocket::Connect(t_server &server)
+BOOL CFtpControlSocket::InitConnect(t_server &server)
{
USES_CONVERSION;
@@ -219,14 +219,14 @@
if (!m_Operation.nOpMode)
m_Operation.nOpMode = CSMODE_CONNECT;
DoClose(FZ_REPLY_CRITICALERROR);
- return;
+ return FALSE;
}
if (m_Operation.nOpMode)
{
ShowStatus(_T("Internal error: m_Operation.nOpMode not zero in Connect"), 1);
m_Operation.nOpMode = CSMODE_CONNECT;
DoClose(FZ_REPLY_CRITICALERROR);
- return;
+ return FALSE;
}
m_Operation.nOpMode = CSMODE_CONNECT;
@@ -235,13 +235,13 @@
{
ShowStatus(_T("Internal error: m_pSslLayer not zero in Connect"), 1);
DoClose(FZ_REPLY_CRITICALERROR);
- return;
+ return FALSE;
}
if (m_pProxyLayer)
{
ShowStatus(_T("Internal error: m_pProxyLayer not zero in Connect"), 1);
DoClose(FZ_REPLY_CRITICALERROR);
- return;
+ return FALSE;
}
if (server.nServerType & FZ_SERVERTYPE_LAYER_SSL_IMPLICIT ||
@@ -328,11 +328,20 @@
{
ShowStatus(_T("Unable to initialize GSS api"), 1);
DoClose(FZ_REPLY_CRITICALERROR);
- return;
+ return FALSE;
}
}
m_Operation.nOpState = m_pGssLayer?CONNECT_GSS_INIT:CONNECT_INIT;
m_Operation.nOpMode = CSMODE_CONNECT;
+ return TRUE;
+}
+
+void CFtpControlSocket::Connect(t_server &server)
+{
+ USES_CONVERSION;
+
+ m_server = server;
+ if (!InitConnect(server)) return;
if (!Create())
{
@@ -3964,6 +3973,8 @@
ShowStatus(IDS_ERRORMSG_CANTCREATEDUETOPORTRANGE,1);
return FALSE;
}
+ m_Operation.nOpMode = 0;
+ if (!InitConnect(m_server)) return FALSE;
}
}
return TRUE;
diff -Nur source.orig/FtpControlSocket.h source/FtpControlSocket.h
--- source.orig/FtpControlSocket.h Fri May 26 14:19:06 2006
+++ source/FtpControlSocket.h Sat Jun 17 12:57:15 2006
@@ -49,6 +49,8 @@
// �berschreibungen
public:
+ t_server m_server;
+ BOOL InitConnect(t_server &server);
virtual void Connect(t_server &server);
virtual void OnTimer();
virtual BOOL IsReady();
可以到這兒抓這個 patch, 與使用這個 patch 加上 sftp UTF8 支援的版本:
http://www.teatime.com.tw/~tommy/mypatch/fz2224_ssl_connect.patch
http://www.teatime.com.tw/~tommy/filezilla.zip
我不確定作者是否會採用我的作法, 因為有點 ugly. 不過就算不是這樣子, 也應該會解決這個問題吧.
2006/6/17: 下午作者回覆, 參考我的作法, 他做了一些修正, 已經放到 CVS 中了.