1 /*
2  * src/interfaces/libpq/win32.c
3  *
4  *
5  *	FILE
6  *		win32.c
7  *
8  *	DESCRIPTION
9  *		Win32 support functions.
10  *
11  * Contains table and functions for looking up win32 socket error
12  * descriptions. But will/may contain other win32 helper functions
13  * for libpq.
14  *
15  * The error constants are taken from the Frambak Bakfram LGSOCKET
16  * library guys who in turn took them from the Winsock FAQ.
17  *
18  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
19  * Portions Copyright (c) 1994, Regents of the University of California
20  *
21  */
22 
23 /* Make stuff compile faster by excluding not used stuff */
24 
25 #define VC_EXTRALEAN
26 #ifndef __MINGW32__
27 #define NOGDI
28 #endif
29 #define NOCRYPT
30 
31 #include "postgres_fe.h"
32 
33 #include "win32.h"
34 
35 /* Declared here to avoid pulling in all includes, which causes name collisions */
36 #ifdef ENABLE_NLS
37 extern char *libpq_gettext(const char *msgid) pg_attribute_format_arg(1);
38 #else
39 #define libpq_gettext(x) (x)
40 #endif
41 
42 
43 static struct WSErrorEntry
44 {
45 	DWORD		error;
46 	const char *description;
47 }			WSErrors[] =
48 
49 {
50 	{
51 		0, "No error"
52 	},
53 	{
54 		WSAEINTR, "Interrupted system call"
55 	},
56 	{
57 		WSAEBADF, "Bad file number"
58 	},
59 	{
60 		WSAEACCES, "Permission denied"
61 	},
62 	{
63 		WSAEFAULT, "Bad address"
64 	},
65 	{
66 		WSAEINVAL, "Invalid argument"
67 	},
68 	{
69 		WSAEMFILE, "Too many open sockets"
70 	},
71 	{
72 		WSAEWOULDBLOCK, "Operation would block"
73 	},
74 	{
75 		WSAEINPROGRESS, "Operation now in progress"
76 	},
77 	{
78 		WSAEALREADY, "Operation already in progress"
79 	},
80 	{
81 		WSAENOTSOCK, "Socket operation on non-socket"
82 	},
83 	{
84 		WSAEDESTADDRREQ, "Destination address required"
85 	},
86 	{
87 		WSAEMSGSIZE, "Message too long"
88 	},
89 	{
90 		WSAEPROTOTYPE, "Protocol wrong type for socket"
91 	},
92 	{
93 		WSAENOPROTOOPT, "Bad protocol option"
94 	},
95 	{
96 		WSAEPROTONOSUPPORT, "Protocol not supported"
97 	},
98 	{
99 		WSAESOCKTNOSUPPORT, "Socket type not supported"
100 	},
101 	{
102 		WSAEOPNOTSUPP, "Operation not supported on socket"
103 	},
104 	{
105 		WSAEPFNOSUPPORT, "Protocol family not supported"
106 	},
107 	{
108 		WSAEAFNOSUPPORT, "Address family not supported"
109 	},
110 	{
111 		WSAEADDRINUSE, "Address already in use"
112 	},
113 	{
114 		WSAEADDRNOTAVAIL, "Cannot assign requested address"
115 	},
116 	{
117 		WSAENETDOWN, "Network is down"
118 	},
119 	{
120 		WSAENETUNREACH, "Network is unreachable"
121 	},
122 	{
123 		WSAENETRESET, "Net connection reset"
124 	},
125 	{
126 		WSAECONNABORTED, "Software caused connection abort"
127 	},
128 	{
129 		WSAECONNRESET, "Connection reset by peer"
130 	},
131 	{
132 		WSAENOBUFS, "No buffer space available"
133 	},
134 	{
135 		WSAEISCONN, "Socket is already connected"
136 	},
137 	{
138 		WSAENOTCONN, "Socket is not connected"
139 	},
140 	{
141 		WSAESHUTDOWN, "Cannot send after socket shutdown"
142 	},
143 	{
144 		WSAETOOMANYREFS, "Too many references, cannot splice"
145 	},
146 	{
147 		WSAETIMEDOUT, "Connection timed out"
148 	},
149 	{
150 		WSAECONNREFUSED, "Connection refused"
151 	},
152 	{
153 		WSAELOOP, "Too many levels of symbolic links"
154 	},
155 	{
156 		WSAENAMETOOLONG, "File name too long"
157 	},
158 	{
159 		WSAEHOSTDOWN, "Host is down"
160 	},
161 	{
162 		WSAEHOSTUNREACH, "No route to host"
163 	},
164 	{
165 		WSAENOTEMPTY, "Directory not empty"
166 	},
167 	{
168 		WSAEPROCLIM, "Too many processes"
169 	},
170 	{
171 		WSAEUSERS, "Too many users"
172 	},
173 	{
174 		WSAEDQUOT, "Disc quota exceeded"
175 	},
176 	{
177 		WSAESTALE, "Stale NFS file handle"
178 	},
179 	{
180 		WSAEREMOTE, "Too many levels of remote in path"
181 	},
182 	{
183 		WSASYSNOTREADY, "Network system is unavailable"
184 	},
185 	{
186 		WSAVERNOTSUPPORTED, "Winsock version out of range"
187 	},
188 	{
189 		WSANOTINITIALISED, "WSAStartup not yet called"
190 	},
191 	{
192 		WSAEDISCON, "Graceful shutdown in progress"
193 	},
194 	{
195 		WSAHOST_NOT_FOUND, "Host not found"
196 	},
197 	{
198 		WSATRY_AGAIN, "NA Host not found / SERVFAIL"
199 	},
200 	{
201 		WSANO_RECOVERY, "Non recoverable FORMERR||REFUSED||NOTIMP"
202 	},
203 	{
204 		WSANO_DATA, "No host data of that type was found"
205 	},
206 	{
207 		0, 0
208 	}							/* End of table */
209 };
210 
211 
212 /*
213  * Returns 0 if not found, linear but who cares, at this moment
214  * we're already in pain :)
215  */
216 
217 static int
218 LookupWSErrorMessage(DWORD err, char *dest)
219 {
220 	struct WSErrorEntry *e;
221 
222 	for (e = WSErrors; e->description; e++)
223 	{
224 		if (e->error == err)
225 		{
226 			strcpy(dest, e->description);
227 			return 1;
228 		}
229 	}
230 	return 0;
231 }
232 
233 
234 struct MessageDLL
235 {
236 	const char *dll_name;
237 	void	   *handle;
238 	int			loaded;			/* BOOL */
239 }			dlls[] =
240 
241 {
242 	{
243 		"netmsg.dll", 0, 0
244 	},
245 	{
246 		"winsock.dll", 0, 0
247 	},
248 	{
249 		"ws2_32.dll", 0, 0
250 	},
251 	{
252 		"wsock32n.dll", 0, 0
253 	},
254 	{
255 		"mswsock.dll", 0, 0
256 	},
257 	{
258 		"ws2help.dll", 0, 0
259 	},
260 	{
261 		"ws2thk.dll", 0, 0
262 	},
263 	{
264 		0, 0, 1
265 	}							/* Last one, no dll, always loaded */
266 };
267 
268 #define DLLS_SIZE (sizeof(dlls)/sizeof(struct MessageDLL))
269 
270 /*
271  * Returns a description of the socket error by first trying
272  * to find it in the lookup table, and if that fails, tries
273  * to load any of the winsock dlls to find that message.
274  * The DLL thing works from Nt4 (spX ?) up, but some special
275  * versions of winsock might have this as well (seen on Win98 SE
276  * special install)			   / Magnus Naeslund (mag@fbab.net)
277  *
278  */
279 
280 const char *
281 winsock_strerror(int err, char *strerrbuf, size_t buflen)
282 {
283 	unsigned long flags;
284 	int			offs,
285 				i;
286 	int			success = LookupWSErrorMessage(err, strerrbuf);
287 
288 	for (i = 0; !success && i < DLLS_SIZE; i++)
289 	{
290 
291 		if (!dlls[i].loaded)
292 		{
293 			dlls[i].loaded = 1; /* Only load once */
294 			dlls[i].handle = (void *) LoadLibraryEx(
295 													dlls[i].dll_name,
296 													0,
297 													LOAD_LIBRARY_AS_DATAFILE);
298 		}
299 
300 		if (dlls[i].dll_name && !dlls[i].handle)
301 			continue;			/* Didn't load */
302 
303 		flags = FORMAT_MESSAGE_FROM_SYSTEM
304 			| FORMAT_MESSAGE_IGNORE_INSERTS
305 			| (dlls[i].handle ? FORMAT_MESSAGE_FROM_HMODULE : 0);
306 
307 		success = 0 != FormatMessage(
308 									 flags,
309 									 dlls[i].handle, err,
310 									 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
311 									 strerrbuf, buflen - 64,
312 									 0
313 			);
314 	}
315 
316 	if (!success)
317 		sprintf(strerrbuf, libpq_gettext("unrecognized socket error: 0x%08X/%d"), err, err);
318 	else
319 	{
320 		strerrbuf[buflen - 1] = '\0';
321 		offs = strlen(strerrbuf);
322 		if (offs > (int) buflen - 64)
323 			offs = buflen - 64;
324 		sprintf(strerrbuf + offs, " (0x%08X/%d)", err, err);
325 	}
326 	return strerrbuf;
327 }
328