xref: /reactos/dll/win32/ws2_32/src/sockctrl.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/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
connect(IN SOCKET s,IN CONST struct sockaddr * name,IN INT namelen)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
listen(IN SOCKET s,IN INT backlog)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
getpeername(IN SOCKET s,OUT LPSOCKADDR name,IN OUT INT FAR * namelen)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
getsockname(IN SOCKET s,OUT LPSOCKADDR name,IN OUT INT FAR * namelen)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
getsockopt(IN SOCKET s,IN INT level,IN INT optname,OUT CHAR FAR * optval,IN OUT INT FAR * optlen)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
setsockopt(IN SOCKET s,IN INT level,IN INT optname,IN CONST CHAR FAR * optval,IN INT optlen)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
shutdown(IN SOCKET s,IN INT how)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
WSAConnect(IN SOCKET s,IN CONST struct sockaddr * name,IN INT namelen,IN LPWSABUF lpCallerData,OUT LPWSABUF lpCalleeData,IN LPQOS lpSQOS,IN LPQOS lpGQOS)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
WSAGetOverlappedResult(IN SOCKET s,IN LPWSAOVERLAPPED lpOverlapped,OUT LPDWORD lpcbTransfer,IN BOOL fWait,OUT LPDWORD lpdwFlags)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