update for HEAD-2003091401
[reactos.git] / lib / ws2_32 / misc / dllmain.c
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS WinSock 2 DLL
4  * FILE:        misc/dllmain.c
5  * PURPOSE:     DLL entry point
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/09-2000 Created
9  */
10 #include <ws2_32.h>
11 #include <catalog.h>
12 #include <handle.h>
13 #include <upcall.h>
14
15 #ifdef DBG
16
17 /* See debug.h for debug/trace constants */
18 DWORD DebugTraceLevel = MIN_TRACE;
19 //DWORD DebugTraceLevel = DEBUG_ULTRA;
20
21 #endif /* DBG */
22
23 /* To make the linker happy */
24 VOID STDCALL KeBugCheck (ULONG  BugCheckCode) {}
25
26
27 HANDLE GlobalHeap;
28 WSPUPCALLTABLE UpcallTable;
29
30
31 /*
32  * @implemented
33  */
34 INT
35 EXPORT
36 WSAGetLastError(VOID)
37 {
38   PWINSOCK_THREAD_BLOCK p = NtCurrentTeb()->WinSockData;
39
40   if (p) {
41     return p->LastErrorValue;
42   } else {
43     /* FIXME: What error code should we use here? Can this even happen? */
44     return ERROR_BAD_ENVIRONMENT;
45   }
46 }
47
48
49 /*
50  * @implemented
51  */
52 VOID
53 EXPORT
54 WSASetLastError(
55     IN  INT iError)
56 {
57   PWINSOCK_THREAD_BLOCK p = NtCurrentTeb()->WinSockData;
58
59   if (p)
60       p->LastErrorValue = iError;
61 }
62
63
64 /*
65  * @implemented
66  */
67 INT
68 EXPORT
69 WSAStartup(
70     IN  WORD wVersionRequested,
71     OUT LPWSADATA lpWSAData)
72 {
73   WS_DbgPrint(MAX_TRACE, ("WSAStartup of ws2_32.dll\n"));
74
75   lpWSAData->wVersion     = wVersionRequested;
76   lpWSAData->wHighVersion = 2;
77   lstrcpyA(lpWSAData->szDescription, "WinSock 2.0");
78   lstrcpyA(lpWSAData->szSystemStatus, "Running");
79   lpWSAData->iMaxSockets  = 0;
80   lpWSAData->iMaxUdpDg    = 0;
81   lpWSAData->lpVendorInfo = NULL;
82
83   WSASETINITIALIZED;
84
85   return NO_ERROR;
86 }
87
88
89 /*
90  * @implemented
91  */
92 INT
93 EXPORT
94 WSACleanup(VOID)
95 {
96   WS_DbgPrint(MAX_TRACE, ("WSACleanup of ws2_32.dll\n"));
97
98   if (!WSAINITIALIZED) {
99     WSASetLastError(WSANOTINITIALISED);
100     return WSANOTINITIALISED;
101   }
102
103   return NO_ERROR;
104 }
105
106
107 /*
108  * @implemented
109  */
110 SOCKET
111 EXPORT
112 socket(
113   IN  INT af,
114   IN  INT type,
115   IN  INT protocol)
116 {
117   return WSASocketA(af, type, protocol, NULL, 0, 0);
118 }
119
120
121 /*
122  * @implemented
123  */
124 SOCKET
125 EXPORT
126 WSASocketA(
127     IN  INT af,
128     IN  INT type,
129     IN  INT protocol,
130     IN  LPWSAPROTOCOL_INFOA lpProtocolInfo,
131     IN  GROUP g,
132     IN  DWORD dwFlags)
133 /*
134  * FUNCTION: Creates a new socket
135  */
136 {
137   WSAPROTOCOL_INFOW ProtocolInfoW;
138   LPWSAPROTOCOL_INFOW p;
139   UNICODE_STRING StringU;
140   ANSI_STRING StringA;
141
142         WS_DbgPrint(MAX_TRACE, ("af (%d)  type (%d)  protocol (%d).\n",
143     af, type, protocol));
144
145   if (lpProtocolInfo) {
146     memcpy(&ProtocolInfoW,
147       lpProtocolInfo,
148       sizeof(WSAPROTOCOL_INFOA) -
149       sizeof(CHAR) * (WSAPROTOCOL_LEN + 1));
150     RtlInitAnsiString(&StringA, (LPSTR)lpProtocolInfo->szProtocol);
151     RtlInitUnicodeString(&StringU, (LPWSTR)&ProtocolInfoW.szProtocol);
152     RtlAnsiStringToUnicodeString(&StringU, &StringA, FALSE);
153     p = &ProtocolInfoW;
154   } else {
155     p = NULL;
156   }
157
158   return WSASocketW(af,
159     type,
160     protocol,
161     p,
162     g,
163     dwFlags);
164 }
165
166
167 /*
168  * @implemented
169  */
170 SOCKET
171 EXPORT
172 WSASocketW(
173     IN  INT af,
174     IN  INT type,
175     IN  INT protocol,
176     IN  LPWSAPROTOCOL_INFOW lpProtocolInfo,
177     IN  GROUP g,
178     IN  DWORD dwFlags)
179 /*
180  * FUNCTION: Creates a new socket descriptor
181  * ARGUMENTS:
182  *     af             = Address family
183  *     type           = Socket type
184  *     protocol       = Protocol type
185  *     lpProtocolInfo = Pointer to protocol information
186  *     g              = Reserved
187  *     dwFlags        = Socket flags
188  * RETURNS:
189  *     Created socket descriptor, or INVALID_SOCKET if it could not be created
190  */
191 {
192   INT Status;
193   SOCKET Socket;
194   PCATALOG_ENTRY Provider;
195   WSAPROTOCOL_INFOW ProtocolInfo;
196
197   WS_DbgPrint(MAX_TRACE, ("af (%d)  type (%d)  protocol (%d).\n",
198       af, type, protocol));
199
200   if (!WSAINITIALIZED) {
201       WSASetLastError(WSANOTINITIALISED);
202       return INVALID_SOCKET;
203   }
204
205   if (!lpProtocolInfo) {
206     lpProtocolInfo = &ProtocolInfo;
207     ZeroMemory(&ProtocolInfo, sizeof(WSAPROTOCOL_INFOW));
208
209     ProtocolInfo.iAddressFamily = af;
210     ProtocolInfo.iSocketType    = type;
211     ProtocolInfo.iProtocol      = protocol;
212   }
213
214   Provider = LocateProvider(lpProtocolInfo);
215   if (!Provider) {
216     WSASetLastError(WSAEAFNOSUPPORT);
217     return INVALID_SOCKET;
218   }
219
220   Status = LoadProvider(Provider, lpProtocolInfo);
221   if (Status != NO_ERROR) {
222     WSASetLastError(Status);
223     return INVALID_SOCKET;
224   }
225
226   WS_DbgPrint(MAX_TRACE, ("Calling WSPSocket at (0x%X).\n",
227     Provider->ProcTable.lpWSPSocket));
228
229   assert(Provider->ProcTable.lpWSPSocket);
230
231   Socket = Provider->ProcTable.lpWSPSocket(
232     af,
233     type,
234     protocol,
235     lpProtocolInfo,
236     g,
237     dwFlags,
238     &Status);
239         if (Status != NO_ERROR) {
240     WSASetLastError(Status);
241     return INVALID_SOCKET;
242   }
243
244   return Socket;
245 }
246
247
248 /*
249  * @implemented
250  */
251 INT
252 EXPORT
253 closesocket(
254     IN  SOCKET s)
255 /*
256  * FUNCTION: Closes a socket descriptor
257  * ARGUMENTS:
258  *     s = Socket descriptor
259  * RETURNS:
260  *     0, or SOCKET_ERROR if an error ocurred
261  */
262 {
263   PCATALOG_ENTRY Provider;
264   INT Status;
265   INT Errno;
266
267   WS_DbgPrint(MAX_TRACE, ("s (0x%X).\n", s));
268
269   if (!WSAINITIALIZED) {
270     WSASetLastError(WSANOTINITIALISED);
271     return SOCKET_ERROR;
272   }
273
274   if (!ReferenceProviderByHandle((HANDLE)s, &Provider)) {
275     WSASetLastError(WSAENOTSOCK);
276     return SOCKET_ERROR;
277   }
278
279   CloseProviderHandle((HANDLE)s);
280
281   DereferenceProviderByPointer(Provider);
282
283   Status = Provider->ProcTable.lpWSPCloseSocket(s, &Errno);
284   if (Status == SOCKET_ERROR)
285     WSASetLastError(Errno);
286
287   return 0;
288 }
289
290
291 /*
292  * @implemented
293  */
294 INT
295 EXPORT
296 select(
297     IN      INT nfds, 
298     IN OUT  LPFD_SET readfds, 
299     IN OUT  LPFD_SET writefds, 
300     IN OUT  LPFD_SET exceptfds, 
301     IN      CONST LPTIMEVAL timeout)
302 /*
303  * FUNCTION: Returns status of one or more sockets
304  * ARGUMENTS:
305  *     nfds      = Always ignored
306  *     readfds   = Pointer to socket set to be checked for readability (optional)
307  *     writefds  = Pointer to socket set to be checked for writability (optional)
308  *     exceptfds = Pointer to socket set to be checked for errors (optional)
309  *     timeout   = Pointer to a TIMEVAL structure indicating maximum wait time
310  *                 (NULL means wait forever)
311  * RETURNS:
312  *     Number of ready socket descriptors, or SOCKET_ERROR if an error ocurred
313  */
314 {
315   PCATALOG_ENTRY Provider;
316   INT Count;
317   INT Errno;
318
319   WS_DbgPrint(MAX_TRACE, ("readfds (0x%X)  writefds (0x%X)  exceptfds (0x%X).\n",
320     readfds, writefds, exceptfds));
321
322   if (!WSAINITIALIZED) {
323     WSASetLastError(WSANOTINITIALISED);
324     return SOCKET_ERROR;
325   }
326
327   /* FIXME: Sockets in FD_SETs should be sorted by their provider */
328
329   /* FIXME: For now, assume only one service provider */
330   if ((readfds != NULL) && (readfds->fd_count > 0)) {
331     if (!ReferenceProviderByHandle((HANDLE)readfds->fd_array[0], &Provider)) {
332       WSASetLastError(WSAENOTSOCK);
333       return SOCKET_ERROR;
334     }
335   } else if ((writefds != NULL) && (writefds->fd_count > 0)) {
336     if (!ReferenceProviderByHandle((HANDLE)writefds->fd_array[0], &Provider)) {
337       WSASetLastError(WSAENOTSOCK);
338       return SOCKET_ERROR;
339     }
340   } else if ((exceptfds != NULL) && (exceptfds->fd_count > 0)) {
341     if (!ReferenceProviderByHandle((HANDLE)exceptfds->fd_array[0], &Provider)) {
342       WSASetLastError(WSAENOTSOCK);
343       return SOCKET_ERROR;
344     }
345   } else {
346     WSASetLastError(WSAEINVAL);
347     return SOCKET_ERROR;
348   }
349
350   Count = Provider->ProcTable.lpWSPSelect(
351     nfds, readfds, writefds, exceptfds, timeout, &Errno);
352
353   WS_DbgPrint(MAX_TRACE, ("Provider (0x%X).\n", Provider));
354
355   DereferenceProviderByPointer(Provider);
356
357   if (Errno != NO_ERROR) {
358     WSASetLastError(Errno);
359     return SOCKET_ERROR;
360   }
361
362   return Count;
363 }
364
365
366 /*
367  * @implemented
368  */
369 INT
370 EXPORT
371 bind(
372   IN  SOCKET s,
373   IN  CONST LPSOCKADDR name,
374   IN  INT namelen)
375 {
376   PCATALOG_ENTRY Provider;
377   INT Status;
378   INT Errno;
379
380   if (!WSAINITIALIZED) {
381     WSASetLastError(WSANOTINITIALISED);
382     return SOCKET_ERROR;
383   }
384
385   if (!ReferenceProviderByHandle((HANDLE)s, &Provider)) {
386     WSASetLastError(WSAENOTSOCK);
387     return SOCKET_ERROR;
388   }
389
390   Status = Provider->ProcTable.lpWSPBind(
391     s, name, namelen, &Errno);
392
393   DereferenceProviderByPointer(Provider);
394
395   if (Status == SOCKET_ERROR) {
396     WSASetLastError(Errno);
397   }
398
399   return Status;
400 }
401
402
403 /*
404  * @implemented
405  */
406 INT
407 EXPORT
408 listen(
409     IN  SOCKET s,
410     IN  INT backlog)
411 {
412   PCATALOG_ENTRY Provider;
413   INT Status;
414   INT Errno;
415
416   if (!WSAINITIALIZED) {
417     WSASetLastError(WSANOTINITIALISED);
418     return SOCKET_ERROR;
419   }
420
421   if (!ReferenceProviderByHandle((HANDLE)s, &Provider)) {
422     WSASetLastError(WSAENOTSOCK);
423     return SOCKET_ERROR;
424   }
425
426   Status = Provider->ProcTable.lpWSPListen(
427     s, backlog, &Errno);
428
429   DereferenceProviderByPointer(Provider);
430
431   if (Status == SOCKET_ERROR) {
432     WSASetLastError(Errno);
433   }
434
435   return Status;
436 }
437
438
439 /*
440  * @implemented
441  */
442 SOCKET
443 EXPORT
444 accept(
445   IN  SOCKET s,
446   OUT LPSOCKADDR addr,
447   OUT INT FAR* addrlen)
448 {
449   return WSAAccept(s, addr, addrlen, NULL, 0);
450 }
451
452
453 /*
454  * @implemented
455  */
456 SOCKET
457 EXPORT
458 WSAAccept(
459   IN      SOCKET s,
460   OUT     LPSOCKADDR addr,
461   IN OUT  LPINT addrlen,
462   IN      LPCONDITIONPROC lpfnCondition,
463   IN      DWORD dwCallbackData)
464 {
465   PCATALOG_ENTRY Provider;
466   SOCKET Socket;
467   INT Errno;
468
469   if (!WSAINITIALIZED) {
470     WSASetLastError(WSANOTINITIALISED);
471     return SOCKET_ERROR;
472   }
473
474   if (!ReferenceProviderByHandle((HANDLE)s, &Provider)) {
475     WSASetLastError(WSAENOTSOCK);
476     return SOCKET_ERROR;
477   }
478
479   Socket = Provider->ProcTable.lpWSPAccept(
480     s, addr, addrlen, lpfnCondition, dwCallbackData, &Errno);
481
482   DereferenceProviderByPointer(Provider);
483
484   if (Socket == INVALID_SOCKET) {
485     WSASetLastError(Errno);
486   }
487
488   return Socket;
489 }
490
491
492 /*
493  * @implemented
494  */
495 INT
496 EXPORT
497 connect(
498   IN  SOCKET s,
499   IN  CONST LPSOCKADDR name,
500   IN  INT namelen)
501 {
502   return WSAConnect(s, name, namelen, NULL, NULL, NULL, NULL);
503 }
504
505
506 /*
507  * @implemented
508  */
509 INT
510 EXPORT
511 WSAConnect(
512   IN  SOCKET s,
513   IN  CONST LPSOCKADDR name,
514   IN  INT namelen,
515   IN  LPWSABUF lpCallerData,
516   OUT LPWSABUF lpCalleeData,
517   IN  LPQOS lpSQOS,
518   IN  LPQOS lpGQOS)
519 {
520   PCATALOG_ENTRY Provider;
521   INT Status;
522   INT Errno;
523
524   if (!WSAINITIALIZED) {
525     WSASetLastError(WSANOTINITIALISED);
526     return SOCKET_ERROR;
527   }
528
529   if (!ReferenceProviderByHandle((HANDLE)s, &Provider)) {
530     WSASetLastError(WSAENOTSOCK);
531     return SOCKET_ERROR;
532   }
533
534   Status = Provider->ProcTable.lpWSPConnect(
535     s, name, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, &Errno);
536
537   DereferenceProviderByPointer(Provider);
538
539   if (Status == SOCKET_ERROR) {
540     WSASetLastError(Errno);
541   }
542
543   return Status;
544 }
545
546
547 BOOL
548 STDCALL
549 DllMain(HANDLE hInstDll,
550         ULONG dwReason,
551         LPVOID lpReserved)
552 {
553   PWINSOCK_THREAD_BLOCK p;
554
555   WS_DbgPrint(MAX_TRACE, ("DllMain of ws2_32.dll.\n"));
556
557   switch (dwReason) {
558   case DLL_PROCESS_ATTACH:
559     GlobalHeap = GetProcessHeap();
560
561     CreateCatalog();
562
563     InitProviderHandleTable();
564
565     UpcallTable.lpWPUCloseEvent         = WPUCloseEvent;
566     UpcallTable.lpWPUCloseSocketHandle  = WPUCloseSocketHandle;
567     UpcallTable.lpWPUCreateEvent        = WPUCreateEvent;
568     UpcallTable.lpWPUCreateSocketHandle = WPUCreateSocketHandle;
569     UpcallTable.lpWPUFDIsSet            = WPUFDIsSet;
570     UpcallTable.lpWPUGetProviderPath    = WPUGetProviderPath;
571     UpcallTable.lpWPUModifyIFSHandle    = WPUModifyIFSHandle;
572     UpcallTable.lpWPUPostMessage        = WPUPostMessage;
573     UpcallTable.lpWPUQueryBlockingCallback    = WPUQueryBlockingCallback;
574     UpcallTable.lpWPUQuerySocketHandleContext = WPUQuerySocketHandleContext;
575     UpcallTable.lpWPUQueueApc           = WPUQueueApc;
576     UpcallTable.lpWPUResetEvent         = WPUResetEvent;
577     UpcallTable.lpWPUSetEvent           = WPUSetEvent;
578     UpcallTable.lpWPUOpenCurrentThread  = WPUOpenCurrentThread;
579     UpcallTable.lpWPUCloseThread        = WPUCloseThread;
580
581     /* Fall through to thread attachment handler */
582
583   case DLL_THREAD_ATTACH:
584     p = HeapAlloc(GlobalHeap, 0, sizeof(WINSOCK_THREAD_BLOCK));
585
586     WS_DbgPrint(MAX_TRACE, ("Thread block at 0x%X.\n", p));
587         
588     if (!p) {
589       return FALSE;
590     }
591
592     p->LastErrorValue = NO_ERROR;
593     p->Initialized    = FALSE;
594
595     NtCurrentTeb()->WinSockData = p;
596     break;
597
598   case DLL_PROCESS_DETACH:
599     p = NtCurrentTeb()->WinSockData;
600
601     if (p)
602       HeapFree(GlobalHeap, 0, p);
603
604     DestroyCatalog();
605
606     FreeProviderHandleTable();
607     break;
608
609   case DLL_THREAD_DETACH:
610     p = NtCurrentTeb()->WinSockData;
611
612     if (p)
613       HeapFree(GlobalHeap, 0, p);
614     break;
615   }
616
617   WS_DbgPrint(MAX_TRACE, ("DllMain of ws2_32.dll. Leaving.\n"));
618
619   return TRUE;
620 }
621
622 /* EOF */