OSDN Git Service

Fix bugs of corruption on resuming downloading files larger than 4GB.
[ffftp/ffftp.git] / socket.c
index 7c80486..1051425 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -38,6 +38,8 @@
 \r
 #include "common.h"\r
 #include "resource.h"\r
+// UTF-8対応\r
+#include "punycode.h"\r
 \r
 #define USE_THIS       1\r
 #define DBG_MSG                0\r
@@ -92,6 +94,8 @@ static int RegistAsyncTable(SOCKET s);
 static int RegistAsyncTableDbase(HANDLE Async);\r
 static int UnRegistAsyncTable(SOCKET s);\r
 static int UnRegistAsyncTableDbase(HANDLE Async);\r
+// UTF-8対応\r
+static HANDLE WSAAsyncGetHostByNameM(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen);\r
 \r
 \r
 /*===== 外部参照 =====*/\r
@@ -271,6 +275,8 @@ static LRESULT CALLBACK SocketWndProc(HWND hWnd, UINT message, WPARAM wParam, LP
                        break;\r
 \r
                case WM_ASYNC_DBASE :\r
+                       // APIの仕様上ハンドルが登録される前にウィンドウメッセージが呼び出される可能性あり\r
+                       RegistAsyncTableDbase((HANDLE)wParam);\r
                        // スレッド衝突のバグ修正\r
                        WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
                        for(Pos = 0; Pos < MAX_SIGNAL_ENTRY_DBASE; Pos++)\r
@@ -291,31 +297,6 @@ static LRESULT CALLBACK SocketWndProc(HWND hWnd, UINT message, WPARAM wParam, LP
                                        break;\r
                                }\r
                        }\r
-                       // APIの仕様上ハンドルが登録される前にウィンドウメッセージが呼び出される可能性あり\r
-                       if(Pos == MAX_SIGNAL_ENTRY_DBASE)\r
-                       {\r
-                               for(Pos = 0; Pos < MAX_SIGNAL_ENTRY_DBASE; Pos++)\r
-                               {\r
-                                       if(SignalDbase[Pos].Async == 0)\r
-                                       {\r
-                                               SignalDbase[Pos].Async = (HANDLE)wParam;\r
-                                               SignalDbase[Pos].Done = 0;\r
-                                               SignalDbase[Pos].ErrorDb = 0;\r
-                                               if(HIWORD(lParam) != 0)\r
-                                               {\r
-                                                       SignalDbase[Pos].ErrorDb = 1;\r
-#if DBG_MSG\r
-                                                       DoPrintf("##### SignalDatabase: error");\r
-#endif\r
-                                               }\r
-                                               SignalDbase[Pos].Done = 1;\r
-#if DBG_MSG\r
-                                               DoPrintf("##### SignalDatabase: Done");\r
-#endif\r
-                                               break;\r
-                                       }\r
-                               }\r
-                       }\r
                        // スレッド衝突のバグ修正\r
                        ReleaseMutex(hAsyncTblAccMutex);\r
                        break;\r
@@ -484,8 +465,8 @@ static int RegistAsyncTable(SOCKET s)
                {\r
                        // 強制的に閉じられたソケットがあると重複する可能性あり\r
 //                     MessageBox(GetMainHwnd(), "Async socket already registerd.", "FFFTP inner error", MB_OK);\r
+//                     break;\r
                        Signal[Pos].Socket = INVALID_SOCKET;\r
-                       break;\r
                }\r
        }\r
        // スレッド衝突のバグ修正\r
@@ -678,7 +659,9 @@ struct hostent *do_gethostbyname(const char *Name, char *Buf, int Len, int *Canc
        Ret = NULL;\r
        *CancelCheckWork = NO;\r
 \r
-       hAsync = WSAAsyncGetHostByName(hWndSocket, WM_ASYNC_DBASE, Name, Buf, Len);\r
+       // UTF-8対応\r
+//     hAsync = WSAAsyncGetHostByName(hWndSocket, WM_ASYNC_DBASE, Name, Buf, Len);\r
+       hAsync = WSAAsyncGetHostByNameM(hWndSocket, WM_ASYNC_DBASE, Name, Buf, Len);\r
        if(hAsync != NULL)\r
        {\r
                RegistAsyncTableDbase(hAsync);\r
@@ -738,12 +721,12 @@ int do_closesocket(SOCKET s)
 #endif\r
        CancelCheckWork = NO;\r
 \r
+       // スレッド衝突のバグ修正\r
+       WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, 0);\r
+       UnRegistAsyncTable(s);\r
        // FTPS対応\r
 //     Ret = closesocket(s);\r
-       if(AskCryptMode() == CRYPT_FTPES || AskCryptMode() == CRYPT_FTPIS)\r
-               Ret = closesocketS(s);\r
-       else\r
-               Ret = closesocketS(s);\r
+       Ret = closesocketS(s);\r
        if(Ret == SOCKET_ERROR)\r
        {\r
                Error = 0;\r
@@ -758,10 +741,12 @@ int do_closesocket(SOCKET s)
                        Ret = 0;\r
        }\r
 \r
-       WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, 0);\r
+       // スレッド衝突のバグ修正\r
+//     WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, 0);\r
        if(BackgrndMessageProc() == YES)\r
                CancelCheckWork = YES;\r
-       UnRegistAsyncTable(s);\r
+       // スレッド衝突のバグ修正\r
+//     UnRegistAsyncTable(s);\r
 \r
 #if DBG_MSG\r
        DoPrintf("# Exit close");\r
@@ -794,12 +779,7 @@ int do_connect(SOCKET s, const struct sockaddr *name, int namelen, int *CancelCh
        Ret = WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, FD_CONNECT | FD_CLOSE | FD_ACCEPT | FD_READ | FD_WRITE);\r
        if(Ret != SOCKET_ERROR)\r
        {\r
-               // FTPS対応\r
-//             Ret = connect(s, name, namelen);\r
-               if(AskCryptMode() == CRYPT_FTPIS)\r
-                       Ret = connectS(s, name, namelen);\r
-               else\r
-                       Ret = connect(s, name, namelen);\r
+               Ret = connect(s, name, namelen);\r
                if(Ret == SOCKET_ERROR)\r
                {\r
                        do\r
@@ -893,12 +873,7 @@ SOCKET do_accept(SOCKET s, struct sockaddr *addr, int *addrlen)
        {\r
                do\r
                {\r
-                       // FTPS対応\r
-//                     Ret2 = accept(s, addr, addrlen);\r
-                       if(AskCryptMode() == CRYPT_FTPIS)\r
-                               Ret2 = acceptS(s, addr, addrlen);\r
-                       else\r
-                               Ret2 = accept(s, addr, addrlen);\r
+                       Ret2 = accept(s, addr, addrlen);\r
                        if(Ret2 != INVALID_SOCKET)\r
                        {\r
 #if DBG_MSG\r
@@ -970,7 +945,7 @@ int do_recv(SOCKET s, char *buf, int len, int flags, int *TimeOutErr, int *Cance
        // FTPS対応\r
        // OpenSSLでは受信確認はFD_READが複数回受信される可能性がある\r
 //     while((*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_READ_BIT) != YES))\r
-       while(AskCryptMode() == CRYPT_NONE && (*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_READ_BIT) != YES))\r
+       while(!IsSSLAttached(s) && (*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_READ_BIT) != YES))\r
        {\r
                if(AskAsyncDone(s, &Error, FD_CLOSE_BIT) == YES)\r
                {\r
@@ -1003,23 +978,20 @@ int do_recv(SOCKET s, char *buf, int len, int flags, int *TimeOutErr, int *Cance
 \r
                        // FTPS対応\r
 //                     Ret = recv(s, buf, len, flags);\r
-                       if(AskCryptMode() == CRYPT_FTPES || AskCryptMode() == CRYPT_FTPIS)\r
-                               Ret = recvS(s, buf, len, flags);\r
-                       else\r
-                               Ret = recv(s, buf, len, flags);\r
+                       Ret = recvS(s, buf, len, flags);\r
                        if(Ret != SOCKET_ERROR)\r
                                break;\r
+                       // 何故か一部のホストとWindows 2000の組み合わせで通信できないバグに暫定対応\r
+                       if(AskAsyncDone(s, &Error, FD_CLOSE_BIT) == YES && recvS(s, buf, len, MSG_PEEK) <= 0)\r
+                               break;\r
                        Error = WSAGetLastError();\r
                        Sleep(1);\r
                        if(BackgrndMessageProc() == YES)\r
                                break;\r
                        // FTPS対応\r
                        // 受信確認をバイパスしたためここでタイムアウトの確認\r
-                       if(AskCryptMode() == CRYPT_FTPES || AskCryptMode() == CRYPT_FTPIS)\r
-                       {\r
-                               if(BackgrndMessageProc() == YES)\r
-                                       *CancelCheckWork = YES;\r
-                       }\r
+                       if(BackgrndMessageProc() == YES)\r
+                               *CancelCheckWork = YES;\r
                        else if(TimeOut != 0)\r
                        {\r
                                time(&ElapseTime);\r
@@ -1080,7 +1052,7 @@ int do_send(SOCKET s, const char *buf, int len, int flags, int *TimeOutErr, int
        // FTPS対応\r
        // 送信バッファの空き確認には影響しないが念のため\r
 //     while((*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_WRITE_BIT) != YES))\r
-       while(AskCryptMode() == CRYPT_NONE && (*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_WRITE_BIT) != YES))\r
+       while(!IsSSLAttached(s) && (*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_WRITE_BIT) != YES))\r
        {\r
                if(AskAsyncDone(s, &Error, FD_CLOSE_BIT) == YES)\r
                {\r
@@ -1114,10 +1086,7 @@ int do_send(SOCKET s, const char *buf, int len, int flags, int *TimeOutErr, int
 \r
                        // FTPS対応\r
 //                     Ret = send(s, buf, len, flags);\r
-                       if(AskCryptMode() == CRYPT_FTPES || AskCryptMode() == CRYPT_FTPIS)\r
-                               Ret = sendS(s, buf, len, flags);\r
-                       else\r
-                               Ret = send(s, buf, len, flags);\r
+                       Ret = sendS(s, buf, len, flags);\r
                        if(Ret != SOCKET_ERROR)\r
                        {\r
 #if DBG_MSG\r
@@ -1125,17 +1094,17 @@ int do_send(SOCKET s, const char *buf, int len, int flags, int *TimeOutErr, int
 #endif\r
                                break;\r
                        }\r
+                       // 何故か一部のホストとWindows 2000の組み合わせで通信できないバグに暫定対応\r
+                       if(AskAsyncDone(s, &Error, FD_CLOSE_BIT) == YES)\r
+                               break;\r
                        Error = WSAGetLastError();\r
                        Sleep(1);\r
                        if(BackgrndMessageProc() == YES)\r
                                break;\r
                        // FTPS対応\r
                        // 送信バッファ確認をバイパスしたためここでタイムアウトの確認\r
-                       if(AskCryptMode() == CRYPT_FTPES || AskCryptMode() == CRYPT_FTPIS)\r
-                       {\r
-                               if(BackgrndMessageProc() == YES)\r
-                                       *CancelCheckWork = YES;\r
-                       }\r
+                       if(BackgrndMessageProc() == YES)\r
+                               *CancelCheckWork = YES;\r
                        else if(TimeOut != 0)\r
                        {\r
                                time(&ElapseTime);\r
@@ -1192,3 +1161,124 @@ int CheckClosedAndReconnect(void)
 \r
 \r
 \r
+// UTF-8対応\r
+\r
+static BOOL ConvertStringToPunycode(LPSTR Output, DWORD Count, LPCSTR Input)\r
+{\r
+       BOOL bResult;\r
+       punycode_uint* pUnicode;\r
+       punycode_uint* p;\r
+       BOOL bNeeded;\r
+       LPCSTR InputString;\r
+       punycode_uint Length;\r
+       punycode_uint OutputLength;\r
+       bResult = FALSE;\r
+       if(pUnicode = malloc(sizeof(punycode_uint) * strlen(Input)))\r
+       {\r
+               p = pUnicode;\r
+               bNeeded = FALSE;\r
+               InputString = Input;\r
+               Length = 0;\r
+               while(*InputString != '\0')\r
+               {\r
+                       *p = 0;\r
+                       if((*InputString & 0x80) == 0x00)\r
+                               *p |= (punycode_uint)*InputString & 0x7f;\r
+                       else if((*InputString & 0xe0) == 0xc0)\r
+                               *p |= (punycode_uint)*InputString & 0x1f;\r
+                       else if((*InputString & 0xf0) == 0xe0)\r
+                               *p |= (punycode_uint)*InputString & 0x0f;\r
+                       else if((*InputString & 0xf8) == 0xf0)\r
+                               *p |= (punycode_uint)*InputString & 0x07;\r
+                       else if((*InputString & 0xfc) == 0xf8)\r
+                               *p |= (punycode_uint)*InputString & 0x03;\r
+                       else if((*InputString & 0xfe) == 0xfc)\r
+                               *p |= (punycode_uint)*InputString & 0x01;\r
+                       InputString++;\r
+                       while((*InputString & 0xc0) == 0x80)\r
+                       {\r
+                               *p = *p << 6;\r
+                               *p |= (punycode_uint)*InputString & 0x3f;\r
+                               InputString++;\r
+                       }\r
+                       if(*p >= 0x80)\r
+                               bNeeded = TRUE;\r
+                       p++;\r
+                       Length++;\r
+               }\r
+               if(bNeeded)\r
+               {\r
+                       if(Count >= strlen("xn--") + 1)\r
+                       {\r
+                               strcpy(Output, "xn--");\r
+                               OutputLength = Count - strlen("xn--");\r
+                               if(punycode_encode(Length, pUnicode, NULL, (punycode_uint*)&OutputLength, Output + strlen("xn--")) == punycode_success)\r
+                               {\r
+                                       Output[strlen("xn--") + OutputLength] = '\0';\r
+                                       bResult = TRUE;\r
+                               }\r
+                       }\r
+               }\r
+               free(pUnicode);\r
+       }\r
+       if(!bResult)\r
+       {\r
+               if(Count >= strlen(Input) + 1)\r
+               {\r
+                       strcpy(Output, Input);\r
+                       bResult = TRUE;\r
+               }\r
+       }\r
+       return bResult;\r
+}\r
+\r
+static BOOL ConvertNameToPunycode(LPSTR Output, LPCSTR Input)\r
+{\r
+       BOOL bResult;\r
+       DWORD Length;\r
+       char* pm0;\r
+       char* pm1;\r
+       char* p;\r
+       char* pNext;\r
+       bResult = FALSE;\r
+       Length = strlen(Input);\r
+       if(pm0 = AllocateStringM(Length + 1))\r
+       {\r
+               if(pm1 = AllocateStringM(Length * 4 + 1))\r
+               {\r
+                       strcpy(pm0, Input);\r
+                       p = pm0;\r
+                       while(p)\r
+                       {\r
+                               if(pNext = strchr(p, '.'))\r
+                               {\r
+                                       *pNext = '\0';\r
+                                       pNext++;\r
+                               }\r
+                               if(ConvertStringToPunycode(pm1, Length * 4, p))\r
+                                       strcat(Output, pm1);\r
+                               if(pNext)\r
+                                       strcat(Output, ".");\r
+                               p = pNext;\r
+                       }\r
+                       bResult = TRUE;\r
+                       FreeDuplicatedString(pm1);\r
+               }\r
+               FreeDuplicatedString(pm0);\r
+       }\r
+       return bResult;\r
+}\r
+\r
+static HANDLE WSAAsyncGetHostByNameM(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen)\r
+{\r
+       HANDLE r = NULL;\r
+       char* pa0 = NULL;\r
+       if(pa0 = AllocateStringA(strlen(name) * 4))\r
+       {\r
+               if(ConvertNameToPunycode(pa0, name))\r
+                       r = WSAAsyncGetHostByName(hWnd, wMsg, pa0, buf, buflen);\r
+       }\r
+       FreeDuplicatedString(pa0);\r
+       return r;\r
+}\r
+\r