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-2021, 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
LookupWSErrorMessage(DWORD err,char * dest)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 *
winsock_strerror(int err,char * strerrbuf,size_t buflen)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(dlls[i].dll_name,
295 0,
296 LOAD_LIBRARY_AS_DATAFILE);
297 }
298
299 if (dlls[i].dll_name && !dlls[i].handle)
300 continue; /* Didn't load */
301
302 flags = FORMAT_MESSAGE_FROM_SYSTEM
303 | FORMAT_MESSAGE_IGNORE_INSERTS
304 | (dlls[i].handle ? FORMAT_MESSAGE_FROM_HMODULE : 0);
305
306 success = 0 != FormatMessage(flags,
307 dlls[i].handle, err,
308 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
309 strerrbuf, buflen - 64,
310 0);
311 }
312
313 if (!success)
314 sprintf(strerrbuf, libpq_gettext("unrecognized socket error: 0x%08X/%d"), err, err);
315 else
316 {
317 strerrbuf[buflen - 1] = '\0';
318 offs = strlen(strerrbuf);
319 if (offs > (int) buflen - 64)
320 offs = buflen - 64;
321 sprintf(strerrbuf + offs, " (0x%08X/%d)", err, err);
322 }
323 return strerrbuf;
324 }
325