1 /*
2  * linc-compat.c: This file is part of the linc library.
3  *
4  * Authors:
5  *    Tor Lillqvist  (tml@novell.com)
6  *
7  * Copyright 2005, Novell, Inc.
8  */
9 #include "config.h"
10 
11 #include <linc/linc.h>
12 
13 #include "linc-compat.h"
14 #include "linc-debug.h"
15 
16 #ifdef G_OS_WIN32
17 
18 /* Map some WinSock error codes to errno values. Only those that
19  * correspond to real errno values that the linc2 source code checks
20  * for are mapped. They should obviously not include those errno
21  * values that don't exist in the Microsoft C library, and which are
22  * defined as the corresponding WSAE* value in linc-compat.h
23  */
24 void
link_map_winsock_error_to_errno(void)25 link_map_winsock_error_to_errno (void)
26 {
27 	int wsa_error = WSAGetLastError ();
28 	d_printf ("WSAGetLastError: %d\n", wsa_error);
29 	errno = wsa_error;
30 	switch (errno) {
31 	case WSAEBADF:
32 		errno = EBADF; break;
33 	case WSAEWOULDBLOCK:
34 		errno = EAGAIN; break;
35 	}
36 }
37 
38 #endif
39 
40 int
link_pipe(int * handles)41 link_pipe (int *handles)
42 {
43 #ifndef G_OS_WIN32
44 
45   return pipe (handles);
46 
47 #else
48 
49   SOCKET temp, temp2, socket1 = -1, socket2 = -1;
50   struct sockaddr_in saddr;
51   int len;
52   u_long arg;
53   fd_set read_set, write_set;
54   struct timeval tv;
55 
56   temp = socket (AF_INET, SOCK_STREAM, 0);
57   if (temp == INVALID_SOCKET)
58     {
59       link_map_winsock_error_to_errno ();
60       goto out0;
61     }
62 
63   arg = 1;
64   if (ioctlsocket (temp, FIONBIO, &arg) == SOCKET_ERROR)
65     {
66       link_map_winsock_error_to_errno ();
67       goto out0;
68     }
69 
70   memset (&saddr, 0, sizeof (saddr));
71   saddr.sin_family = AF_INET;
72   saddr.sin_port = 0;
73   saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
74 
75   if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr)))
76     {
77       link_map_winsock_error_to_errno ();
78       goto out0;
79     }
80 
81   if (listen (temp, 1) == SOCKET_ERROR)
82     {
83       link_map_winsock_error_to_errno ();
84       goto out0;
85     }
86 
87   len = sizeof (saddr);
88   if (getsockname (temp, (struct sockaddr *)&saddr, &len))
89     {
90       link_map_winsock_error_to_errno ();
91       goto out0;
92     }
93 
94   socket1 = socket (AF_INET, SOCK_STREAM, 0);
95   if (socket1 == INVALID_SOCKET)
96     {
97       link_map_winsock_error_to_errno ();
98       goto out0;
99     }
100 
101   if (!DuplicateHandle (GetCurrentProcess (), (HANDLE) socket1,
102 			GetCurrentProcess (), (LPHANDLE) &temp2,
103 			0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) {
104     goto out1;
105   }
106   socket1 = temp2;
107 
108   arg = 1;
109   if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR)
110     {
111       link_map_winsock_error_to_errno ();
112       goto out1;
113     }
114 
115   if (connect (socket1, (struct sockaddr  *)&saddr, len) != SOCKET_ERROR ||
116       WSAGetLastError () != WSAEWOULDBLOCK)
117     {
118       link_map_winsock_error_to_errno ();
119       goto out1;
120     }
121 
122   FD_ZERO (&read_set);
123   FD_SET (temp, &read_set);
124 
125   tv.tv_sec = 0;
126   tv.tv_usec = 0;
127 
128   if (select (0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR)
129     {
130       link_map_winsock_error_to_errno ();
131       goto out1;
132     }
133 
134   if (!FD_ISSET (temp, &read_set))
135     {
136       errno = WSAECONNREFUSED;	/* Oh well, whatever */
137       goto out1;
138     }
139 
140   socket2 = accept (temp, (struct sockaddr *) &saddr, &len);
141   if (socket2 == INVALID_SOCKET)
142     {
143       link_map_winsock_error_to_errno ();
144       goto out1;
145     }
146 
147   FD_ZERO (&write_set);
148   FD_SET (socket1, &write_set);
149 
150   tv.tv_sec = 0;
151   tv.tv_usec = 0;
152 
153   if (select (0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR)
154     {
155       link_map_winsock_error_to_errno ();
156       goto out2;
157     }
158 
159   if (!FD_ISSET (socket1, &write_set))
160     {
161       errno = WSAECONNREFUSED;
162       goto out2;
163     }
164 
165   if (!DuplicateHandle (GetCurrentProcess (), (HANDLE) socket2,
166 			GetCurrentProcess (), (LPHANDLE) &temp2,
167 			0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) {
168     goto out2;
169   }
170   socket2 = temp2;
171 
172   arg = 0;
173   if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR)
174     {
175       link_map_winsock_error_to_errno ();
176       goto out2;
177     }
178 
179   arg = 0;
180   if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR)
181     {
182       link_map_winsock_error_to_errno ();
183       goto out2;
184     }
185 
186   handles[0] = socket1;
187   handles[1] = socket2;
188 
189   d_printf ("socketpair %d <-> %d\n", socket1, socket2);
190 
191   closesocket (temp);
192 
193   return 0;
194 
195  out2:
196   closesocket (socket2);
197  out1:
198   closesocket (socket1);
199  out0:
200   closesocket (temp);
201 
202   return -1;
203 
204 #endif
205 }
206 
207 const char *
link_strerror(int number)208 link_strerror (int number)
209 {
210 	switch (number) {
211 #ifdef HAVE_WINSOCK2_H
212 	case WSAEOPNOTSUPP:
213 	  return "Operation not supported on transport endpoint";
214 	case WSAEPFNOSUPPORT:
215 	  return "Protocol family not supported";
216 	case WSAECONNRESET:
217 	  return "Connection reset by peer";
218 	case WSAENOBUFS:
219 	  return "No buffer space available";
220 	case WSAEAFNOSUPPORT:
221 	  return "Address family not supported by protocol family";
222 	case WSAENOTSOCK:
223 	  return "Socket operation on non-socket";
224 	case WSAENOPROTOOPT:
225 	  return "Protocol not available";
226 	case WSAESHUTDOWN:
227 	  return "Can't send after socket shutdown";
228 	case WSAECONNREFUSED:
229 	  return "Connection refused";
230 	case WSAEADDRINUSE:
231 	  return "Address already in use";
232 	case WSAECONNABORTED:
233 	  return "Connection aborted";
234 	case WSAENETUNREACH:
235 	  return "Network is unreachable";
236 	case WSAENETDOWN:
237 	  return "Network interface is not configured";
238 	case WSAETIMEDOUT:
239 	  return "Connection timed out";
240 	case WSAEHOSTDOWN:
241 	  return "Host is down";
242 	case WSAEHOSTUNREACH:
243 	  return "Host is unreachable";
244 	case WSAEINPROGRESS:
245 	  return "Connection already in progress";
246 	case WSAEALREADY:
247 	  return "Socket already connected";
248 	case WSAEPROTONOSUPPORT:
249 	  return "Unknown protocol";
250 	case WSAESOCKTNOSUPPORT:
251 	  return "Socket type not supported";
252 	case WSAEADDRNOTAVAIL:
253 	  return "Address not available";
254 	case WSAEISCONN:
255 	  return "Socket is already connected";
256 	case WSAENOTCONN:
257 	  return "Socket is not connected";
258 #endif
259 	default:
260 		return g_strerror (number);
261 	}
262 }
263