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