1 /*=============================================================================
\r
5 ===============================================================================
\r
6 / Copyright (C) 1997-2007 Sota. All rights reserved.
\r
8 / Redistribution and use in source and binary forms, with or without
\r
9 / modification, are permitted provided that the following conditions
\r
12 / 1. Redistributions of source code must retain the above copyright
\r
13 / notice, this list of conditions and the following disclaimer.
\r
14 / 2. Redistributions in binary form must reproduce the above copyright
\r
15 / notice, this list of conditions and the following disclaimer in the
\r
16 / documentation and/or other materials provided with the distribution.
\r
18 / THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
\r
19 / IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
\r
20 / OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
\r
21 / IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
22 / INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
\r
23 / BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
\r
24 / USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
\r
25 / ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
\r
26 / (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
\r
27 / THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
28 /============================================================================*/
\r
32 #include <ws2tcpip.h>
\r
33 #include <windows.h>
\r
38 #include <windowsx.h>
\r
39 #include <commctrl.h>
\r
42 #include "resource.h"
\r
44 #include "punycode.h"
\r
52 // Winsock2で定義される定数と名前が重複し値が異なるため使用不可
\r
53 //#define FD_CONNECT_BIT 0x0001
\r
54 //#define FD_CLOSE_BIT 0x0002
\r
55 //#define FD_ACCEPT_BIT 0x0004
\r
56 //#define FD_READ_BIT 0x0008
\r
57 //#define FD_WRITE_BIT 0x0010
\r
78 } ASYNCSIGNALDATABASE;
\r
83 //#define MAX_SIGNAL_ENTRY 10
\r
84 //#define MAX_SIGNAL_ENTRY_DBASE 5
\r
85 #define MAX_SIGNAL_ENTRY 16
\r
86 #define MAX_SIGNAL_ENTRY_DBASE 16
\r
91 /*===== プロトタイプ =====*/
\r
93 static LRESULT CALLBACK SocketWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
\r
94 static int AskAsyncDone(SOCKET s, int *Error, int Mask);
\r
95 static int AskAsyncDoneDbase(HANDLE Async, int *Error);
\r
96 static int RegistAsyncTable(SOCKET s);
\r
97 static int RegistAsyncTableDbase(HANDLE Async);
\r
98 static int UnRegistAsyncTable(SOCKET s);
\r
99 static int UnRegistAsyncTableDbase(HANDLE Async);
\r
101 static HANDLE WSAAsyncGetHostByNameM(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen);
\r
103 static HANDLE WSAAsyncGetHostByNameIPv6M(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen, short Family);
\r
106 /*===== 外部参照 =====*/
\r
108 extern int TimeOut;
\r
111 /*===== ローカルなワーク =====*/
\r
113 static const char SocketWndClass[] = "FFFTPSocketWnd";
\r
114 static HWND hWndSocket;
\r
116 static ASYNCSIGNAL Signal[MAX_SIGNAL_ENTRY];
\r
117 static ASYNCSIGNALDATABASE SignalDbase[MAX_SIGNAL_ENTRY_DBASE];
\r
119 //static HANDLE hAsyncTblAccMutex;
\r
121 static HANDLE hAsyncTblAccMutex;
\r
133 * FFFTP_SUCCESS/FFFTP_FAIL
\r
134 *----------------------------------------------------------------------------*/
\r
136 int MakeSocketWin(HWND hWnd, HINSTANCE hInst)
\r
142 wClass.cbSize = sizeof(WNDCLASSEX);
\r
144 wClass.lpfnWndProc = SocketWndProc;
\r
145 wClass.cbClsExtra = 0;
\r
146 wClass.cbWndExtra = 0;
\r
147 wClass.hInstance = hInst;
\r
148 wClass.hIcon = NULL;
\r
149 wClass.hCursor = NULL;
\r
150 wClass.hbrBackground = (HBRUSH)CreateSolidBrush(GetSysColor(COLOR_INFOBK));
\r
151 wClass.lpszMenuName = NULL;
\r
152 wClass.lpszClassName = SocketWndClass;
\r
153 wClass.hIconSm = NULL;
\r
154 RegisterClassEx(&wClass);
\r
157 hWndSocket = CreateWindowEx(0, SocketWndClass, NULL,
\r
158 WS_BORDER | WS_POPUP,
\r
160 hWnd, NULL, hInst, NULL);
\r
162 if(hWndSocket != NULL)
\r
164 // hAsyncTblAccMutex = CreateMutex(NULL, FALSE, NULL);
\r
167 // for(i = 0; i < MAX_SIGNAL_ENTRY; i++)
\r
168 // Signal[i].Socket = INVALID_SOCKET;
\r
169 // for(i = 0; i < MAX_SIGNAL_ENTRY_DBASE; i++)
\r
170 // SignalDbase[i].Async = 0;
\r
171 if(hAsyncTblAccMutex = CreateMutex(NULL, FALSE, NULL))
\r
173 for(i = 0; i < MAX_SIGNAL_ENTRY; i++)
\r
174 Signal[i].Socket = INVALID_SOCKET;
\r
175 for(i = 0; i < MAX_SIGNAL_ENTRY_DBASE; i++)
\r
176 SignalDbase[i].Async = 0;
\r
178 Sts = FFFTP_SUCCESS;
\r
191 *----------------------------------------------------------------------------*/
\r
193 void DeleteSocketWin(void)
\r
195 // CloseHandle(hAsyncTblAccMutex);
\r
197 CloseHandle(hAsyncTblAccMutex);
\r
198 hAsyncTblAccMutex = NULL;
\r
200 if(hWndSocket != NULL)
\r
201 DestroyWindow(hWndSocket);
\r
209 * HWND hWnd : ウインドウハンドル
\r
210 * UINT message : メッセージ番号
\r
211 * WPARAM wParam : メッセージの WPARAM 引数
\r
212 * LPARAM lParam : メッセージの LPARAM 引数
\r
216 *----------------------------------------------------------------------------*/
\r
218 static LRESULT CALLBACK SocketWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
224 case WM_ASYNC_SOCKET :
\r
226 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
\r
227 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)
\r
229 if(Signal[Pos].Socket == (SOCKET)wParam)
\r
231 Signal[Pos].Error = WSAGETSELECTERROR(lParam);
\r
233 if(WSAGETSELECTERROR(lParam) != 0)
\r
234 DoPrintf("####### Signal: error (%d)", WSAGETSELECTERROR(lParam));
\r
237 switch(WSAGETSELECTEVENT(lParam))
\r
240 Signal[Pos].FdConnect = 1;
\r
242 DoPrintf("####### Signal: connect (S=%x)", Signal[Pos].Socket);
\r
247 Signal[Pos].FdClose = 1;
\r
249 DoPrintf("####### Signal: close (S=%x)", Signal[Pos].Socket);
\r
251 //SetTaskMsg("####### Signal: close (%d) (S=%x)", Pos, Signal[Pos].Socket);
\r
255 Signal[Pos].FdAccept = 1;
\r
257 DoPrintf("####### Signal: accept (S=%x)", Signal[Pos].Socket);
\r
262 Signal[Pos].FdRead = 1;
\r
264 DoPrintf("####### Signal: read (S=%x)", Signal[Pos].Socket);
\r
269 Signal[Pos].FdWrite = 1;
\r
271 DoPrintf("####### Signal: write (S=%x)", Signal[Pos].Socket);
\r
279 ReleaseMutex(hAsyncTblAccMutex);
\r
282 case WM_ASYNC_DBASE :
\r
283 // APIの仕様上ハンドルが登録される前にウィンドウメッセージが呼び出される可能性あり
\r
284 RegistAsyncTableDbase((HANDLE)wParam);
\r
286 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
\r
287 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY_DBASE; Pos++)
\r
289 if(SignalDbase[Pos].Async == (HANDLE)wParam)
\r
291 if(HIWORD(lParam) != 0)
\r
293 SignalDbase[Pos].ErrorDb = 1;
\r
295 DoPrintf("##### SignalDatabase: error");
\r
298 SignalDbase[Pos].Done = 1;
\r
300 DoPrintf("##### SignalDatabase: Done");
\r
306 ReleaseMutex(hAsyncTblAccMutex);
\r
310 return(DefWindowProc(hWnd, message, wParam, lParam));
\r
325 *----------------------------------------------------------------------------*/
\r
327 static int AskAsyncDone(SOCKET s, int *Error, int Mask)
\r
333 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
\r
336 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)
\r
338 if(Signal[Pos].Socket == s)
\r
340 *Error = Signal[Pos].Error;
\r
341 if(Signal[Pos].Error != 0)
\r
343 if((Mask & FD_CONNECT) && (Signal[Pos].FdConnect != 0))
\r
347 DoPrintf("### Ask: connect (Sts=%d, Error=%d)", Sts, *Error);
\r
350 if((Mask & FD_CLOSE) && (Signal[Pos].FdClose != 0))
\r
351 // if(Mask & FD_CLOSE)
\r
355 DoPrintf("### Ask: close (Sts=%d, Error=%d)", Sts, *Error);
\r
358 if((Mask & FD_ACCEPT) && (Signal[Pos].FdAccept != 0))
\r
360 Signal[Pos].FdAccept = 0;
\r
363 DoPrintf("### Ask: accept (Sts=%d, Error=%d)", Sts, *Error);
\r
366 if((Mask & FD_READ) && (Signal[Pos].FdRead != 0))
\r
368 Signal[Pos].FdRead = 0;
\r
371 DoPrintf("### Ask: read (Sts=%d, Error=%d)", Sts, *Error);
\r
374 if((Mask & FD_WRITE) && (Signal[Pos].FdWrite != 0))
\r
376 Signal[Pos].FdWrite = 0;
\r
379 DoPrintf("### Ask: write (Sts=%d, Error=%d)", Sts, *Error);
\r
386 ReleaseMutex(hAsyncTblAccMutex);
\r
388 if(Pos == MAX_SIGNAL_ENTRY)
\r
390 if(Mask & FD_CLOSE)
\r
396 MessageBox(GetMainHwnd(), "AskAsyncDone called with unregisterd socket.", "FFFTP inner error", MB_OK);
\r
411 *----------------------------------------------------------------------------*/
\r
413 static int AskAsyncDoneDbase(HANDLE Async, int *Error)
\r
419 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
\r
422 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY_DBASE; Pos++)
\r
424 if(SignalDbase[Pos].Async == Async)
\r
426 if(SignalDbase[Pos].Done != 0)
\r
428 *Error = SignalDbase[Pos].ErrorDb;
\r
431 DoPrintf("### Ask: Dbase (Sts=%d, Error=%d)", Sts, *Error);
\r
438 ReleaseMutex(hAsyncTblAccMutex);
\r
440 if(Pos == MAX_SIGNAL_ENTRY_DBASE)
\r
442 MessageBox(GetMainHwnd(), "AskAsyncDoneDbase called with unregisterd handle.", "FFFTP inner error", MB_OK);
\r
457 *----------------------------------------------------------------------------*/
\r
459 static int RegistAsyncTable(SOCKET s)
\r
465 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
\r
467 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)
\r
469 if(Signal[Pos].Socket == s)
\r
471 // 強制的に閉じられたソケットがあると重複する可能性あり
\r
472 // MessageBox(GetMainHwnd(), "Async socket already registerd.", "FFFTP inner error", MB_OK);
\r
474 Signal[Pos].Socket = INVALID_SOCKET;
\r
478 ReleaseMutex(hAsyncTblAccMutex);
\r
480 if(Pos == MAX_SIGNAL_ENTRY)
\r
483 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
\r
484 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)
\r
486 if(Signal[Pos].Socket == INVALID_SOCKET)
\r
489 //SetTaskMsg("############### Regist socket (%d)", Pos);
\r
491 Signal[Pos].Socket = s;
\r
492 Signal[Pos].Error = 0;
\r
493 Signal[Pos].FdConnect = 0;
\r
494 Signal[Pos].FdClose = 0;
\r
495 Signal[Pos].FdAccept = 0;
\r
496 Signal[Pos].FdRead = 0;
\r
497 Signal[Pos].FdWrite = 0;
\r
503 ReleaseMutex(hAsyncTblAccMutex);
\r
505 if(Pos == MAX_SIGNAL_ENTRY)
\r
507 MessageBox(GetMainHwnd(), "No more async regist space.", "FFFTP inner error", MB_OK);
\r
523 *----------------------------------------------------------------------------*/
\r
525 static int RegistAsyncTableDbase(HANDLE Async)
\r
531 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
\r
533 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY_DBASE; Pos++)
\r
535 if(SignalDbase[Pos].Async == Async)
\r
537 // 強制的に閉じられたハンドルがあると重複する可能性あり
\r
538 // MessageBox(GetMainHwnd(), "Async handle already registerd.", "FFFTP inner error", MB_OK);
\r
539 // APIの仕様上ハンドルが登録される前にウィンドウメッセージが呼び出される可能性あり
\r
544 ReleaseMutex(hAsyncTblAccMutex);
\r
546 if(Pos == MAX_SIGNAL_ENTRY_DBASE)
\r
549 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
\r
550 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)
\r
552 if(SignalDbase[Pos].Async == 0)
\r
555 //SetTaskMsg("############### Regist dbase (%d)", Pos);
\r
557 SignalDbase[Pos].Async = Async;
\r
558 SignalDbase[Pos].Done = 0;
\r
559 SignalDbase[Pos].ErrorDb = 0;
\r
565 ReleaseMutex(hAsyncTblAccMutex);
\r
567 if(Pos == MAX_SIGNAL_ENTRY_DBASE)
\r
569 MessageBox(GetMainHwnd(), "No more async dbase regist space.", "FFFTP inner error", MB_OK);
\r
585 *----------------------------------------------------------------------------*/
\r
587 static int UnRegistAsyncTable(SOCKET s)
\r
593 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
\r
595 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)
\r
597 if(Signal[Pos].Socket == s)
\r
600 //SetTaskMsg("############### UnRegist socket (%d)", Pos);
\r
602 Signal[Pos].Socket = INVALID_SOCKET;
\r
608 ReleaseMutex(hAsyncTblAccMutex);
\r
620 *----------------------------------------------------------------------------*/
\r
622 static int UnRegistAsyncTableDbase(HANDLE Async)
\r
628 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
\r
630 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY_DBASE; Pos++)
\r
632 if(SignalDbase[Pos].Async == Async)
\r
635 //SetTaskMsg("############### UnRegist dbase (%d)", Pos);
\r
637 SignalDbase[Pos].Async = 0;
\r
643 ReleaseMutex(hAsyncTblAccMutex);
\r
654 struct hostent *do_gethostbyname(const char *Name, char *Buf, int Len, int *CancelCheckWork)
\r
657 struct hostent *Ret;
\r
662 DoPrintf("# Start gethostbyname");
\r
666 // *CancelCheckWork = NO;
\r
669 // hAsync = WSAAsyncGetHostByName(hWndSocket, WM_ASYNC_DBASE, Name, Buf, Len);
\r
671 // hAsync = WSAAsyncGetHostByNameM(hWndSocket, WM_ASYNC_DBASE, Name, Buf, Len);
\r
672 hAsync = WSAAsyncGetHostByNameIPv6M(hWndSocket, WM_ASYNC_DBASE, Name, Buf, Len, AF_INET);
\r
675 RegistAsyncTableDbase(hAsync);
\r
676 while((*CancelCheckWork == NO) && (AskAsyncDoneDbase(hAsync, &Error) != YES))
\r
679 if(BackgrndMessageProc() == YES)
\r
680 *CancelCheckWork = YES;
\r
683 if(*CancelCheckWork == YES)
\r
685 WSACancelAsyncRequest(hAsync);
\r
687 else if(Error == 0)
\r
689 Ret = (struct hostent *)Buf;
\r
691 UnRegistAsyncTableDbase(hAsync);
\r
695 return(gethostbyname(Name));
\r
703 SOCKET do_socket(int af, int type, int protocol)
\r
707 Ret = socket(af, type, protocol);
\r
708 if(Ret != INVALID_SOCKET)
\r
710 RegistAsyncTable(Ret);
\r
713 DoPrintf("# do_socket (S=%x)", Ret);
\r
720 int do_closesocket(SOCKET s)
\r
725 int CancelCheckWork;
\r
728 DoPrintf("# Start close (S=%x)", s);
\r
730 CancelCheckWork = NO;
\r
733 WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, 0);
\r
734 UnRegistAsyncTable(s);
\r
736 // Ret = closesocket(s);
\r
737 Ret = closesocketS(s);
\r
738 if(Ret == SOCKET_ERROR)
\r
741 while((CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_CLOSE) != YES))
\r
744 if(BackgrndMessageProc() == YES)
\r
745 CancelCheckWork = YES;
\r
748 if((CancelCheckWork == NO) && (Error == 0))
\r
753 // WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, 0);
\r
754 if(BackgrndMessageProc() == YES)
\r
755 CancelCheckWork = YES;
\r
757 // UnRegistAsyncTable(s);
\r
760 DoPrintf("# Exit close");
\r
764 return(closesocket(s));
\r
773 int do_connect(SOCKET s, const struct sockaddr *name, int namelen, int *CancelCheckWork)
\r
780 DoPrintf("# Start connect (S=%x)", s);
\r
783 // *CancelCheckWork = NO;
\r
786 DoPrintf("## Async set: FD_CONNECT|FD_CLOSE|FD_ACCEPT|FD_READ|FD_WRITE");
\r
788 // 高速化のためFD_READとFD_WRITEを使用しない
\r
789 // Ret = WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, FD_CONNECT | FD_CLOSE | FD_ACCEPT | FD_READ | FD_WRITE);
\r
790 Ret = WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, FD_CONNECT | FD_CLOSE | FD_ACCEPT);
\r
791 if(Ret != SOCKET_ERROR)
\r
793 Ret = connect(s, name, namelen);
\r
794 if(Ret == SOCKET_ERROR)
\r
799 while((*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_CONNECT) != YES))
\r
802 if(BackgrndMessageProc() == YES)
\r
803 *CancelCheckWork = YES;
\r
806 if(*CancelCheckWork == YES)
\r
812 // Error = WSAGetLastError();
\r
813 DoPrintf("#### Connect: Error=%d", Error);
\r
816 while((Ret != 0) && (Error == WSAEWOULDBLOCK));
\r
820 DoPrintf("#### Connect: AsyncSelect error (%d)", WSAGetLastError());
\r
823 DoPrintf("# Exit connect (%d)", Ret);
\r
827 return(connect(s, name, namelen));
\r
835 int do_listen(SOCKET s, int backlog)
\r
841 DoPrintf("# Start listen (S=%x)", s);
\r
842 DoPrintf("## Async set: FD_CLOSE|FD_ACCEPT");
\r
845 Ret = WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, FD_CLOSE | FD_ACCEPT);
\r
846 if(Ret != SOCKET_ERROR)
\r
847 Ret = listen(s, backlog);
\r
850 DoPrintf("# Exit listen (%d)", Ret);
\r
857 SOCKET do_accept(SOCKET s, struct sockaddr *addr, int *addrlen)
\r
861 int CancelCheckWork;
\r
865 DoPrintf("# Start accept (S=%x)", s);
\r
867 CancelCheckWork = NO;
\r
868 Ret2 = INVALID_SOCKET;
\r
871 while((CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_ACCEPT) != YES))
\r
873 if(AskAsyncDone(s, &Error, FD_CLOSE) == YES)
\r
879 if(BackgrndMessageProc() == YES)
\r
880 CancelCheckWork = YES;
\r
883 if((CancelCheckWork == NO) && (Error == 0))
\r
887 Ret2 = accept(s, addr, addrlen);
\r
888 if(Ret2 != INVALID_SOCKET)
\r
891 DoPrintf("## do_sccept (S=%x)", Ret2);
\r
892 DoPrintf("## Async set: FD_CONNECT|FD_CLOSE|FD_ACCEPT|FD_READ|FD_WRITE");
\r
894 RegistAsyncTable(Ret2);
\r
895 if(WSAAsyncSelect(Ret2, hWndSocket, WM_ASYNC_SOCKET, FD_CONNECT | FD_CLOSE | FD_ACCEPT | FD_READ | FD_WRITE) == SOCKET_ERROR)
\r
897 do_closesocket(Ret2);
\r
898 Ret2 = INVALID_SOCKET;
\r
902 Error = WSAGetLastError();
\r
904 if(BackgrndMessageProc() == YES)
\r
907 while(Error == WSAEWOULDBLOCK);
\r
911 DoPrintf("# Exit accept");
\r
915 return(accept(s, addr, addrlen));
\r
922 /*----- recv相当の関数 --------------------------------------------------------
\r
926 * char *buf : データを読み込むバッファ
\r
928 * int flags : recvに与えるフラグ
\r
929 * int *TimeOutErr : タイムアウトしたかどうかを返すワーク
\r
932 * int : recvの戻り値と同じ
\r
935 * タイムアウトの時は TimeOut=YES、Ret=SOCKET_ERROR になる
\r
936 *----------------------------------------------------------------------------*/
\r
937 int do_recv(SOCKET s, char *buf, int len, int flags, int *TimeOutErr, int *CancelCheckWork)
\r
946 DoPrintf("# Start recv (S=%x)", s);
\r
950 // *CancelCheckWork = NO;
\r
951 Ret = SOCKET_ERROR;
\r
958 // OpenSSLでは受信確認はFD_READが複数回受信される可能性がある
\r
959 // while((*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_READ) != YES))
\r
960 // 短時間にFD_READが2回以上通知される対策
\r
961 // while(!IsSSLAttached(s) && (*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_READ) != YES))
\r
963 // if(AskAsyncDone(s, &Error, FD_CLOSE) == YES)
\r
969 // if(BackgrndMessageProc() == YES)
\r
970 // *CancelCheckWork = YES;
\r
971 // else if(TimeOut != 0)
\r
973 // time(&ElapseTime);
\r
974 // ElapseTime -= StartTime;
\r
975 // if(ElapseTime >= TimeOut)
\r
977 // DoPrintf("do_recv timed out");
\r
978 // *TimeOutErr = YES;
\r
979 // *CancelCheckWork = YES;
\r
984 if(/*(Ret != 0) && */(Error == 0) && (*CancelCheckWork == NO) && (*TimeOutErr == NO))
\r
989 DoPrintf("## recv()");
\r
993 // Ret = recv(s, buf, len, flags);
\r
994 Ret = recvS(s, buf, len, flags);
\r
995 if(Ret != SOCKET_ERROR)
\r
997 Error = WSAGetLastError();
\r
999 if(BackgrndMessageProc() == YES)
\r
1002 // 受信確認をバイパスしたためここでタイムアウトの確認
\r
1003 if(BackgrndMessageProc() == YES)
\r
1004 *CancelCheckWork = YES;
\r
1005 else if(TimeOut != 0)
\r
1007 time(&ElapseTime);
\r
1008 ElapseTime -= StartTime;
\r
1009 if(ElapseTime >= TimeOut)
\r
1011 DoPrintf("do_recv timed out");
\r
1012 *TimeOutErr = YES;
\r
1013 *CancelCheckWork = YES;
\r
1016 if(*CancelCheckWork == YES)
\r
1019 while(Error == WSAEWOULDBLOCK);
\r
1022 if(BackgrndMessageProc() == YES)
\r
1023 Ret = SOCKET_ERROR;
\r
1026 DoPrintf("# Exit recv (%d)", Ret);
\r
1030 return(recv(s, buf, len, flags));
\r
1036 int do_send(SOCKET s, const char *buf, int len, int flags, int *TimeOutErr, int *CancelCheckWork)
\r
1041 time_t ElapseTime;
\r
1045 DoPrintf("# Start send (S=%x)", s);
\r
1049 // *CancelCheckWork = NO;
\r
1050 Ret = SOCKET_ERROR;
\r
1057 DoPrintf("## Async set: FD_CONNECT|FD_CLOSE|FD_ACCEPT|FD_READ|FD_WRITE");
\r
1059 // Windows 2000でFD_WRITEが通知されないことがあるバグ修正
\r
1060 // 毎回通知されたのはNT 4.0までのバグであり仕様ではない
\r
1061 // XP以降は互換性のためか毎回通知される
\r
1062 // WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, FD_CONNECT | FD_CLOSE | FD_ACCEPT | FD_READ | FD_WRITE);
\r
1063 if(BackgrndMessageProc() == YES)
\r
1064 *CancelCheckWork = YES;
\r
1067 // 送信バッファの空き確認には影響しないが念のため
\r
1068 // while((*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_WRITE) != YES))
\r
1069 // Windows 2000でFD_WRITEが通知されないことがあるバグ修正
\r
1070 // while(!IsSSLAttached(s) && (*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_WRITE) != YES))
\r
1072 // if(AskAsyncDone(s, &Error, FD_CLOSE) == YES)
\r
1079 // if(BackgrndMessageProc() == YES)
\r
1080 // *CancelCheckWork = YES;
\r
1081 // else if(TimeOut != 0)
\r
1083 // time(&ElapseTime);
\r
1084 // ElapseTime -= StartTime;
\r
1085 // if(ElapseTime >= TimeOut)
\r
1087 // DoPrintf("do_write timed out");
\r
1088 // *TimeOutErr = YES;
\r
1089 // *CancelCheckWork = YES;
\r
1094 if((Error == 0) && (*CancelCheckWork == NO) && (*TimeOutErr == NO))
\r
1099 DoPrintf("## send()");
\r
1103 // Ret = send(s, buf, len, flags);
\r
1104 Ret = sendS(s, buf, len, flags);
\r
1105 if(Ret != SOCKET_ERROR)
\r
1108 DoPrintf("## send() OK");
\r
1112 Error = WSAGetLastError();
\r
1114 if(BackgrndMessageProc() == YES)
\r
1117 // 送信バッファ確認をバイパスしたためここでタイムアウトの確認
\r
1118 if(BackgrndMessageProc() == YES)
\r
1119 *CancelCheckWork = YES;
\r
1120 else if(TimeOut != 0)
\r
1122 time(&ElapseTime);
\r
1123 ElapseTime -= StartTime;
\r
1124 if(ElapseTime >= TimeOut)
\r
1126 DoPrintf("do_recv timed out");
\r
1127 *TimeOutErr = YES;
\r
1128 *CancelCheckWork = YES;
\r
1131 if(*CancelCheckWork == YES)
\r
1134 while(Error == WSAEWOULDBLOCK);
\r
1137 if(BackgrndMessageProc() == YES)
\r
1138 Ret = SOCKET_ERROR;
\r
1141 DoPrintf("# Exit send (%d)", Ret);
\r
1145 return(send(s, buf, len, flags));
\r
1151 void RemoveReceivedData(SOCKET s)
\r
1156 while((len = recvS(s, buf, sizeof(buf), MSG_PEEK)) >= 0)
\r
1158 AskAsyncDone(s, &Error, FD_READ);
\r
1159 recvS(s, buf, len, 0);
\r
1170 * FFFTP_SUCCESS/FFFTP_FAIL
\r
1171 *----------------------------------------------------------------------------*/
\r
1173 int CheckClosedAndReconnect(void)
\r
1178 //SetTaskMsg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
\r
1180 Sts = FFFTP_SUCCESS;
\r
1181 if(AskAsyncDone(AskCmdCtrlSkt(), &Error, FD_CLOSE) == YES)
\r
1183 Sts = ReConnectCmdSkt();
\r
1201 } GETHOSTBYNAMEDATA;
\r
1203 static DWORD WINAPI WSAAsyncGetHostByNameIPv6ThreadProc(LPVOID lpParameter)
\r
1205 GETHOSTBYNAMEDATA* pData;
\r
1206 struct hostent* pHost;
\r
1207 struct addrinfo* pAddr;
\r
1208 struct addrinfo* p;
\r
1210 pData = (GETHOSTBYNAMEDATA*)lpParameter;
\r
1211 if(getaddrinfo(pData->name, NULL, NULL, &pAddr) == 0)
\r
1216 if(p->ai_family == pData->Family)
\r
1218 switch(p->ai_family)
\r
1221 pHost = (struct hostent*)pData->buf;
\r
1222 if((size_t)pData->buflen >= sizeof(struct hostent) + sizeof(char*) * 2 + sizeof(struct in_addr)
\r
1223 && p->ai_addrlen >= sizeof(struct sockaddr_in))
\r
1225 pHost->h_name = NULL;
\r
1226 pHost->h_aliases = NULL;
\r
1227 pHost->h_addrtype = p->ai_family;
\r
1228 pHost->h_length = sizeof(struct in_addr);
\r
1229 pHost->h_addr_list = (char**)(&pHost[1]);
\r
1230 pHost->h_addr_list[0] = (char*)(&pHost->h_addr_list[2]);
\r
1231 pHost->h_addr_list[1] = NULL;
\r
1232 memcpy(pHost->h_addr_list[0], &((struct sockaddr_in*)p->ai_addr)->sin_addr, sizeof(struct in_addr));
\r
1233 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(sizeof(struct hostent) + sizeof(char*) * 2 + p->ai_addrlen));
\r
1236 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(WSAENOBUFS << 16));
\r
1239 pHost = (struct hostent*)pData->buf;
\r
1240 if((size_t)pData->buflen >= sizeof(struct hostent) + sizeof(char*) * 2 + sizeof(struct in6_addr)
\r
1241 && p->ai_addrlen >= sizeof(struct sockaddr_in6))
\r
1243 pHost->h_name = NULL;
\r
1244 pHost->h_aliases = NULL;
\r
1245 pHost->h_addrtype = p->ai_family;
\r
1246 pHost->h_length = sizeof(struct in6_addr);
\r
1247 pHost->h_addr_list = (char**)(&pHost[1]);
\r
1248 pHost->h_addr_list[0] = (char*)(&pHost->h_addr_list[2]);
\r
1249 pHost->h_addr_list[1] = NULL;
\r
1250 memcpy(pHost->h_addr_list[0], &((struct sockaddr_in6*)p->ai_addr)->sin6_addr, sizeof(struct in6_addr));
\r
1251 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(sizeof(struct hostent) + sizeof(char*) * 2 + p->ai_addrlen));
\r
1254 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(WSAENOBUFS << 16));
\r
1263 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(ERROR_INVALID_FUNCTION << 16));
\r
1264 freeaddrinfo(pAddr);
\r
1267 PostMessage(pData->hWnd, pData->wMsg, (WPARAM)pData->h, (LPARAM)(ERROR_INVALID_FUNCTION << 16));
\r
1268 free(pData->name);
\r
1270 // CreateThreadが返すハンドルが重複するのを回避
\r
1275 // IPv6対応のWSAAsyncGetHostByName相当の関数
\r
1276 // FamilyにはAF_INETまたはAF_INET6を指定可能
\r
1278 static HANDLE WSAAsyncGetHostByNameIPv6(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen, short Family)
\r
1281 GETHOSTBYNAMEDATA* pData;
\r
1283 if(pData = malloc(sizeof(GETHOSTBYNAMEDATA)))
\r
1285 pData->hWnd = hWnd;
\r
1286 pData->wMsg = wMsg;
\r
1287 if(pData->name = malloc(sizeof(char) * (strlen(name) + 1)))
\r
1289 strcpy(pData->name, name);
\r
1291 pData->buflen = buflen;
\r
1292 pData->Family = Family;
\r
1293 if(pData->h = CreateThread(NULL, 0, WSAAsyncGetHostByNameIPv6ThreadProc, pData, CREATE_SUSPENDED, NULL))
\r
1295 ResumeThread(pData->h);
\r
1296 hResult = pData->h;
\r
1305 free(pData->name);
\r
1312 // WSAAsyncGetHostByNameIPv6用のWSACancelAsyncRequest相当の関数
\r
1313 int WSACancelAsyncRequestIPv6(HANDLE hAsyncTaskHandle)
\r
1316 Result = SOCKET_ERROR;
\r
1317 if(TerminateThread(hAsyncTaskHandle, 0))
\r
1324 static BOOL ConvertStringToPunycode(LPSTR Output, DWORD Count, LPCSTR Input)
\r
1327 punycode_uint* pUnicode;
\r
1330 LPCSTR InputString;
\r
1331 punycode_uint Length;
\r
1332 punycode_uint OutputLength;
\r
1334 if(pUnicode = malloc(sizeof(punycode_uint) * strlen(Input)))
\r
1338 InputString = Input;
\r
1340 while(*InputString != '\0')
\r
1342 *p = (punycode_uint)GetNextCharM(InputString, &InputString);
\r
1350 if(Count >= strlen("xn--") + 1)
\r
1352 strcpy(Output, "xn--");
\r
1353 OutputLength = Count - strlen("xn--");
\r
1354 if(punycode_encode(Length, pUnicode, NULL, (punycode_uint*)&OutputLength, Output + strlen("xn--")) == punycode_success)
\r
1356 Output[strlen("xn--") + OutputLength] = '\0';
\r
1365 if(Count >= strlen(Input) + 1)
\r
1367 strcpy(Output, Input);
\r
1374 static BOOL ConvertNameToPunycode(LPSTR Output, LPCSTR Input)
\r
1383 Length = strlen(Input);
\r
1384 if(pm0 = AllocateStringM(Length + 1))
\r
1386 if(pm1 = AllocateStringM(Length * 4 + 1))
\r
1388 strcpy(pm0, Input);
\r
1392 if(pNext = strchr(p, '.'))
\r
1397 if(ConvertStringToPunycode(pm1, Length * 4, p))
\r
1398 strcat(Output, pm1);
\r
1400 strcat(Output, ".");
\r
1404 FreeDuplicatedString(pm1);
\r
1406 FreeDuplicatedString(pm0);
\r
1411 static HANDLE WSAAsyncGetHostByNameM(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen)
\r
1415 if(pa0 = AllocateStringA(strlen(name) * 4))
\r
1417 if(ConvertNameToPunycode(pa0, name))
\r
1418 r = WSAAsyncGetHostByName(hWnd, wMsg, pa0, buf, buflen);
\r
1420 FreeDuplicatedString(pa0);
\r
1424 static HANDLE WSAAsyncGetHostByNameIPv6M(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen, short Family)
\r
1428 if(pa0 = AllocateStringA(strlen(name) * 4))
\r
1430 if(ConvertNameToPunycode(pa0, name))
\r
1431 r = WSAAsyncGetHostByNameIPv6(hWnd, wMsg, pa0, buf, buflen, Family);
\r
1433 FreeDuplicatedString(pa0);
\r