xref: /reactos/dll/win32/ws2_32/src/sockctrl.c (revision 9393fc32)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS WinSock 2 API
4  * FILE:        dll/win32/ws2_32/src/sockctrl.c
5  * PURPOSE:     Socket Control/State 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 INT
22 WSAAPI
23 connect(IN SOCKET s,
24         IN CONST struct sockaddr *name,
25         IN INT namelen)
26 {
27     PWSPROCESS Process;
28     PWSTHREAD Thread;
29     PWSSOCKET Socket;
30     INT ErrorCode, OldErrorCode = ERROR_SUCCESS;
31     INT Status;
32     BOOLEAN TryAgain = TRUE;
33     DPRINT("connect: %lx, %p, %lx\n", s, name, namelen);
34 
35     /* Enter prolog */
36     ErrorCode = WsApiProlog(&Process, &Thread);
37     if (ErrorCode == ERROR_SUCCESS)
38     {
39         /* Get the Socket Context */
40         if ((Socket = WsSockGetSocket(s)))
41         {
42             if (!IsBadReadPtr(name, sizeof(struct sockaddr)))
43             {
44                 while (TRUE)
45                 {
46                     /* Make the call */
47                     Status = Socket->Provider->Service.lpWSPConnect(s,
48                                                                     name,
49                                                                     namelen,
50                                                                     NULL,
51                                                                     NULL,
52                                                                     NULL,
53                                                                     NULL,
54                                                                     &ErrorCode);
55 
56                     /* Check if error code was due to the host not being found */
57                     if ((Status == SOCKET_ERROR) &&
58                         ((ErrorCode == WSAEHOSTUNREACH) ||
59                          (ErrorCode == WSAENETUNREACH)))
60                     {
61                         /* Check if we can try again */
62                         if (TryAgain)
63                         {
64                             /* Save the old error code */
65                             OldErrorCode = ErrorCode;
66 
67                             /* Make sure we don't retry 3 times */
68                             TryAgain = FALSE;
69 
70                             /* Make the RAS Auto-dial attempt */
71                             if (WSAttemptAutodialAddr(name, namelen)) continue;
72                         }
73                         else
74                         {
75                             /* Restore the error code */
76                             ErrorCode = OldErrorCode;
77                         }
78                     }
79 
80                     /* Break out of the loop */
81                     break;
82                 }
83 
84                 /* Deference the Socket Context */
85                 WsSockDereference(Socket);
86 
87                 /* Return Provider Value */
88                 if (Status == ERROR_SUCCESS) return Status;
89 
90                 /* If everything seemed fine, then the WSP call failed itself */
91                 if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
92             }
93             else
94             {
95                 /* Invalid user pointer */
96                 ErrorCode = WSAEFAULT;
97             }
98         }
99         else
100         {
101             /* No Socket Context Found */
102             ErrorCode = WSAENOTSOCK;
103         }
104     }
105 
106     /* If this is Winsock 1.1, normalize the error code */
107     if ((ErrorCode == WSAEALREADY) && (LOBYTE(Process->Version) == 1))
108     {
109         /* WS 1.1 apps expect this */
110         ErrorCode = WSAEINVAL;
111     }
112 
113     /* Return with an Error */
114     SetLastError(ErrorCode);
115     return SOCKET_ERROR;
116 }
117 
118 /*
119  * @implemented
120  */
121 INT
122 WSAAPI
123 listen(IN SOCKET s,
124        IN INT backlog)
125 {
126     PWSSOCKET Socket;
127     INT Status;
128     INT ErrorCode;
129     DPRINT("connect: %lx, %lx\n", s, backlog);
130 
131     /* Check for WSAStartup */
132     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
133     {
134         /* Get the Socket Context */
135         if ((Socket = WsSockGetSocket(s)))
136         {
137             /* Make the call */
138             Status = Socket->Provider->Service.lpWSPListen(s,
139                                                            backlog,
140                                                            &ErrorCode);
141             /* Deference the Socket Context */
142             WsSockDereference(Socket);
143 
144             /* Return Provider Value */
145             if (Status == ERROR_SUCCESS) return Status;
146 
147             /* If everything seemed fine, then the WSP call failed itself */
148             if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
149         }
150         else
151         {
152             /* No Socket Context Found */
153             ErrorCode = WSAENOTSOCK;
154         }
155     }
156 
157     /* Return with an Error */
158     SetLastError(ErrorCode);
159     return SOCKET_ERROR;
160 }
161 
162 /*
163  * @implemented
164  */
165 INT
166 WSAAPI
167 getpeername(IN SOCKET s,
168             OUT LPSOCKADDR name,
169             IN OUT INT FAR* namelen)
170 {
171     PWSSOCKET Socket;
172     INT Status;
173     INT ErrorCode;
174     DPRINT("getpeername: %lx, %p, %lx\n", s, name, namelen);
175 
176     /* Check for WSAStartup */
177     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
178     {
179         /* Get the Socket Context */
180         if ((Socket = WsSockGetSocket(s)))
181         {
182             /* Make the call */
183             Status = Socket->Provider->Service.lpWSPGetPeerName(s,
184                                                                 name,
185                                                                 namelen,
186                                                                 &ErrorCode);
187             /* Deference the Socket Context */
188             WsSockDereference(Socket);
189 
190             /* Return Provider Value */
191             if (Status == ERROR_SUCCESS) return Status;
192 
193             /* If everything seemed fine, then the WSP call failed itself */
194             if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
195         }
196         else
197         {
198             /* No Socket Context Found */
199             ErrorCode = WSAENOTSOCK;
200         }
201     }
202 
203     /* Return with an Error */
204     SetLastError(ErrorCode);
205     return SOCKET_ERROR;
206 }
207 
208 /*
209  * @implemented
210  */
211 INT
212 WSAAPI
213 getsockname(IN SOCKET s,
214             OUT LPSOCKADDR name,
215             IN OUT INT FAR* namelen)
216 {
217     PWSSOCKET Socket;
218     INT Status;
219     INT ErrorCode;
220     DPRINT("getsockname: %lx, %p, %lx\n", s, name, namelen);
221 
222     /* Check for WSAStartup */
223     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
224     {
225         /* Get the Socket Context */
226         if ((Socket = WsSockGetSocket(s)))
227         {
228             if (name && namelen && (*namelen >= sizeof(*name)))
229             {
230                 /* Make the call */
231                 Status = Socket->Provider->Service.lpWSPGetSockName(s,
232                                                                     name,
233                                                                     namelen,
234                                                                     &ErrorCode);
235 
236                 /* Deference the Socket Context */
237                 WsSockDereference(Socket);
238 
239                 /* Return Provider Value */
240                 if (Status == ERROR_SUCCESS) return Status;
241 
242                 /* If everything seemed fine, then the WSP call failed itself */
243                 if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
244             }
245             else
246             {
247                 /* Deference the Socket Context */
248                 WsSockDereference(Socket);
249 
250                 /* name or namelen not valid */
251                 ErrorCode = WSAEFAULT;
252             }
253         }
254         else
255         {
256             /* No Socket Context Found */
257             ErrorCode = WSAENOTSOCK;
258         }
259     }
260 
261     /* Return with an Error */
262     SetLastError(ErrorCode);
263     return SOCKET_ERROR;
264 }
265 
266 /*
267  * @implemented
268  */
269 INT
270 WSAAPI
271 getsockopt(IN SOCKET s,
272            IN INT level,
273            IN INT optname,
274            OUT CHAR FAR* optval,
275            IN OUT INT FAR* optlen)
276 {
277     PWSPROCESS Process;
278     PWSTHREAD Thread;
279     PWSSOCKET Socket;
280     INT ErrorCode;
281     INT Status;
282     WSAPROTOCOL_INFOW ProtocolInfo;
283     PCHAR OldOptVal = NULL;
284     INT OldOptLen = 0;
285     DPRINT("getsockopt: %lx, %lx, %lx\n", s, level, optname);
286 
287     /* Enter prolog */
288     if ((ErrorCode = WsApiProlog(&Process, &Thread)) == ERROR_SUCCESS)
289     {
290         /* Check if we're getting the open type */
291         if ((level == SOL_SOCKET) && (optname == SO_OPENTYPE))
292         {
293             /* Validate size */
294             Status = ERROR_SUCCESS;
295             _SEH2_TRY
296             {
297                 if (!(optlen) || (*optlen < sizeof(DWORD)))
298                 {
299                     /* Fail */
300                     Status = SOCKET_ERROR;
301                     SetLastError(WSAEFAULT);
302                     _SEH2_LEAVE;
303                 }
304 
305                 /* Set the open type */
306                 *(DWORD*)optval = Thread->OpenType;
307                 *optlen = sizeof(DWORD);
308             }
309             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
310             {
311                 Status = SOCKET_ERROR;
312                 SetLastError(WSAEFAULT);
313             }
314             _SEH2_END;
315 
316             return Status;
317         }
318 
319         /* Get the Socket Context */
320         if ((Socket = WsSockGetSocket(s)))
321         {
322             /* Check if ANSI data was requested */
323             if ((level == SOL_SOCKET) && (optname == SO_PROTOCOL_INFOA))
324             {
325                 /* Validate size and pointers */
326                 ErrorCode = NO_ERROR;
327                 _SEH2_TRY
328                 {
329                     if (!(optval) ||
330                         !(optlen) ||
331                         (*optlen < sizeof(WSAPROTOCOL_INFOA)))
332                     {
333                         /* Set return size and error code */
334                         *optlen = sizeof(WSAPROTOCOL_INFOA);
335                         ErrorCode = WSAEFAULT;
336                         _SEH2_LEAVE;
337                     }
338 
339                     /* It worked. Save the values */
340                     OldOptLen = *optlen;
341                     OldOptVal = optval;
342 
343                     /* Hack them so WSP will know how to deal with it */
344                     *optlen = sizeof(WSAPROTOCOL_INFOW);
345                     optval = (PCHAR)&ProtocolInfo;
346                     optname = SO_PROTOCOL_INFOW;
347                 }
348                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
349                 {
350                     ErrorCode = WSAEFAULT;
351                 }
352                 _SEH2_END;
353 
354                 /* Did we encounter invalid parameters? */
355                 if (ErrorCode != NO_ERROR)
356                 {
357                     /* Dereference the socket and fail */
358                     WsSockDereference(Socket);
359                     SetLastError(ErrorCode);
360                     return SOCKET_ERROR;
361                 }
362             }
363 
364             /* Make the call */
365             Status = Socket->Provider->Service.lpWSPGetSockOpt(s,
366                                                                level,
367                                                                optname,
368                                                                optval,
369                                                                optlen,
370                                                                &ErrorCode);
371 
372             /* Deference the Socket Context */
373             WsSockDereference(Socket);
374 
375             /* Check provider value */
376             if (Status == ERROR_SUCCESS)
377             {
378                 /* Did we use the A->W hack? */
379                 if (!OldOptVal) return Status;
380 
381                 /* We did, so we have to convert the unicode info to ansi */
382                 ErrorCode = MapUnicodeProtocolInfoToAnsi(&ProtocolInfo,
383                                                          (LPWSAPROTOCOL_INFOA)
384                                                          OldOptVal);
385 
386                 /* Return the length */
387                 _SEH2_TRY
388                 {
389                     *optlen = OldOptLen;
390                 }
391                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
392                 {
393                     ErrorCode = WSAEFAULT;
394                 }
395                 _SEH2_END;
396 
397                 /* Return success if this worked */
398                 if (ErrorCode == ERROR_SUCCESS) return Status;
399             }
400 
401             /* If everything seemed fine, then the WSP call failed itself */
402             if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
403         }
404         else
405         {
406             /* No Socket Context Found */
407             ErrorCode = WSAENOTSOCK;
408         }
409     }
410 
411     /* Return with an Error */
412     SetLastError(ErrorCode);
413     return SOCKET_ERROR;
414 }
415 
416 /*
417  * @implemented
418  */
419 INT
420 WSAAPI
421 setsockopt(IN SOCKET s,
422            IN INT level,
423            IN INT optname,
424            IN CONST CHAR FAR* optval,
425            IN INT optlen)
426 {
427     PWSPROCESS Process;
428     PWSTHREAD Thread;
429     PWSSOCKET Socket;
430     INT ErrorCode;
431     INT Status;
432     DPRINT("setsockopt: %lx, %lx, %lx\n", s, level, optname);
433 
434     /* Enter prolog */
435     if ((ErrorCode = WsApiProlog(&Process, &Thread)) == ERROR_SUCCESS)
436     {
437         /* Check if we're changing the open type */
438         if (level == SOL_SOCKET && optname == SO_OPENTYPE)
439         {
440             /* Validate size */
441             if (optlen < sizeof(DWORD))
442             {
443                 /* Fail */
444                 SetLastError(WSAEFAULT);
445                 return SOCKET_ERROR;
446             }
447 
448             /* Set the open type */
449             Status = ERROR_SUCCESS;
450             _SEH2_TRY
451             {
452                 Thread->OpenType = *(DWORD*)optval;
453             }
454             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
455             {
456                 Status = SOCKET_ERROR;
457                 SetLastError(WSAEFAULT);
458             }
459             _SEH2_END;
460 
461             return Status;
462         }
463         if (!optval && optlen > 0)
464         {
465             SetLastError(WSAEFAULT);
466             return SOCKET_ERROR;
467         }
468 
469         /* Get the Socket Context */
470         if ((Socket = WsSockGetSocket(s)))
471         {
472             /* Make the call */
473             Status = Socket->Provider->Service.lpWSPSetSockOpt(s,
474                                                                level,
475                                                                optname,
476                                                                optval,
477                                                                optlen,
478                                                                &ErrorCode);
479 
480             /* Deference the Socket Context */
481             WsSockDereference(Socket);
482 
483             /* Return Provider Value */
484             if (Status == ERROR_SUCCESS) return Status;
485 
486             /* If everything seemed fine, then the WSP call failed itself */
487             if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
488         }
489         else
490         {
491             /* No Socket Context Found */
492             ErrorCode = WSAENOTSOCK;
493         }
494     }
495 
496     /* Return with an Error */
497     SetLastError(ErrorCode);
498     return SOCKET_ERROR;
499 }
500 
501 /*
502  * @implemented
503  */
504 INT
505 WSAAPI
506 shutdown(IN SOCKET s,
507          IN INT how)
508 {
509     PWSSOCKET Socket;
510     INT Status;
511     INT ErrorCode;
512     DPRINT("shutdown: %lx, %lx\n", s, how);
513 
514     /* Check for WSAStartup */
515     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
516     {
517         /* Get the Socket Context */
518         if ((Socket = WsSockGetSocket(s)))
519         {
520             /* Make the call */
521             Status = Socket->Provider->Service.lpWSPShutdown(s, how, &ErrorCode);
522 
523             /* Deference the Socket Context */
524             WsSockDereference(Socket);
525 
526             /* Return Provider Value */
527             if (Status == ERROR_SUCCESS) return Status;
528 
529             /* If everything seemed fine, then the WSP call failed itself */
530             if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
531         }
532         else
533         {
534             /* No Socket Context Found */
535             ErrorCode = WSAENOTSOCK;
536         }
537     }
538 
539     /* Return with an Error */
540     SetLastError(ErrorCode);
541     return SOCKET_ERROR;
542 }
543 
544 /*
545  * @implemented
546  */
547 INT
548 WSAAPI
549 WSAConnect(IN SOCKET s,
550            IN CONST struct sockaddr *name,
551            IN INT namelen,
552            IN LPWSABUF lpCallerData,
553            OUT LPWSABUF lpCalleeData,
554            IN LPQOS lpSQOS,
555            IN LPQOS lpGQOS)
556 {
557     PWSSOCKET Socket;
558     INT Status;
559     INT ErrorCode;
560     DPRINT("WSAConnect: %lx, %lx, %lx, %p\n", s, name, namelen, lpCallerData);
561 
562     /* Check for WSAStartup */
563     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
564     {
565         /* Get the Socket Context */
566         if ((Socket = WsSockGetSocket(s)))
567         {
568             /* Make the call */
569             Status = Socket->Provider->Service.lpWSPConnect(s,
570                                                             name,
571                                                             namelen,
572                                                             lpCallerData,
573                                                             lpCalleeData,
574                                                             lpSQOS,
575                                                             lpGQOS,
576                                                             &ErrorCode);
577             /* Deference the Socket Context */
578             WsSockDereference(Socket);
579 
580             /* Return Provider Value */
581             if (Status == ERROR_SUCCESS) return Status;
582 
583             /* If everything seemed fine, then the WSP call failed itself */
584             if (ErrorCode == NO_ERROR) ErrorCode = WSASYSCALLFAILURE;
585         }
586         else
587         {
588             /* No Socket Context Found */
589             ErrorCode = WSAENOTSOCK;
590         }
591     }
592 
593     /* Return with an Error */
594     SetLastError(ErrorCode);
595     return SOCKET_ERROR;
596 }
597 
598 /*
599  * @implemented
600  */
601 BOOL
602 WSAAPI
603 WSAGetOverlappedResult(IN SOCKET s,
604                        IN LPWSAOVERLAPPED lpOverlapped,
605                        OUT LPDWORD lpcbTransfer,
606                        IN BOOL fWait,
607                        OUT LPDWORD lpdwFlags)
608 {
609     PWSSOCKET Socket;
610     INT Status;
611     INT ErrorCode;
612     DPRINT("WSAGetOverlappedResult: %lx, %lx\n", s, lpOverlapped);
613 
614     /* Check for WSAStartup */
615     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
616     {
617         /* Get the Socket Context */
618         if ((Socket = WsSockGetSocket(s)))
619         {
620             /* Make the call */
621             Status = Socket->Provider->Service.lpWSPGetOverlappedResult(s,
622                                                                         lpOverlapped,
623                                                                         lpcbTransfer,
624                                                                         fWait,
625                                                                         lpdwFlags,
626                                                                         &ErrorCode);
627             /* Deference the Socket Context */
628             WsSockDereference(Socket);
629 
630             /* Return Provider Value */
631             if (Status) return Status;
632         }
633         else
634         {
635             /* No Socket Context Found */
636             ErrorCode = WSAENOTSOCK;
637         }
638     }
639 
640     /* Return with an Error */
641     SetLastError(ErrorCode);
642     return FALSE;
643 }
644