xref: /reactos/dll/win32/ws2_32/src/socklife.c (revision 682f85ad)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS WinSock 2 API
4  * FILE:        dll/win32/ws2_32/src/socklife.c
5  * PURPOSE:     Socket Lifetime Support
6  * PROGRAMMER:  Alex Ionescu (alex@relsoft.net)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ws2_32.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* FUNCTIONS *****************************************************************/
17 
18 /*
19  * @implemented
20  */
21 SOCKET
22 WSAAPI
accept(IN SOCKET s,OUT LPSOCKADDR addr,OUT INT FAR * addrlen)23 accept(IN  SOCKET s,
24        OUT LPSOCKADDR addr,
25        OUT INT FAR* addrlen)
26 {
27     /* Let WSA do it */
28     return WSAAccept(s, addr, addrlen, NULL, 0);
29 }
30 
31 /*
32  * @implemented
33  */
34 INT
35 WSAAPI
bind(IN SOCKET s,IN CONST struct sockaddr * name,IN INT namelen)36 bind(IN SOCKET s,
37      IN CONST struct sockaddr *name,
38      IN INT namelen)
39 {
40     PWSSOCKET Socket;
41     INT Status;
42     INT ErrorCode;
43     DPRINT("bind: %lx, %p, %lx\n", s, name, namelen);
44 
45     /* Check for WSAStartup */
46     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
47     {
48         /* Get the Socket Context */
49         if ((Socket = WsSockGetSocket(s)))
50         {
51             if (name && (namelen >= sizeof(*name)))
52             {
53                 /* Make the call */
54                 Status = Socket->Provider->Service.lpWSPBind(s,
55                                                              name,
56                                                              namelen,
57                                                              &ErrorCode);
58                 /* Deference the Socket Context */
59                 WsSockDereference(Socket);
60 
61                 /* Return Provider Value */
62                 if (Status == ERROR_SUCCESS) return Status;
63 
64                 /* If everything seemed fine, then the WSP call failed itself */
65                 if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
66             }
67             else
68             {
69                 /* Deference the Socket Context */
70                 WsSockDereference(Socket);
71 
72                 /* name or namelen not valid */
73                 ErrorCode = WSAEFAULT;
74             }
75         }
76         else
77         {
78             /* No Socket Context Found */
79             ErrorCode = WSAENOTSOCK;
80         }
81     }
82 
83     /* Return with an Error */
84     SetLastError(ErrorCode);
85     return SOCKET_ERROR;
86 }
87 
88 /*
89  * @implemented
90  */
91 INT
92 WSAAPI
closesocket(IN SOCKET s)93 closesocket(IN SOCKET s)
94 {
95     PWSSOCKET Socket;
96     INT Status;
97     INT ErrorCode;
98     DPRINT("closesocket: %lx\n", s);
99 
100     /* Check for WSAStartup */
101     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
102     {
103         /* Get the Socket Context */
104         if ((Socket = WsSockGetSocket(s)))
105         {
106             /* Make the call */
107             Status = Socket->Provider->Service.lpWSPCloseSocket(s, &ErrorCode);
108 
109             /* Check if this is a provider socket */
110             if ((Status == ERROR_SUCCESS) && (Socket->IsProvider))
111             {
112                 /* Disassociate the handle */
113                 if (WsSockDisassociateHandle(Socket) == ERROR_SUCCESS)
114                 {
115                     /* Deference the Socket Context */
116                     WsSockDereference(Socket);
117                 }
118 
119                 /* Remove the last reference */
120                 WsSockDereference(Socket);
121 
122                 /* Return success if everything is OK */
123                 if (ErrorCode == ERROR_SUCCESS) return ErrorCode;
124             }
125         }
126         else
127         {
128             /* No Socket Context Found */
129             ErrorCode = WSAENOTSOCK;
130         }
131     }
132 
133     /* Return with an Error */
134     SetLastError(ErrorCode);
135     return SOCKET_ERROR;
136 }
137 
138 /*
139  * @implemented
140  */
141 SOCKET
142 WSAAPI
socket(IN INT af,IN INT type,IN INT protocol)143 socket(IN INT af,
144        IN INT type,
145        IN INT protocol)
146 {
147     PWSPROCESS Process;
148     PWSTHREAD Thread;
149     DWORD Flags = 0;
150     INT ErrorCode;
151     DPRINT("socket: %lx, %lx, %lx\n", af, type, protocol);
152 
153     /* Enter prolog */
154     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
155     {
156         /* Fail here */
157         SetLastError(ErrorCode);
158         return INVALID_SOCKET;
159     }
160 
161     /* Check the current open type and use overlapped if it's default */
162     if (!Thread->OpenType) Flags = WSA_FLAG_OVERLAPPED;
163 
164     /* Make the protocol negative if this is NETBIOS */
165     if ((af == AF_NETBIOS) && (protocol > 0)) protocol *= -1;
166 
167     /* Now let WSA handle it */
168     return WSASocketW(af, type, protocol, NULL, 0, Flags);
169 }
170 
171 /*
172  * @unimplemented
173  */
174 INT
175 WSPAPI
WPUCloseSocketHandle(IN SOCKET s,OUT LPINT lpErrno)176 WPUCloseSocketHandle(IN SOCKET s,
177                      OUT LPINT lpErrno)
178 {
179     UNIMPLEMENTED;
180     return 0;
181 }
182 
183 /*
184  * @unimplemented
185  */
186 SOCKET
187 WSPAPI
WPUCreateSocketHandle(IN DWORD dwCatalogEntryId,IN DWORD_PTR dwContext,OUT LPINT lpErrno)188 WPUCreateSocketHandle(IN DWORD dwCatalogEntryId,
189                       IN DWORD_PTR dwContext,
190                       OUT LPINT lpErrno)
191 {
192     UNIMPLEMENTED;
193     return (SOCKET)0;
194 }
195 
196 /*
197  * @implemented
198  */
199 SOCKET
200 WSPAPI
WPUModifyIFSHandle(IN DWORD dwCatalogEntryId,IN SOCKET ProposedHandle,OUT LPINT lpErrno)201 WPUModifyIFSHandle(IN DWORD dwCatalogEntryId,
202                    IN SOCKET ProposedHandle,
203                    OUT LPINT lpErrno)
204 {
205     SOCKET Handle = INVALID_SOCKET;
206     DWORD ErrorCode = ERROR_SUCCESS;
207     PWSPROCESS Process;
208     PTCATALOG Catalog;
209     PTCATALOG_ENTRY Entry;
210     PWSSOCKET Socket;
211     DPRINT("WPUModifyIFSHandle: %lx, %lx\n", dwCatalogEntryId, ProposedHandle);
212 
213     /* Get the current process */
214     if ((Process = WsGetProcess()))
215     {
216         /* Get the Transport Catalog */
217         if ((Catalog = WsProcGetTCatalog(Process)))
218         {
219             /* Get the entry for this ID */
220             ErrorCode = WsTcGetEntryFromCatalogEntryId(Catalog,
221                                                        dwCatalogEntryId,
222                                                        &Entry);
223             /* Check for success */
224             if (ErrorCode == ERROR_SUCCESS)
225             {
226                 /* Create a socket object */
227                 if ((Socket = WsSockAllocate()))
228                 {
229                     /* Initialize it */
230                     WsSockInitialize(Socket, Entry);
231 
232                     /* Associate it */
233                     ErrorCode = WsSockAssociateHandle(Socket,
234                                                       ProposedHandle,
235                                                       TRUE);
236                     /* Check for success */
237                     if (ErrorCode == ERROR_SUCCESS)
238                     {
239                         /* Return */
240                         Handle = ProposedHandle;
241                         *lpErrno = ERROR_SUCCESS;
242                     }
243                     else
244                     {
245                         /* Fail */
246                         WsSockDereference(Socket);
247                         *lpErrno = ErrorCode;
248                     }
249 
250                     /* Dereference the extra count */
251                     WsSockDereference(Socket);
252                 }
253                 else
254                 {
255                     /* No memory to allocate a socket */
256                     *lpErrno = WSAENOBUFS;
257                 }
258 
259                 /* Dereference the catalog entry */
260                 WsTcEntryDereference(Entry);
261             }
262             else
263             {
264                 /* Entry not found */
265                 *lpErrno = ErrorCode;
266             }
267         }
268         else
269         {
270             /* Catalog not found */
271             *lpErrno = WSANOTINITIALISED;
272         }
273     }
274     else
275     {
276         /* Process not ready */
277         *lpErrno = WSANOTINITIALISED;
278     }
279 
280     /* Return */
281     return Handle;
282 }
283 
284 /*
285  * @unimplemented
286  */
287 INT
288 WSPAPI
WPUQuerySocketHandleContext(IN SOCKET s,OUT PDWORD_PTR lpContext,OUT LPINT lpErrno)289 WPUQuerySocketHandleContext(IN SOCKET s,
290                             OUT PDWORD_PTR lpContext,
291                             OUT LPINT lpErrno)
292 {
293     UNIMPLEMENTED;
294     return 0;
295 }
296 
297 /*
298  * @implemented
299  */
300 SOCKET
301 WSAAPI
WSAAccept(IN SOCKET s,OUT LPSOCKADDR addr,IN OUT LPINT addrlen,IN LPCONDITIONPROC lpfnCondition,IN DWORD_PTR dwCallbackData)302 WSAAccept(IN SOCKET s,
303           OUT LPSOCKADDR addr,
304           IN OUT LPINT addrlen,
305           IN LPCONDITIONPROC lpfnCondition,
306           IN DWORD_PTR dwCallbackData)
307 {
308     PWSPROCESS Process;
309     PWSTHREAD Thread;
310     PWSSOCKET Socket;
311     DWORD OpenType;
312     INT ErrorCode;
313     SOCKET Status;
314     DPRINT("WSAAccept: %lx, %lx, %lx, %p\n", s, addr, addrlen, lpfnCondition);
315 
316     /* Enter prolog */
317     if ((ErrorCode = WsApiProlog(&Process, &Thread)) == ERROR_SUCCESS)
318     {
319         /* Get the Socket Context */
320         if ((Socket = WsSockGetSocket(s)))
321         {
322             /* Get the old open type and set new one */
323             OpenType = Thread->OpenType;
324             Thread->OpenType = Socket->Overlapped ? 0 : SO_SYNCHRONOUS_NONALERT;
325 
326             /* Make the call */
327             Status = Socket->Provider->Service.lpWSPAccept(s,
328                                                            addr,
329                                                            addrlen,
330                                                            lpfnCondition,
331                                                            dwCallbackData,
332                                                            &ErrorCode);
333             /* Restore open type */
334             Thread->OpenType = OpenType;
335 
336             /* Deference the Socket Context */
337             WsSockDereference(Socket);
338 
339             /* Check if we got a valid socket */
340             if (Status != INVALID_SOCKET)
341             {
342                 /* Check if we got a new socket */
343                 if (Status != s)
344                 {
345                     /* Add a new reference */
346                     WsSockAddApiReference(Status);
347                 }
348 
349                 /* Return */
350                 return Status;
351             }
352         }
353         else
354         {
355             /* No Socket Context Found */
356             ErrorCode = WSAENOTSOCK;
357         }
358     }
359 
360     /* Return with an Error */
361     SetLastError(ErrorCode);
362     return INVALID_SOCKET;
363 }
364 
365 /*
366  * @implemented
367  */
368 SOCKET
369 WSAAPI
WSAJoinLeaf(IN SOCKET s,IN CONST struct sockaddr * name,IN INT namelen,IN LPWSABUF lpCallerData,OUT LPWSABUF lpCalleeData,IN LPQOS lpSQOS,IN LPQOS lpGQOS,IN DWORD dwFlags)370 WSAJoinLeaf(IN SOCKET s,
371             IN CONST struct sockaddr *name,
372             IN INT namelen,
373             IN LPWSABUF lpCallerData,
374             OUT LPWSABUF lpCalleeData,
375             IN LPQOS lpSQOS,
376             IN LPQOS lpGQOS,
377             IN DWORD dwFlags)
378 {
379     PWSPROCESS Process;
380     PWSTHREAD Thread;
381     PWSSOCKET Socket;
382     DWORD OpenType;
383     INT ErrorCode;
384     SOCKET Status;
385     DPRINT("WSAJoinLeaf: %lx, %lx, %lx\n", s, name, namelen);
386 
387     /* Enter prolog */
388     if ((ErrorCode = WsApiProlog(&Process, &Thread)) == ERROR_SUCCESS)
389     {
390         /* Get the Socket Context */
391         if ((Socket = WsSockGetSocket(s)))
392         {
393             /* Get the old open type and set new one */
394             OpenType = Thread->OpenType;
395             Thread->OpenType = Socket->Overlapped ? 0 : SO_SYNCHRONOUS_NONALERT;
396 
397             /* Make the call */
398             Status = Socket->Provider->Service.lpWSPJoinLeaf(s,
399                                                              name,
400                                                              namelen,
401                                                              lpCallerData,
402                                                              lpCalleeData,
403                                                              lpSQOS,
404                                                              lpGQOS,
405                                                              dwFlags,
406                                                              &ErrorCode);
407             /* Restore open type */
408             Thread->OpenType = OpenType;
409 
410             /* Deference the Socket Context */
411             WsSockDereference(Socket);
412 
413             /* Check if we got a valid socket */
414             if (Status != INVALID_SOCKET)
415             {
416                 /* Check if we got a new socket */
417                 if (Status != s)
418                 {
419                     /* Add a new reference */
420                     WsSockAddApiReference(Status);
421                 }
422 
423                 /* Return */
424                 return Status;
425             }
426         }
427         else
428         {
429             /* No Socket Context Found */
430             ErrorCode = WSAENOTSOCK;
431         }
432     }
433 
434     /* Return with an Error */
435     SetLastError(ErrorCode);
436     return INVALID_SOCKET;
437 }
438 
439 /*
440  * @implemented
441  */
442 SOCKET
443 WSAAPI
WSASocketA(IN INT af,IN INT type,IN INT protocol,IN LPWSAPROTOCOL_INFOA lpProtocolInfo,IN GROUP g,IN DWORD dwFlags)444 WSASocketA(IN INT af,
445            IN INT type,
446            IN INT protocol,
447            IN LPWSAPROTOCOL_INFOA lpProtocolInfo,
448            IN GROUP g,
449            IN DWORD dwFlags)
450 {
451     WSAPROTOCOL_INFOW ProtocolInfoW;
452     LPWSAPROTOCOL_INFOW p = &ProtocolInfoW;
453 
454     /* Convert Protocol Info to Wide */
455     if (lpProtocolInfo)
456     {
457         /* Copy the Data */
458         memcpy(&ProtocolInfoW,
459                lpProtocolInfo,
460                sizeof(WSAPROTOCOL_INFOA) - sizeof(CHAR) * (WSAPROTOCOL_LEN + 1));
461 
462         /* Convert the String */
463         MultiByteToWideChar(CP_ACP,
464                             0,
465                             lpProtocolInfo->szProtocol,
466                             -1,
467                             ProtocolInfoW.szProtocol,
468                             sizeof(ProtocolInfoW.szProtocol) / sizeof(WCHAR));
469     }
470     else
471     {
472         /* No Protocol Info Specified */
473         p = NULL;
474     }
475 
476     /* Call the Unicode Function */
477     return WSASocketW(af,
478                       type,
479                       protocol,
480                       p,
481                       g,
482                       dwFlags);
483 }
484 
485 /*
486  * @implemented
487  */
488 SOCKET
489 WSAAPI
WSASocketW(IN INT af,IN INT type,IN INT protocol,IN LPWSAPROTOCOL_INFOW lpProtocolInfo,IN GROUP g,IN DWORD dwFlags)490 WSASocketW(IN INT af,
491            IN INT type,
492            IN INT protocol,
493            IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
494            IN GROUP g,
495            IN DWORD dwFlags)
496 {
497     PWSPROCESS Process;
498     PWSTHREAD Thread;
499     INT ErrorCode;
500     PTCATALOG Catalog;
501     DWORD CatalogId;
502     PTCATALOG_ENTRY CatalogEntry;
503     LPWSAPROTOCOL_INFOW ProtocolInfo;
504     DWORD OpenType;
505     SOCKET Status = INVALID_SOCKET;
506     DPRINT("WSASocketW: %lx, %lx, %lx, %p\n", af, type, protocol, lpProtocolInfo);
507 
508     /* Enter prolog */
509     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
510     {
511         /* Fail now */
512         SetLastError(ErrorCode);
513         return INVALID_SOCKET;
514     }
515 
516     /* Get the catalog */
517     Catalog = WsProcGetTCatalog(Process);
518 
519     /* Find a Provider for the Catalog ID */
520     if (lpProtocolInfo)
521     {
522         /* Get the catalog ID */
523         CatalogId = lpProtocolInfo->dwCatalogEntryId;
524 
525         /* Get the Catalog Entry */
526         ErrorCode = WsTcGetEntryFromCatalogEntryId(Catalog,
527                                                    CatalogId,
528                                                    &CatalogEntry);
529     }
530     else
531     {
532         /* No ID */
533         CatalogId = 0;
534 
535 DoLookup:
536         /* Get the Catalog Data from the Socket Info */
537         ErrorCode = WsTcGetEntryFromTriplet(Catalog,
538                                             af,
539                                             type,
540                                             protocol,
541                                             CatalogId,
542                                             &CatalogEntry);
543     }
544 
545     /* Check for Success */
546     if (ErrorCode == ERROR_SUCCESS)
547     {
548         /* Use the default Protocol Info if none given */
549         ProtocolInfo = lpProtocolInfo ? lpProtocolInfo : &CatalogEntry->ProtocolInfo;
550 
551         /* Save the open type and set new one */
552         OpenType = Thread->OpenType;
553         Thread->OpenType = (dwFlags & WSA_FLAG_OVERLAPPED) ?
554                             0 : SO_SYNCHRONOUS_NONALERT;
555 
556         /* Call the Provider to create the Socket */
557         Status = CatalogEntry->Provider->Service.lpWSPSocket(af,
558                                                              type,
559                                                              protocol,
560                                                              ProtocolInfo,
561                                                              g,
562                                                              dwFlags,
563                                                              &ErrorCode);
564         /* Restore open type */
565         Thread->OpenType = OpenType;
566 
567         /* Get the catalog ID now, and dereference */
568         CatalogId = ProtocolInfo->dwCatalogEntryId;
569         WsTcEntryDereference(CatalogEntry);
570 
571         /* Did we fail with WSAEINPROGRESS and had no specific provider? */
572         if ((Status == INVALID_SOCKET) &&
573             (ErrorCode == WSAEINPROGRESS) &&
574             !(lpProtocolInfo))
575         {
576             /* In that case, restart the lookup from this ID */
577             goto DoLookup;
578         }
579 
580         /* Check if we got a valid socket */
581         if (Status != INVALID_SOCKET)
582         {
583             /* Add an API reference and return */
584             WsSockAddApiReference(Status);
585             return Status;
586         }
587     }
588 
589     /* Return with an Error */
590     SetLastError(ErrorCode);
591     return INVALID_SOCKET;
592 }
593