OSDN Git Service

Fix bugs of simultaneous connection.
[ffftp/ffftp.git] / socket.c
1 /*=============================================================================\r
2 *\r
3 *                                                                       ソケット\r
4 *\r
5 ===============================================================================\r
6 / Copyright (C) 1997-2007 Sota. All rights reserved.\r
7 /\r
8 / Redistribution and use in source and binary forms, with or without \r
9 / modification, are permitted provided that the following conditions \r
10 / are met:\r
11 /\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
17 /\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
29 \r
30 #define STRICT\r
31 // IPv6対応\r
32 #include <winsock2.h>\r
33 #include <windows.h>\r
34 #include <stdio.h>\r
35 #include <stdlib.h>\r
36 #include <string.h>\r
37 #include <time.h>\r
38 #include <windowsx.h>\r
39 #include <commctrl.h>\r
40 \r
41 #include "common.h"\r
42 #include "resource.h"\r
43 \r
44 #define USE_THIS        1\r
45 #define DBG_MSG         0\r
46 \r
47 \r
48 \r
49 \r
50 // Winsock2で定義される定数と名前が重複し値が異なるため使用不可\r
51 //#define FD_CONNECT_BIT                0x0001\r
52 //#define FD_CLOSE_BIT          0x0002\r
53 //#define FD_ACCEPT_BIT         0x0004\r
54 //#define FD_READ_BIT                   0x0008\r
55 //#define FD_WRITE_BIT          0x0010\r
56 \r
57 \r
58 \r
59 \r
60 \r
61 typedef struct {\r
62         SOCKET Socket;\r
63         int FdConnect;\r
64         int FdClose;\r
65         int FdAccept;\r
66         int FdRead;\r
67         int FdWrite;\r
68         int Error;\r
69 } ASYNCSIGNAL;\r
70 \r
71 \r
72 typedef struct {\r
73         HANDLE Async;\r
74         int Done;\r
75         int ErrorDb;\r
76 } ASYNCSIGNALDATABASE;\r
77 \r
78 \r
79 // スレッド衝突のバグ修正\r
80 // 念のためテーブルを増量\r
81 //#define MAX_SIGNAL_ENTRY              10\r
82 //#define MAX_SIGNAL_ENTRY_DBASE        5\r
83 #define MAX_SIGNAL_ENTRY                16\r
84 #define MAX_SIGNAL_ENTRY_DBASE  16\r
85 \r
86 \r
87 \r
88 \r
89 /*===== プロトタイプ =====*/\r
90 \r
91 static LRESULT CALLBACK SocketWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);\r
92 static int AskAsyncDone(SOCKET s, int *Error, int Mask);\r
93 static int AskAsyncDoneDbase(HANDLE Async, int *Error);\r
94 static int RegistAsyncTable(SOCKET s);\r
95 static int RegistAsyncTableDbase(HANDLE Async);\r
96 static int UnRegistAsyncTable(SOCKET s);\r
97 static int UnRegistAsyncTableDbase(HANDLE Async);\r
98 \r
99 \r
100 /*===== 外部参照 =====*/\r
101 \r
102 extern int TimeOut;\r
103 \r
104 \r
105 /*===== ローカルなワーク =====*/\r
106 \r
107 static const char SocketWndClass[] = "FFFTPSocketWnd";\r
108 static HWND hWndSocket;\r
109 \r
110 static ASYNCSIGNAL Signal[MAX_SIGNAL_ENTRY];\r
111 static ASYNCSIGNALDATABASE SignalDbase[MAX_SIGNAL_ENTRY_DBASE];\r
112 \r
113 //static HANDLE hAsyncTblAccMutex;\r
114 // スレッド衝突のバグ修正\r
115 static HANDLE hAsyncTblAccMutex;\r
116 \r
117 \r
118 \r
119 \r
120 \r
121 /*----- \r
122 *\r
123 *       Parameter\r
124 *\r
125 *       Return Value\r
126 *               int ステータス\r
127 *                       FFFTP_SUCCESS/FFFTP_FAIL\r
128 *----------------------------------------------------------------------------*/\r
129 \r
130 int MakeSocketWin(HWND hWnd, HINSTANCE hInst)\r
131 {\r
132         int i;\r
133         int Sts;\r
134         WNDCLASSEX wClass;\r
135 \r
136         wClass.cbSize        = sizeof(WNDCLASSEX);\r
137         wClass.style         = 0;\r
138         wClass.lpfnWndProc   = SocketWndProc;\r
139         wClass.cbClsExtra    = 0;\r
140         wClass.cbWndExtra    = 0;\r
141         wClass.hInstance     = hInst;\r
142         wClass.hIcon         = NULL;\r
143         wClass.hCursor       = NULL;\r
144         wClass.hbrBackground = (HBRUSH)CreateSolidBrush(GetSysColor(COLOR_INFOBK));\r
145         wClass.lpszMenuName  = NULL;\r
146         wClass.lpszClassName = SocketWndClass;\r
147         wClass.hIconSm       = NULL;\r
148         RegisterClassEx(&wClass);\r
149 \r
150         Sts = FFFTP_FAIL;\r
151         hWndSocket = CreateWindowEx(0, SocketWndClass, NULL,\r
152                         WS_BORDER | WS_POPUP,\r
153                         0, 0, 0, 0,\r
154                         hWnd, NULL, hInst, NULL);\r
155 \r
156         if(hWndSocket != NULL)\r
157         {\r
158 //              hAsyncTblAccMutex = CreateMutex(NULL, FALSE, NULL);\r
159 \r
160                 // スレッド衝突のバグ修正\r
161 //              for(i = 0; i < MAX_SIGNAL_ENTRY; i++)\r
162 //                      Signal[i].Socket = INVALID_SOCKET;\r
163 //              for(i = 0; i < MAX_SIGNAL_ENTRY_DBASE; i++)\r
164 //                      SignalDbase[i].Async = 0;\r
165                 if(hAsyncTblAccMutex = CreateMutex(NULL, FALSE, NULL))\r
166                 {\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                 }\r
172                 Sts = FFFTP_SUCCESS;\r
173         }\r
174         return(Sts);\r
175 }\r
176 \r
177 \r
178 /*----- \r
179 *\r
180 *       Parameter\r
181 *               なし\r
182 *\r
183 *       Return Value\r
184 *               なし\r
185 *----------------------------------------------------------------------------*/\r
186 \r
187 void DeleteSocketWin(void)\r
188 {\r
189 //      CloseHandle(hAsyncTblAccMutex);\r
190         // スレッド衝突のバグ修正\r
191         CloseHandle(hAsyncTblAccMutex);\r
192         hAsyncTblAccMutex = NULL;\r
193 \r
194         if(hWndSocket != NULL)\r
195                 DestroyWindow(hWndSocket);\r
196         return;\r
197 }\r
198 \r
199 \r
200 /*----- \r
201 *\r
202 *       Parameter\r
203 *               HWND hWnd : ウインドウハンドル\r
204 *               UINT message : メッセージ番号\r
205 *               WPARAM wParam : メッセージの WPARAM 引数\r
206 *               LPARAM lParam : メッセージの LPARAM 引数\r
207 *\r
208 *       Return Value\r
209 *               BOOL TRUE/FALSE\r
210 *----------------------------------------------------------------------------*/\r
211 \r
212 static LRESULT CALLBACK SocketWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\r
213 {\r
214         int Pos;\r
215 \r
216         switch(message)\r
217         {\r
218                 case WM_ASYNC_SOCKET :\r
219                         // スレッド衝突のバグ修正\r
220                         WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
221                         for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)\r
222                         {\r
223                                 if(Signal[Pos].Socket == (SOCKET)wParam)\r
224                                 {\r
225                                         Signal[Pos].Error = WSAGETSELECTERROR(lParam);\r
226 #if DBG_MSG\r
227                                         if(WSAGETSELECTERROR(lParam) != 0)\r
228                                                 DoPrintf("####### Signal: error (%d)", WSAGETSELECTERROR(lParam));\r
229 #endif\r
230 \r
231                                         switch(WSAGETSELECTEVENT(lParam))\r
232                                         {\r
233                                                 case FD_CONNECT :\r
234                                                         Signal[Pos].FdConnect = 1;\r
235 #if DBG_MSG\r
236                                                         DoPrintf("####### Signal: connect (S=%x)", Signal[Pos].Socket);\r
237 #endif\r
238                                                         break;\r
239 \r
240                                                 case FD_CLOSE :\r
241                                                         Signal[Pos].FdClose = 1;\r
242 #if DBG_MSG\r
243                                                         DoPrintf("####### Signal: close (S=%x)", Signal[Pos].Socket);\r
244 #endif\r
245 //SetTaskMsg("####### Signal: close (%d) (S=%x)", Pos, Signal[Pos].Socket);\r
246                                                         break;\r
247 \r
248                                                 case FD_ACCEPT :\r
249                                                         Signal[Pos].FdAccept = 1;\r
250 #if DBG_MSG\r
251                                                         DoPrintf("####### Signal: accept (S=%x)", Signal[Pos].Socket);\r
252 #endif\r
253                                                         break;\r
254 \r
255                                                 case FD_READ :\r
256                                                         Signal[Pos].FdRead = 1;\r
257 #if DBG_MSG\r
258                                                         DoPrintf("####### Signal: read (S=%x)", Signal[Pos].Socket);\r
259 #endif\r
260                                                         break;\r
261 \r
262                                                 case FD_WRITE :\r
263                                                         Signal[Pos].FdWrite = 1;\r
264 #if DBG_MSG\r
265                                                         DoPrintf("####### Signal: write (S=%x)", Signal[Pos].Socket);\r
266 #endif\r
267                                                         break;\r
268                                         }\r
269                                         break;\r
270                                 }\r
271                         }\r
272                         // スレッド衝突のバグ修正\r
273                         ReleaseMutex(hAsyncTblAccMutex);\r
274                         break;\r
275 \r
276                 case WM_ASYNC_DBASE :\r
277                         // APIの仕様上ハンドルが登録される前にウィンドウメッセージが呼び出される可能性あり\r
278                         RegistAsyncTableDbase((HANDLE)wParam);\r
279                         // スレッド衝突のバグ修正\r
280                         WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
281                         for(Pos = 0; Pos < MAX_SIGNAL_ENTRY_DBASE; Pos++)\r
282                         {\r
283                                 if(SignalDbase[Pos].Async == (HANDLE)wParam)\r
284                                 {\r
285                                         if(HIWORD(lParam) != 0)\r
286                                         {\r
287                                                 SignalDbase[Pos].ErrorDb = 1;\r
288 #if DBG_MSG\r
289                                                 DoPrintf("##### SignalDatabase: error");\r
290 #endif\r
291                                         }\r
292                                         SignalDbase[Pos].Done = 1;\r
293 #if DBG_MSG\r
294                                         DoPrintf("##### SignalDatabase: Done");\r
295 #endif\r
296                                         break;\r
297                                 }\r
298                         }\r
299                         // スレッド衝突のバグ修正\r
300                         ReleaseMutex(hAsyncTblAccMutex);\r
301                         break;\r
302 \r
303                 default :\r
304                         return(DefWindowProc(hWnd, message, wParam, lParam));\r
305         }\r
306     return(0);\r
307 }\r
308 \r
309 \r
310 \r
311 \r
312 /*----- \r
313 *\r
314 *       Parameter\r
315 *               \r
316 *\r
317 *       Return Value\r
318 *               \r
319 *----------------------------------------------------------------------------*/\r
320 \r
321 static int AskAsyncDone(SOCKET s, int *Error, int Mask)\r
322 {\r
323         int Sts;\r
324         int Pos;\r
325 \r
326         // スレッド衝突のバグ修正\r
327         WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
328         Sts = NO;\r
329         *Error = 0;\r
330         for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)\r
331         {\r
332                 if(Signal[Pos].Socket == s)\r
333                 {\r
334                         *Error = Signal[Pos].Error;\r
335                         if(Signal[Pos].Error != 0)\r
336                                 Sts = YES;\r
337                         if((Mask & FD_CONNECT) && (Signal[Pos].FdConnect != 0))\r
338                         {\r
339                                 Sts = YES;\r
340 #if DBG_MSG\r
341                                 DoPrintf("### Ask: connect (Sts=%d, Error=%d)", Sts, *Error);\r
342 #endif\r
343                         }\r
344                         if((Mask & FD_CLOSE) && (Signal[Pos].FdClose != 0))\r
345 //                      if(Mask & FD_CLOSE)\r
346                         {\r
347                                 Sts = YES;\r
348 #if DBG_MSG\r
349                                 DoPrintf("### Ask: close (Sts=%d, Error=%d)", Sts, *Error);\r
350 #endif\r
351                         }\r
352                         if((Mask & FD_ACCEPT) && (Signal[Pos].FdAccept != 0))\r
353                         {\r
354                                 Signal[Pos].FdAccept = 0;\r
355                                 Sts = YES;\r
356 #if DBG_MSG\r
357                                 DoPrintf("### Ask: accept (Sts=%d, Error=%d)", Sts, *Error);\r
358 #endif\r
359                         }\r
360                         if((Mask & FD_READ) && (Signal[Pos].FdRead != 0))\r
361                         {\r
362                                 Signal[Pos].FdRead = 0;\r
363                                 Sts = YES;\r
364 #if DBG_MSG\r
365                                 DoPrintf("### Ask: read (Sts=%d, Error=%d)", Sts, *Error);\r
366 #endif\r
367                         }\r
368                         if((Mask & FD_WRITE) && (Signal[Pos].FdWrite != 0))\r
369                         {\r
370                                 Signal[Pos].FdWrite = 0;\r
371                                 Sts = YES;\r
372 #if DBG_MSG\r
373                                 DoPrintf("### Ask: write (Sts=%d, Error=%d)", Sts, *Error);\r
374 #endif\r
375                         }\r
376                         break;\r
377                 }\r
378         }\r
379         // スレッド衝突のバグ修正\r
380         ReleaseMutex(hAsyncTblAccMutex);\r
381 \r
382         if(Pos == MAX_SIGNAL_ENTRY)\r
383         {\r
384                 if(Mask & FD_CLOSE)\r
385                 {\r
386                                 Sts = YES;\r
387                 }\r
388                 else\r
389                 {\r
390                         MessageBox(GetMainHwnd(), "AskAsyncDone called with unregisterd socket.", "FFFTP inner error", MB_OK);\r
391                         exit(1);\r
392                 }\r
393         }\r
394         return(Sts);\r
395 }\r
396 \r
397 \r
398 /*----- \r
399 *\r
400 *       Parameter\r
401 *               \r
402 *\r
403 *       Return Value\r
404 *               \r
405 *----------------------------------------------------------------------------*/\r
406 \r
407 static int AskAsyncDoneDbase(HANDLE Async, int *Error)\r
408 {\r
409         int Sts;\r
410         int Pos;\r
411 \r
412         // スレッド衝突のバグ修正\r
413         WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
414         Sts = NO;\r
415         *Error = 0;\r
416         for(Pos = 0; Pos < MAX_SIGNAL_ENTRY_DBASE; Pos++)\r
417         {\r
418                 if(SignalDbase[Pos].Async == Async)\r
419                 {\r
420                         if(SignalDbase[Pos].Done != 0)\r
421                         {\r
422                                 *Error = SignalDbase[Pos].ErrorDb;\r
423                                 Sts = YES;\r
424 #if DBG_MSG\r
425                                 DoPrintf("### Ask: Dbase (Sts=%d, Error=%d)", Sts, *Error);\r
426 #endif\r
427                         }\r
428                         break;\r
429                 }\r
430         }\r
431         // スレッド衝突のバグ修正\r
432         ReleaseMutex(hAsyncTblAccMutex);\r
433 \r
434         if(Pos == MAX_SIGNAL_ENTRY_DBASE)\r
435         {\r
436                 MessageBox(GetMainHwnd(), "AskAsyncDoneDbase called with unregisterd handle.", "FFFTP inner error", MB_OK);\r
437                 exit(1);\r
438         }\r
439         return(Sts);\r
440 }\r
441 \r
442 \r
443 \r
444 /*----- \r
445 *\r
446 *       Parameter\r
447 *               \r
448 *\r
449 *       Return Value\r
450 *               \r
451 *----------------------------------------------------------------------------*/\r
452 \r
453 static int RegistAsyncTable(SOCKET s)\r
454 {\r
455         int Sts;\r
456         int Pos;\r
457 \r
458         // スレッド衝突のバグ修正\r
459         WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
460         Sts = NO;\r
461         for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)\r
462         {\r
463                 if(Signal[Pos].Socket == s)\r
464                 {\r
465                         // 強制的に閉じられたソケットがあると重複する可能性あり\r
466 //                      MessageBox(GetMainHwnd(), "Async socket already registerd.", "FFFTP inner error", MB_OK);\r
467 //                      break;\r
468                         Signal[Pos].Socket = INVALID_SOCKET;\r
469                 }\r
470         }\r
471         // スレッド衝突のバグ修正\r
472         ReleaseMutex(hAsyncTblAccMutex);\r
473 \r
474         if(Pos == MAX_SIGNAL_ENTRY)\r
475         {\r
476                 // スレッド衝突のバグ修正\r
477                 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
478                 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)\r
479                 {\r
480                         if(Signal[Pos].Socket == INVALID_SOCKET)\r
481                         {\r
482 \r
483 //SetTaskMsg("############### Regist socket (%d)", Pos);\r
484 \r
485                                 Signal[Pos].Socket = s;\r
486                                 Signal[Pos].Error = 0;\r
487                                 Signal[Pos].FdConnect = 0;\r
488                                 Signal[Pos].FdClose = 0;\r
489                                 Signal[Pos].FdAccept = 0;\r
490                                 Signal[Pos].FdRead = 0;\r
491                                 Signal[Pos].FdWrite = 0;\r
492                                 Sts = YES;\r
493                                 break;\r
494                         }\r
495                 }\r
496                 // スレッド衝突のバグ修正\r
497                 ReleaseMutex(hAsyncTblAccMutex);\r
498 \r
499                 if(Pos == MAX_SIGNAL_ENTRY)\r
500                 {\r
501                         MessageBox(GetMainHwnd(), "No more async regist space.", "FFFTP inner error", MB_OK);\r
502                         exit(1);\r
503                 }\r
504         }\r
505 \r
506         return(Sts);\r
507 }\r
508 \r
509 \r
510 /*----- \r
511 *\r
512 *       Parameter\r
513 *               \r
514 *\r
515 *       Return Value\r
516 *               \r
517 *----------------------------------------------------------------------------*/\r
518 \r
519 static int RegistAsyncTableDbase(HANDLE Async)\r
520 {\r
521         int Sts;\r
522         int Pos;\r
523 \r
524         // スレッド衝突のバグ修正\r
525         WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
526         Sts = NO;\r
527         for(Pos = 0; Pos < MAX_SIGNAL_ENTRY_DBASE; Pos++)\r
528         {\r
529                 if(SignalDbase[Pos].Async == Async)\r
530                 {\r
531                         // 強制的に閉じられたハンドルがあると重複する可能性あり\r
532 //                      MessageBox(GetMainHwnd(), "Async handle already registerd.", "FFFTP inner error", MB_OK);\r
533                         // APIの仕様上ハンドルが登録される前にウィンドウメッセージが呼び出される可能性あり\r
534                         break;\r
535                 }\r
536         }\r
537         // スレッド衝突のバグ修正\r
538         ReleaseMutex(hAsyncTblAccMutex);\r
539 \r
540         if(Pos == MAX_SIGNAL_ENTRY_DBASE)\r
541         {\r
542                 // スレッド衝突のバグ修正\r
543                 WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
544                 for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)\r
545                 {\r
546                         if(SignalDbase[Pos].Async == 0)\r
547                         {\r
548 \r
549 //SetTaskMsg("############### Regist dbase (%d)", Pos);\r
550 \r
551                                 SignalDbase[Pos].Async = Async;\r
552                                 SignalDbase[Pos].Done = 0;\r
553                                 SignalDbase[Pos].ErrorDb = 0;\r
554                                 Sts = YES;\r
555                                 break;\r
556                         }\r
557                 }\r
558                 // スレッド衝突のバグ修正\r
559                 ReleaseMutex(hAsyncTblAccMutex);\r
560 \r
561                 if(Pos == MAX_SIGNAL_ENTRY_DBASE)\r
562                 {\r
563                         MessageBox(GetMainHwnd(), "No more async dbase regist space.", "FFFTP inner error", MB_OK);\r
564                         exit(1);\r
565                 }\r
566         }\r
567 \r
568         return(Sts);\r
569 }\r
570 \r
571 \r
572 /*----- \r
573 *\r
574 *       Parameter\r
575 *               \r
576 *\r
577 *       Return Value\r
578 *               \r
579 *----------------------------------------------------------------------------*/\r
580 \r
581 static int UnRegistAsyncTable(SOCKET s)\r
582 {\r
583         int Sts;\r
584         int Pos;\r
585 \r
586         // スレッド衝突のバグ修正\r
587         WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
588         Sts = NO;\r
589         for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)\r
590         {\r
591                 if(Signal[Pos].Socket == s)\r
592                 {\r
593 \r
594 //SetTaskMsg("############### UnRegist socket (%d)", Pos);\r
595 \r
596                         Signal[Pos].Socket = INVALID_SOCKET;\r
597                         Sts = YES;\r
598                         break;\r
599                 }\r
600         }\r
601         // スレッド衝突のバグ修正\r
602         ReleaseMutex(hAsyncTblAccMutex);\r
603         return(Sts);\r
604 }\r
605 \r
606 \r
607 /*----- \r
608 *\r
609 *       Parameter\r
610 *               \r
611 *\r
612 *       Return Value\r
613 *               \r
614 *----------------------------------------------------------------------------*/\r
615 \r
616 static int UnRegistAsyncTableDbase(HANDLE Async)\r
617 {\r
618         int Sts;\r
619         int Pos;\r
620 \r
621         // スレッド衝突のバグ修正\r
622         WaitForSingleObject(hAsyncTblAccMutex, INFINITE);\r
623         Sts = NO;\r
624         for(Pos = 0; Pos < MAX_SIGNAL_ENTRY_DBASE; Pos++)\r
625         {\r
626                 if(SignalDbase[Pos].Async == Async)\r
627                 {\r
628 \r
629 //SetTaskMsg("############### UnRegist dbase (%d)", Pos);\r
630 \r
631                         SignalDbase[Pos].Async = 0;\r
632                         Sts = YES;\r
633                         break;\r
634                 }\r
635         }\r
636         // スレッド衝突のバグ修正\r
637         ReleaseMutex(hAsyncTblAccMutex);\r
638         return(Sts);\r
639 }\r
640 \r
641 \r
642 \r
643 \r
644 \r
645 \r
646 \r
647 \r
648 // IPv6対応\r
649 //struct hostent *do_gethostbyname(const char *Name, char *Buf, int Len, int *CancelCheckWork)\r
650 struct hostent *do_gethostbynameIPv4(const char *Name, char *Buf, int Len, int *CancelCheckWork)\r
651 {\r
652 #if USE_THIS\r
653         struct hostent *Ret;\r
654         HANDLE hAsync;\r
655         int Error;\r
656 \r
657 #if DBG_MSG\r
658         DoPrintf("# Start gethostbyname");\r
659 #endif\r
660         Ret = NULL;\r
661         // 同時接続対応\r
662 //      *CancelCheckWork = NO;\r
663 \r
664         // UTF-8対応\r
665 //      hAsync = WSAAsyncGetHostByName(hWndSocket, WM_ASYNC_DBASE, Name, Buf, Len);\r
666         hAsync = WSAAsyncGetHostByNameM(hWndSocket, WM_ASYNC_DBASE, Name, Buf, Len);\r
667         if(hAsync != NULL)\r
668         {\r
669                 RegistAsyncTableDbase(hAsync);\r
670                 while((*CancelCheckWork == NO) && (AskAsyncDoneDbase(hAsync, &Error) != YES))\r
671                 {\r
672                         Sleep(1);\r
673                         if(BackgrndMessageProc() == YES)\r
674                                 *CancelCheckWork = YES;\r
675                 }\r
676 \r
677                 if(*CancelCheckWork == YES)\r
678                 {\r
679                         WSACancelAsyncRequest(hAsync);\r
680                 }\r
681                 else if(Error == 0)\r
682                 {\r
683                         Ret = (struct hostent *)Buf;\r
684                 }\r
685                 UnRegistAsyncTableDbase(hAsync);\r
686         }\r
687         return(Ret);\r
688 #else\r
689         return(gethostbyname(Name));\r
690 #endif\r
691 }\r
692 \r
693 \r
694 struct hostent *do_gethostbynameIPv6(const char *Name, char *Buf, int Len, int *CancelCheckWork)\r
695 {\r
696 #if USE_THIS\r
697         struct hostent *Ret;\r
698         HANDLE hAsync;\r
699         int Error;\r
700 \r
701 #if DBG_MSG\r
702         DoPrintf("# Start gethostbyname");\r
703 #endif\r
704         Ret = NULL;\r
705         // 同時接続対応\r
706 //      *CancelCheckWork = NO;\r
707 \r
708         // UTF-8対応\r
709 //      hAsync = WSAAsyncGetHostByName(hWndSocket, WM_ASYNC_DBASE, Name, Buf, Len);\r
710         hAsync = WSAAsyncGetHostByNameIPv6M(hWndSocket, WM_ASYNC_DBASE, Name, Buf, Len, AF_INET6);\r
711         if(hAsync != NULL)\r
712         {\r
713                 RegistAsyncTableDbase(hAsync);\r
714                 while((*CancelCheckWork == NO) && (AskAsyncDoneDbase(hAsync, &Error) != YES))\r
715                 {\r
716                         Sleep(1);\r
717                         if(BackgrndMessageProc() == YES)\r
718                                 *CancelCheckWork = YES;\r
719                 }\r
720 \r
721                 if(*CancelCheckWork == YES)\r
722                 {\r
723                         WSACancelAsyncRequest(hAsync);\r
724                 }\r
725                 else if(Error == 0)\r
726                 {\r
727                         Ret = (struct hostent *)Buf;\r
728                 }\r
729                 UnRegistAsyncTableDbase(hAsync);\r
730         }\r
731         return(Ret);\r
732 #else\r
733         return(gethostbyname(Name));\r
734 #endif\r
735 }\r
736 \r
737 \r
738 \r
739 \r
740 \r
741 SOCKET do_socket(int af, int type, int protocol)\r
742 {\r
743         SOCKET Ret;\r
744 \r
745         Ret = socket(af, type, protocol);\r
746         if(Ret != INVALID_SOCKET)\r
747         {\r
748                 RegistAsyncTable(Ret);\r
749         }\r
750 #if DBG_MSG\r
751         DoPrintf("# do_socket (S=%x)", Ret);\r
752 #endif\r
753         return(Ret);\r
754 }\r
755 \r
756 \r
757 \r
758 int do_closesocket(SOCKET s)\r
759 {\r
760 #if USE_THIS\r
761         int Ret;\r
762         int Error;\r
763         int CancelCheckWork;\r
764 \r
765 #if DBG_MSG\r
766         DoPrintf("# Start close (S=%x)", s);\r
767 #endif\r
768         CancelCheckWork = NO;\r
769 \r
770         // スレッド衝突のバグ修正\r
771         WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, 0);\r
772         UnRegistAsyncTable(s);\r
773         // FTPS対応\r
774 //      Ret = closesocket(s);\r
775         Ret = FTPS_closesocket(s);\r
776         if(Ret == SOCKET_ERROR)\r
777         {\r
778                 Error = 0;\r
779                 while((CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_CLOSE) != YES))\r
780                 {\r
781                         Sleep(1);\r
782                         if(BackgrndMessageProc() == YES)\r
783                                 CancelCheckWork = YES;\r
784                 }\r
785 \r
786                 if((CancelCheckWork == NO) && (Error == 0))\r
787                         Ret = 0;\r
788         }\r
789 \r
790         // スレッド衝突のバグ修正\r
791 //      WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, 0);\r
792         if(BackgrndMessageProc() == YES)\r
793                 CancelCheckWork = YES;\r
794         // スレッド衝突のバグ修正\r
795 //      UnRegistAsyncTable(s);\r
796 \r
797 #if DBG_MSG\r
798         DoPrintf("# Exit close");\r
799 #endif\r
800         return(Ret);\r
801 #else\r
802         return(closesocket(s));\r
803 #endif\r
804 }\r
805 \r
806 \r
807 \r
808 \r
809 \r
810 \r
811 int do_connect(SOCKET s, const struct sockaddr *name, int namelen, int *CancelCheckWork)\r
812 {\r
813 #if USE_THIS\r
814         int Ret;\r
815         int Error;\r
816 \r
817 #if DBG_MSG\r
818         DoPrintf("# Start connect (S=%x)", s);\r
819 #endif\r
820         // 同時接続対応\r
821 //      *CancelCheckWork = NO;\r
822 \r
823 #if DBG_MSG\r
824         DoPrintf("## Async set: FD_CONNECT|FD_CLOSE|FD_ACCEPT|FD_READ|FD_WRITE");\r
825 #endif\r
826         // 高速化のためFD_READとFD_WRITEを使用しない\r
827 //      Ret = WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, FD_CONNECT | FD_CLOSE | FD_ACCEPT | FD_READ | FD_WRITE);\r
828         Ret = WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, FD_CONNECT | FD_CLOSE | FD_ACCEPT);\r
829         if(Ret != SOCKET_ERROR)\r
830         {\r
831                 Ret = connect(s, name, namelen);\r
832                 if(Ret == SOCKET_ERROR)\r
833                 {\r
834                         do\r
835                         {\r
836                                 Error = 0;\r
837                                 while((*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_CONNECT) != YES))\r
838                                 {\r
839                                         Sleep(1);\r
840                                         if(BackgrndMessageProc() == YES)\r
841                                                 *CancelCheckWork = YES;\r
842                                 }\r
843 \r
844                                 if(*CancelCheckWork == YES)\r
845                                         break;\r
846                                 if(Error == 0)\r
847                                         Ret = 0;\r
848                                 else\r
849                                 {\r
850 //                                      Error = WSAGetLastError();\r
851                                         DoPrintf("#### Connect: Error=%d", Error);\r
852                                 }\r
853                         }\r
854                         while((Ret != 0) && (Error == WSAEWOULDBLOCK));\r
855                 }\r
856         }\r
857         else\r
858                 DoPrintf("#### Connect: AsyncSelect error (%d)", WSAGetLastError());\r
859 \r
860 #if DBG_MSG\r
861         DoPrintf("# Exit connect (%d)", Ret);\r
862 #endif\r
863         return(Ret);\r
864 #else\r
865         return(connect(s, name, namelen));\r
866 #endif\r
867 }\r
868 \r
869 \r
870 \r
871 \r
872 \r
873 int do_listen(SOCKET s, int backlog)\r
874 {\r
875         int Ret;\r
876 \r
877         Ret = 1;\r
878 #if DBG_MSG\r
879         DoPrintf("# Start listen (S=%x)", s);\r
880         DoPrintf("## Async set: FD_CLOSE|FD_ACCEPT");\r
881 #endif\r
882 \r
883         Ret = WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, FD_CLOSE | FD_ACCEPT);\r
884         if(Ret != SOCKET_ERROR)\r
885                 Ret = listen(s, backlog);\r
886 \r
887 #if DBG_MSG\r
888         DoPrintf("# Exit listen (%d)", Ret);\r
889 #endif\r
890         return(Ret);\r
891 }\r
892 \r
893 \r
894 \r
895 SOCKET do_accept(SOCKET s, struct sockaddr *addr, int *addrlen)\r
896 {\r
897 #if USE_THIS\r
898         SOCKET Ret2;\r
899         int CancelCheckWork;\r
900         int Error;\r
901 \r
902 #if DBG_MSG\r
903         DoPrintf("# Start accept (S=%x)", s);\r
904 #endif\r
905         CancelCheckWork = NO;\r
906         Ret2 = INVALID_SOCKET;\r
907         Error = 0;\r
908 \r
909         while((CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_ACCEPT) != YES))\r
910         {\r
911                 if(AskAsyncDone(s, &Error, FD_CLOSE) == YES)\r
912                 {\r
913                         Error = 1;\r
914                         break;\r
915                 }\r
916                 Sleep(1);\r
917                 if(BackgrndMessageProc() == YES)\r
918                         CancelCheckWork = YES;\r
919         }\r
920 \r
921         if((CancelCheckWork == NO) && (Error == 0))\r
922         {\r
923                 do\r
924                 {\r
925                         Ret2 = accept(s, addr, addrlen);\r
926                         if(Ret2 != INVALID_SOCKET)\r
927                         {\r
928 #if DBG_MSG\r
929                                 DoPrintf("## do_sccept (S=%x)", Ret2);\r
930                                 DoPrintf("## Async set: FD_CONNECT|FD_CLOSE|FD_ACCEPT|FD_READ|FD_WRITE");\r
931 #endif\r
932                                 RegistAsyncTable(Ret2);\r
933                                 if(WSAAsyncSelect(Ret2, hWndSocket, WM_ASYNC_SOCKET, FD_CONNECT | FD_CLOSE | FD_ACCEPT | FD_READ | FD_WRITE) == SOCKET_ERROR)\r
934                                 {\r
935                                         do_closesocket(Ret2);\r
936                                         Ret2 = INVALID_SOCKET;\r
937                                 }\r
938                                 break;\r
939                         }\r
940                         Error = WSAGetLastError();\r
941                         Sleep(1);\r
942                         if(BackgrndMessageProc() == YES)\r
943                                 break;\r
944                 }\r
945                 while(Error == WSAEWOULDBLOCK);\r
946         }\r
947 \r
948 #if DBG_MSG\r
949         DoPrintf("# Exit accept");\r
950 #endif\r
951         return(Ret2);\r
952 #else\r
953         return(accept(s, addr, addrlen));\r
954 #endif\r
955 }\r
956 \r
957 \r
958 \r
959 \r
960 /*----- recv相当の関数 --------------------------------------------------------\r
961 *\r
962 *       Parameter\r
963 *               SOCKET s : ソケット\r
964 *               char *buf : データを読み込むバッファ\r
965 *               int len : 長さ\r
966 *               int flags : recvに与えるフラグ\r
967 *               int *TimeOutErr : タイムアウトしたかどうかを返すワーク\r
968 *\r
969 *       Return Value\r
970 *               int : recvの戻り値と同じ\r
971 *\r
972 *       Note\r
973 *               タイムアウトの時は TimeOut=YES、Ret=SOCKET_ERROR になる\r
974 *----------------------------------------------------------------------------*/\r
975 int do_recv(SOCKET s, char *buf, int len, int flags, int *TimeOutErr, int *CancelCheckWork)\r
976 {\r
977 #if USE_THIS\r
978         int Ret;\r
979         time_t StartTime;\r
980         time_t ElapseTime;\r
981         int Error;\r
982 \r
983 #if DBG_MSG\r
984         DoPrintf("# Start recv (S=%x)", s);\r
985 #endif\r
986         *TimeOutErr = NO;\r
987         // 同時接続対応\r
988 //      *CancelCheckWork = NO;\r
989         Ret = SOCKET_ERROR;\r
990         Error = 0;\r
991 \r
992         if(TimeOut != 0)\r
993                 time(&StartTime);\r
994 \r
995         // FTPS対応\r
996         // OpenSSLでは受信確認はFD_READが複数回受信される可能性がある\r
997 //      while((*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_READ) != YES))\r
998         // 短時間にFD_READが2回以上通知される対策\r
999 //      while(!IsSSLAttached(s) && (*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_READ) != YES))\r
1000 //      {\r
1001 //              if(AskAsyncDone(s, &Error, FD_CLOSE) == YES)\r
1002 //              {\r
1003 //                      Ret = 0;\r
1004 //                      break;\r
1005 //              }\r
1006 //              Sleep(1);\r
1007 //              if(BackgrndMessageProc() == YES)\r
1008 //                      *CancelCheckWork = YES;\r
1009 //              else if(TimeOut != 0)\r
1010 //              {\r
1011 //                      time(&ElapseTime);\r
1012 //                      ElapseTime -= StartTime;\r
1013 //                      if(ElapseTime >= TimeOut)\r
1014 //                      {\r
1015 //                              DoPrintf("do_recv timed out");\r
1016 //                              *TimeOutErr = YES;\r
1017 //                              *CancelCheckWork = YES;\r
1018 //                      }\r
1019 //              }\r
1020 //      }\r
1021 \r
1022         if(/*(Ret != 0) && */(Error == 0) && (*CancelCheckWork == NO) && (*TimeOutErr == NO))\r
1023         {\r
1024                 do\r
1025                 {\r
1026 #if DBG_MSG\r
1027                         DoPrintf("## recv()");\r
1028 #endif\r
1029 \r
1030                         // FTPS対応\r
1031 //                      Ret = recv(s, buf, len, flags);\r
1032                         Ret = FTPS_recv(s, buf, len, flags);\r
1033                         if(Ret != SOCKET_ERROR)\r
1034                                 break;\r
1035                         Error = WSAGetLastError();\r
1036                         Sleep(1);\r
1037                         if(BackgrndMessageProc() == YES)\r
1038                                 break;\r
1039                         // FTPS対応\r
1040                         // 受信確認をバイパスしたためここでタイムアウトの確認\r
1041                         if(BackgrndMessageProc() == YES)\r
1042                                 *CancelCheckWork = YES;\r
1043                         else if(TimeOut != 0)\r
1044                         {\r
1045                                 time(&ElapseTime);\r
1046                                 ElapseTime -= StartTime;\r
1047                                 if(ElapseTime >= TimeOut)\r
1048                                 {\r
1049                                         DoPrintf("do_recv timed out");\r
1050                                         *TimeOutErr = YES;\r
1051                                         *CancelCheckWork = YES;\r
1052                                 }\r
1053                         }\r
1054                         if(*CancelCheckWork == YES)\r
1055                                 break;\r
1056                 }\r
1057                 while(Error == WSAEWOULDBLOCK);\r
1058         }\r
1059 \r
1060         if(BackgrndMessageProc() == YES)\r
1061                 Ret = SOCKET_ERROR;\r
1062 \r
1063 #if DBG_MSG\r
1064         DoPrintf("# Exit recv (%d)", Ret);\r
1065 #endif\r
1066         return(Ret);\r
1067 #else\r
1068         return(recv(s, buf, len, flags));\r
1069 #endif\r
1070 }\r
1071 \r
1072 \r
1073 \r
1074 int do_send(SOCKET s, const char *buf, int len, int flags, int *TimeOutErr, int *CancelCheckWork)\r
1075 {\r
1076 #if USE_THIS\r
1077         int Ret;\r
1078         time_t StartTime;\r
1079         time_t ElapseTime;\r
1080         int Error;\r
1081 \r
1082 #if DBG_MSG\r
1083         DoPrintf("# Start send (S=%x)", s);\r
1084 #endif\r
1085         *TimeOutErr = NO;\r
1086         // 同時接続対応\r
1087 //      *CancelCheckWork = NO;\r
1088         Ret = SOCKET_ERROR;\r
1089         Error = 0;\r
1090 \r
1091         if(TimeOut != 0)\r
1092                 time(&StartTime);\r
1093 \r
1094 #if DBG_MSG\r
1095         DoPrintf("## Async set: FD_CONNECT|FD_CLOSE|FD_ACCEPT|FD_READ|FD_WRITE");\r
1096 #endif\r
1097         // Windows 2000でFD_WRITEが通知されないことがあるバグ修正\r
1098         // 毎回通知されたのはNT 4.0までのバグであり仕様ではない\r
1099         // XP以降は互換性のためか毎回通知される\r
1100 //      WSAAsyncSelect(s, hWndSocket, WM_ASYNC_SOCKET, FD_CONNECT | FD_CLOSE | FD_ACCEPT | FD_READ | FD_WRITE);\r
1101         if(BackgrndMessageProc() == YES)\r
1102                 *CancelCheckWork = YES;\r
1103 \r
1104         // FTPS対応\r
1105         // 送信バッファの空き確認には影響しないが念のため\r
1106 //      while((*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_WRITE) != YES))\r
1107         // Windows 2000でFD_WRITEが通知されないことがあるバグ修正\r
1108 //      while(!IsSSLAttached(s) && (*CancelCheckWork == NO) && (AskAsyncDone(s, &Error, FD_WRITE) != YES))\r
1109 //      {\r
1110 //              if(AskAsyncDone(s, &Error, FD_CLOSE) == YES)\r
1111 //              {\r
1112 //                      Error = 1;\r
1113 //                      break;\r
1114 //              }\r
1115 //\r
1116 //              Sleep(1);\r
1117 //              if(BackgrndMessageProc() == YES)\r
1118 //                      *CancelCheckWork = YES;\r
1119 //              else if(TimeOut != 0)\r
1120 //              {\r
1121 //                      time(&ElapseTime);\r
1122 //                      ElapseTime -= StartTime;\r
1123 //                      if(ElapseTime >= TimeOut)\r
1124 //                      {\r
1125 //                              DoPrintf("do_write timed out");\r
1126 //                              *TimeOutErr = YES;\r
1127 //                              *CancelCheckWork = YES;\r
1128 //                      }\r
1129 //              }\r
1130 //      }\r
1131 \r
1132         if((Error == 0) && (*CancelCheckWork == NO) && (*TimeOutErr == NO))\r
1133         {\r
1134                 do\r
1135                 {\r
1136 #if DBG_MSG\r
1137                         DoPrintf("## send()");\r
1138 #endif\r
1139 \r
1140                         // FTPS対応\r
1141 //                      Ret = send(s, buf, len, flags);\r
1142                         Ret = FTPS_send(s, buf, len, flags);\r
1143                         if(Ret != SOCKET_ERROR)\r
1144                         {\r
1145 #if DBG_MSG\r
1146                                 DoPrintf("## send() OK");\r
1147 #endif\r
1148                                 break;\r
1149                         }\r
1150                         Error = WSAGetLastError();\r
1151                         Sleep(1);\r
1152                         if(BackgrndMessageProc() == YES)\r
1153                                 break;\r
1154                         // FTPS対応\r
1155                         // 送信バッファ確認をバイパスしたためここでタイムアウトの確認\r
1156                         if(BackgrndMessageProc() == YES)\r
1157                                 *CancelCheckWork = YES;\r
1158                         else if(TimeOut != 0)\r
1159                         {\r
1160                                 time(&ElapseTime);\r
1161                                 ElapseTime -= StartTime;\r
1162                                 if(ElapseTime >= TimeOut)\r
1163                                 {\r
1164                                         DoPrintf("do_recv timed out");\r
1165                                         *TimeOutErr = YES;\r
1166                                         *CancelCheckWork = YES;\r
1167                                 }\r
1168                         }\r
1169                         if(*CancelCheckWork == YES)\r
1170                                 break;\r
1171                 }\r
1172                 while(Error == WSAEWOULDBLOCK);\r
1173         }\r
1174 \r
1175         if(BackgrndMessageProc() == YES)\r
1176                 Ret = SOCKET_ERROR;\r
1177 \r
1178 #if DBG_MSG\r
1179         DoPrintf("# Exit send (%d)", Ret);\r
1180 #endif\r
1181         return(Ret);\r
1182 #else\r
1183         return(send(s, buf, len, flags));\r
1184 #endif\r
1185 }\r
1186 \r
1187 \r
1188 // 同時接続対応\r
1189 void RemoveReceivedData(SOCKET s)\r
1190 {\r
1191         char buf[1024];\r
1192         int len;\r
1193         int Error;\r
1194         while((len = FTPS_recv(s, buf, sizeof(buf), MSG_PEEK)) >= 0)\r
1195         {\r
1196                 AskAsyncDone(s, &Error, FD_READ);\r
1197                 FTPS_recv(s, buf, len, 0);\r
1198         }\r
1199 }\r
1200 \r
1201 \r
1202 /*----- \r
1203 *\r
1204 *       Parameter\r
1205 *\r
1206 *       Return Value\r
1207 *               int ステータス\r
1208 *                       FFFTP_SUCCESS/FFFTP_FAIL\r
1209 *----------------------------------------------------------------------------*/\r
1210 \r
1211 int CheckClosedAndReconnect(void)\r
1212 {\r
1213         int Error;\r
1214         int Sts;\r
1215 \r
1216 //SetTaskMsg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");\r
1217 \r
1218         Sts = FFFTP_SUCCESS;\r
1219         if(AskAsyncDone(AskCmdCtrlSkt(), &Error, FD_CLOSE) == YES)\r
1220         {\r
1221                 Sts = ReConnectCmdSkt();\r
1222         }\r
1223         return(Sts);\r
1224 }\r
1225 \r
1226 \r
1227 \r
1228 // 同時接続対応\r
1229 int CheckClosedAndReconnectTrnSkt(SOCKET *Skt, int *CancelCheckWork)\r
1230 {\r
1231         int Error;\r
1232         int Sts;\r
1233 \r
1234 //SetTaskMsg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");\r
1235 \r
1236         Sts = FFFTP_SUCCESS;\r
1237         if(AskAsyncDone(*Skt, &Error, FD_CLOSE) == YES)\r
1238         {\r
1239                 Sts = ReConnectTrnSkt(Skt, CancelCheckWork);\r
1240         }\r
1241         return(Sts);\r
1242 }\r
1243 \r