~ubuntu-branches/ubuntu/precise/postgresql-9.1/precise-security

« back to all changes in this revision

Viewing changes to src/backend/port/win32/socket.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * socket.c
 
4
 *        Microsoft Windows Win32 Socket Functions
 
5
 *
 
6
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
 
7
 *
 
8
 * IDENTIFICATION
 
9
 *        src/backend/port/win32/socket.c
 
10
 *
 
11
 *-------------------------------------------------------------------------
 
12
 */
 
13
 
 
14
#include "postgres.h"
 
15
 
 
16
/*
 
17
 * Indicate if pgwin32_recv() and pgwin32_send() should operate
 
18
 * in non-blocking mode.
 
19
 *
 
20
 * Since the socket emulation layer always sets the actual socket to
 
21
 * non-blocking mode in order to be able to deliver signals, we must
 
22
 * specify this in a separate flag if we actually need non-blocking
 
23
 * operation.
 
24
 *
 
25
 * This flag changes the behaviour *globally* for all socket operations,
 
26
 * so it should only be set for very short periods of time.
 
27
 */
 
28
int                     pgwin32_noblock = 0;
 
29
 
 
30
#undef socket
 
31
#undef accept
 
32
#undef connect
 
33
#undef select
 
34
#undef recv
 
35
#undef send
 
36
 
 
37
/*
 
38
 * Blocking socket functions implemented so they listen on both
 
39
 * the socket and the signal event, required for signal handling.
 
40
 */
 
41
 
 
42
/*
 
43
 * Convert the last socket error code into errno
 
44
 */
 
45
static void
 
46
TranslateSocketError(void)
 
47
{
 
48
        switch (WSAGetLastError())
 
49
        {
 
50
                case WSANOTINITIALISED:
 
51
                case WSAENETDOWN:
 
52
                case WSAEINPROGRESS:
 
53
                case WSAEINVAL:
 
54
                case WSAESOCKTNOSUPPORT:
 
55
                case WSAEFAULT:
 
56
                case WSAEINVALIDPROVIDER:
 
57
                case WSAEINVALIDPROCTABLE:
 
58
                case WSAEMSGSIZE:
 
59
                        errno = EINVAL;
 
60
                        break;
 
61
                case WSAEAFNOSUPPORT:
 
62
                        errno = EAFNOSUPPORT;
 
63
                        break;
 
64
                case WSAEMFILE:
 
65
                        errno = EMFILE;
 
66
                        break;
 
67
                case WSAENOBUFS:
 
68
                        errno = ENOBUFS;
 
69
                        break;
 
70
                case WSAEPROTONOSUPPORT:
 
71
                case WSAEPROTOTYPE:
 
72
                        errno = EPROTONOSUPPORT;
 
73
                        break;
 
74
                case WSAECONNREFUSED:
 
75
                        errno = ECONNREFUSED;
 
76
                        break;
 
77
                case WSAEINTR:
 
78
                        errno = EINTR;
 
79
                        break;
 
80
                case WSAENOTSOCK:
 
81
                        errno = EBADFD;
 
82
                        break;
 
83
                case WSAEOPNOTSUPP:
 
84
                        errno = EOPNOTSUPP;
 
85
                        break;
 
86
                case WSAEWOULDBLOCK:
 
87
                        errno = EWOULDBLOCK;
 
88
                        break;
 
89
                case WSAEACCES:
 
90
                        errno = EACCES;
 
91
                        break;
 
92
                case WSAENOTCONN:
 
93
                case WSAENETRESET:
 
94
                case WSAECONNRESET:
 
95
                case WSAESHUTDOWN:
 
96
                case WSAECONNABORTED:
 
97
                case WSAEDISCON:
 
98
                        errno = ECONNREFUSED;           /* ENOTCONN? */
 
99
                        break;
 
100
                default:
 
101
                        ereport(NOTICE,
 
102
                                        (errmsg_internal("Unknown win32 socket error code: %i", WSAGetLastError())));
 
103
                        errno = EINVAL;
 
104
        }
 
105
}
 
106
 
 
107
static int
 
108
pgwin32_poll_signals(void)
 
109
{
 
110
        if (UNBLOCKED_SIGNAL_QUEUE())
 
111
        {
 
112
                pgwin32_dispatch_queued_signals();
 
113
                errno = EINTR;
 
114
                return 1;
 
115
        }
 
116
        return 0;
 
117
}
 
118
 
 
119
static int
 
120
isDataGram(SOCKET s)
 
121
{
 
122
        int                     type;
 
123
        int                     typelen = sizeof(type);
 
124
 
 
125
        if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &type, &typelen))
 
126
                return 1;
 
127
 
 
128
        return (type == SOCK_DGRAM) ? 1 : 0;
 
129
}
 
130
 
 
131
int
 
132
pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout)
 
133
{
 
134
        static HANDLE waitevent = INVALID_HANDLE_VALUE;
 
135
        static SOCKET current_socket = -1;
 
136
        static int      isUDP = 0;
 
137
        HANDLE          events[2];
 
138
        int                     r;
 
139
 
 
140
        if (waitevent == INVALID_HANDLE_VALUE)
 
141
        {
 
142
                waitevent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
143
 
 
144
                if (waitevent == INVALID_HANDLE_VALUE)
 
145
                        ereport(ERROR,
 
146
                                        (errmsg_internal("Failed to create socket waiting event: %i", (int) GetLastError())));
 
147
        }
 
148
        else if (!ResetEvent(waitevent))
 
149
                ereport(ERROR,
 
150
                                (errmsg_internal("Failed to reset socket waiting event: %i", (int) GetLastError())));
 
151
 
 
152
        /*
 
153
         * make sure we don't multiplex this kernel event object with a different
 
154
         * socket from a previous call
 
155
         */
 
156
 
 
157
        if (current_socket != s)
 
158
        {
 
159
                if (current_socket != -1)
 
160
                        WSAEventSelect(current_socket, waitevent, 0);
 
161
                isUDP = isDataGram(s);
 
162
        }
 
163
 
 
164
        current_socket = s;
 
165
 
 
166
        if (WSAEventSelect(s, waitevent, what) == SOCKET_ERROR)
 
167
        {
 
168
                TranslateSocketError();
 
169
                return 0;
 
170
        }
 
171
 
 
172
        events[0] = pgwin32_signal_event;
 
173
        events[1] = waitevent;
 
174
 
 
175
        /*
 
176
         * Just a workaround of unknown locking problem with writing in UDP socket
 
177
         * under high load: Client's pgsql backend sleeps infinitely in
 
178
         * WaitForMultipleObjectsEx, pgstat process sleeps in pgwin32_select().
 
179
         * So, we will wait with small timeout(0.1 sec) and if sockect is still
 
180
         * blocked, try WSASend (see comments in pgwin32_select) and wait again.
 
181
         */
 
182
        if ((what & FD_WRITE) && isUDP)
 
183
        {
 
184
                for (;;)
 
185
                {
 
186
                        r = WaitForMultipleObjectsEx(2, events, FALSE, 100, TRUE);
 
187
 
 
188
                        if (r == WAIT_TIMEOUT)
 
189
                        {
 
190
                                char            c;
 
191
                                WSABUF          buf;
 
192
                                DWORD           sent;
 
193
 
 
194
                                buf.buf = &c;
 
195
                                buf.len = 0;
 
196
 
 
197
                                r = WSASend(s, &buf, 1, &sent, 0, NULL, NULL);
 
198
                                if (r == 0)             /* Completed - means things are fine! */
 
199
                                        return 1;
 
200
                                else if (WSAGetLastError() != WSAEWOULDBLOCK)
 
201
                                {
 
202
                                        TranslateSocketError();
 
203
                                        return 0;
 
204
                                }
 
205
                        }
 
206
                        else
 
207
                                break;
 
208
                }
 
209
        }
 
210
        else
 
211
                r = WaitForMultipleObjectsEx(2, events, FALSE, timeout, TRUE);
 
212
 
 
213
        if (r == WAIT_OBJECT_0 || r == WAIT_IO_COMPLETION)
 
214
        {
 
215
                pgwin32_dispatch_queued_signals();
 
216
                errno = EINTR;
 
217
                return 0;
 
218
        }
 
219
        if (r == WAIT_OBJECT_0 + 1)
 
220
                return 1;
 
221
        if (r == WAIT_TIMEOUT)
 
222
                return 0;
 
223
        ereport(ERROR,
 
224
                        (errmsg_internal("Bad return from WaitForMultipleObjects: %i (%i)", r, (int) GetLastError())));
 
225
        return 0;
 
226
}
 
227
 
 
228
/*
 
229
 * Create a socket, setting it to overlapped and non-blocking
 
230
 */
 
231
SOCKET
 
232
pgwin32_socket(int af, int type, int protocol)
 
233
{
 
234
        SOCKET          s;
 
235
        unsigned long on = 1;
 
236
 
 
237
        s = WSASocket(af, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
 
238
        if (s == INVALID_SOCKET)
 
239
        {
 
240
                TranslateSocketError();
 
241
                return INVALID_SOCKET;
 
242
        }
 
243
 
 
244
        if (ioctlsocket(s, FIONBIO, &on))
 
245
        {
 
246
                TranslateSocketError();
 
247
                return INVALID_SOCKET;
 
248
        }
 
249
        errno = 0;
 
250
 
 
251
        return s;
 
252
}
 
253
 
 
254
 
 
255
SOCKET
 
256
pgwin32_accept(SOCKET s, struct sockaddr * addr, int *addrlen)
 
257
{
 
258
        SOCKET          rs;
 
259
 
 
260
        /*
 
261
         * Poll for signals, but don't return with EINTR, since we don't handle
 
262
         * that in pqcomm.c
 
263
         */
 
264
        pgwin32_poll_signals();
 
265
 
 
266
        rs = WSAAccept(s, addr, addrlen, NULL, 0);
 
267
        if (rs == INVALID_SOCKET)
 
268
        {
 
269
                TranslateSocketError();
 
270
                return INVALID_SOCKET;
 
271
        }
 
272
        return rs;
 
273
}
 
274
 
 
275
 
 
276
/* No signal delivery during connect. */
 
277
int
 
278
pgwin32_connect(SOCKET s, const struct sockaddr * addr, int addrlen)
 
279
{
 
280
        int                     r;
 
281
 
 
282
        r = WSAConnect(s, addr, addrlen, NULL, NULL, NULL, NULL);
 
283
        if (r == 0)
 
284
                return 0;
 
285
 
 
286
        if (WSAGetLastError() != WSAEWOULDBLOCK)
 
287
        {
 
288
                TranslateSocketError();
 
289
                return -1;
 
290
        }
 
291
 
 
292
        while (pgwin32_waitforsinglesocket(s, FD_CONNECT, INFINITE) == 0)
 
293
        {
 
294
                /* Loop endlessly as long as we are just delivering signals */
 
295
        }
 
296
 
 
297
        return 0;
 
298
}
 
299
 
 
300
int
 
301
pgwin32_recv(SOCKET s, char *buf, int len, int f)
 
302
{
 
303
        WSABUF          wbuf;
 
304
        int                     r;
 
305
        DWORD           b;
 
306
        DWORD           flags = f;
 
307
        int                     n;
 
308
 
 
309
        if (pgwin32_poll_signals())
 
310
                return -1;
 
311
 
 
312
        wbuf.len = len;
 
313
        wbuf.buf = buf;
 
314
 
 
315
        r = WSARecv(s, &wbuf, 1, &b, &flags, NULL, NULL);
 
316
        if (r != SOCKET_ERROR && b > 0)
 
317
                /* Read succeeded right away */
 
318
                return b;
 
319
 
 
320
        if (r == SOCKET_ERROR &&
 
321
                WSAGetLastError() != WSAEWOULDBLOCK)
 
322
        {
 
323
                TranslateSocketError();
 
324
                return -1;
 
325
        }
 
326
 
 
327
        if (pgwin32_noblock)
 
328
        {
 
329
                /*
 
330
                 * No data received, and we are in "emulated non-blocking mode", so
 
331
                 * return indicating that we'd block if we were to continue.
 
332
                 */
 
333
                errno = EWOULDBLOCK;
 
334
                return -1;
 
335
        }
 
336
 
 
337
        /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */
 
338
 
 
339
        for (n = 0; n < 5; n++)
 
340
        {
 
341
                if (pgwin32_waitforsinglesocket(s, FD_READ | FD_CLOSE | FD_ACCEPT,
 
342
                                                                                INFINITE) == 0)
 
343
                        return -1;                      /* errno already set */
 
344
 
 
345
                r = WSARecv(s, &wbuf, 1, &b, &flags, NULL, NULL);
 
346
                if (r == SOCKET_ERROR)
 
347
                {
 
348
                        if (WSAGetLastError() == WSAEWOULDBLOCK)
 
349
                        {
 
350
                                /*
 
351
                                 * There seem to be cases on win2k (at least) where WSARecv
 
352
                                 * can return WSAEWOULDBLOCK even when
 
353
                                 * pgwin32_waitforsinglesocket claims the socket is readable.
 
354
                                 * In this case, just sleep for a moment and try again. We try
 
355
                                 * up to 5 times - if it fails more than that it's not likely
 
356
                                 * to ever come back.
 
357
                                 */
 
358
                                pg_usleep(10000);
 
359
                                continue;
 
360
                        }
 
361
                        TranslateSocketError();
 
362
                        return -1;
 
363
                }
 
364
                return b;
 
365
        }
 
366
        ereport(NOTICE,
 
367
          (errmsg_internal("Failed to read from ready socket (after retries)")));
 
368
        errno = EWOULDBLOCK;
 
369
        return -1;
 
370
}
 
371
 
 
372
/*
 
373
 * The second argument to send() is defined by SUS to be a "const void *"
 
374
 * and so we use the same signature here to keep compilers happy when
 
375
 * handling callers.
 
376
 * 
 
377
 * But the buf member of a WSABUF struct is defined as "char *", so we cast
 
378
 * the second argument to that here when assigning it, also to keep compilers
 
379
 * happy.
 
380
 */
 
381
 
 
382
int
 
383
pgwin32_send(SOCKET s, const void *buf, int len, int flags)
 
384
{
 
385
        WSABUF          wbuf;
 
386
        int                     r;
 
387
        DWORD           b;
 
388
 
 
389
        if (pgwin32_poll_signals())
 
390
                return -1;
 
391
 
 
392
        wbuf.len = len;
 
393
        wbuf.buf = (char *) buf;
 
394
 
 
395
        /*
 
396
         * Readiness of socket to send data to UDP socket may be not true: socket
 
397
         * can become busy again! So loop until send or error occurs.
 
398
         */
 
399
        for (;;)
 
400
        {
 
401
                r = WSASend(s, &wbuf, 1, &b, flags, NULL, NULL);
 
402
                if (r != SOCKET_ERROR && b > 0)
 
403
                        /* Write succeeded right away */
 
404
                        return b;
 
405
 
 
406
                if (r == SOCKET_ERROR &&
 
407
                        WSAGetLastError() != WSAEWOULDBLOCK)
 
408
                {
 
409
                        TranslateSocketError();
 
410
                        return -1;
 
411
                }
 
412
 
 
413
                if (pgwin32_noblock)
 
414
                {
 
415
                        /*
 
416
                         * No data sent, and we are in "emulated non-blocking mode", so
 
417
                         * return indicating that we'd block if we were to continue.
 
418
                         */
 
419
                        errno = EWOULDBLOCK;
 
420
                        return -1;
 
421
                }
 
422
 
 
423
                /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */
 
424
 
 
425
                if (pgwin32_waitforsinglesocket(s, FD_WRITE | FD_CLOSE, INFINITE) == 0)
 
426
                        return -1;
 
427
        }
 
428
 
 
429
        return -1;
 
430
}
 
431
 
 
432
 
 
433
/*
 
434
 * Wait for activity on one or more sockets.
 
435
 * While waiting, allow signals to run
 
436
 *
 
437
 * NOTE! Currently does not implement exceptfds check,
 
438
 * since it is not used in postgresql!
 
439
 */
 
440
int
 
441
pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval * timeout)
 
442
{
 
443
        WSAEVENT        events[FD_SETSIZE * 2]; /* worst case is readfds totally
 
444
                                                                                 * different from writefds, so
 
445
                                                                                 * 2*FD_SETSIZE sockets */
 
446
        SOCKET          sockets[FD_SETSIZE * 2];
 
447
        int                     numevents = 0;
 
448
        int                     i;
 
449
        int                     r;
 
450
        DWORD           timeoutval = WSA_INFINITE;
 
451
        FD_SET          outreadfds;
 
452
        FD_SET          outwritefds;
 
453
        int                     nummatches = 0;
 
454
 
 
455
        Assert(exceptfds == NULL);
 
456
 
 
457
        if (pgwin32_poll_signals())
 
458
                return -1;
 
459
 
 
460
        FD_ZERO(&outreadfds);
 
461
        FD_ZERO(&outwritefds);
 
462
 
 
463
        /*
 
464
         * Write FDs are different in the way that it is only flagged by
 
465
         * WSASelectEvent() if we have tried to write to them first. So try an
 
466
         * empty write
 
467
         */
 
468
        if (writefds)
 
469
        {
 
470
                for (i = 0; i < writefds->fd_count; i++)
 
471
                {
 
472
                        char            c;
 
473
                        WSABUF          buf;
 
474
                        DWORD           sent;
 
475
 
 
476
                        buf.buf = &c;
 
477
                        buf.len = 0;
 
478
 
 
479
                        r = WSASend(writefds->fd_array[i], &buf, 1, &sent, 0, NULL, NULL);
 
480
                        if (r == 0)                     /* Completed - means things are fine! */
 
481
                                FD_SET(writefds->fd_array[i], &outwritefds);
 
482
 
 
483
                        else
 
484
                        {                                       /* Not completed */
 
485
                                if (WSAGetLastError() != WSAEWOULDBLOCK)
 
486
 
 
487
                                        /*
 
488
                                         * Not completed, and not just "would block", so an error
 
489
                                         * occured
 
490
                                         */
 
491
                                        FD_SET(writefds->fd_array[i], &outwritefds);
 
492
                        }
 
493
                }
 
494
                if (outwritefds.fd_count > 0)
 
495
                {
 
496
                        memcpy(writefds, &outwritefds, sizeof(fd_set));
 
497
                        if (readfds)
 
498
                                FD_ZERO(readfds);
 
499
                        return outwritefds.fd_count;
 
500
                }
 
501
        }
 
502
 
 
503
 
 
504
        /* Now set up for an actual select */
 
505
 
 
506
        if (timeout != NULL)
 
507
        {
 
508
                /* timeoutval is in milliseconds */
 
509
                timeoutval = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
 
510
        }
 
511
 
 
512
        if (readfds != NULL)
 
513
        {
 
514
                for (i = 0; i < readfds->fd_count; i++)
 
515
                {
 
516
                        events[numevents] = WSACreateEvent();
 
517
                        sockets[numevents] = readfds->fd_array[i];
 
518
                        numevents++;
 
519
                }
 
520
        }
 
521
        if (writefds != NULL)
 
522
        {
 
523
                for (i = 0; i < writefds->fd_count; i++)
 
524
                {
 
525
                        if (!readfds ||
 
526
                                !FD_ISSET(writefds->fd_array[i], readfds))
 
527
                        {
 
528
                                /* If the socket is not in the read list */
 
529
                                events[numevents] = WSACreateEvent();
 
530
                                sockets[numevents] = writefds->fd_array[i];
 
531
                                numevents++;
 
532
                        }
 
533
                }
 
534
        }
 
535
 
 
536
        for (i = 0; i < numevents; i++)
 
537
        {
 
538
                int                     flags = 0;
 
539
 
 
540
                if (readfds && FD_ISSET(sockets[i], readfds))
 
541
                        flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
 
542
 
 
543
                if (writefds && FD_ISSET(sockets[i], writefds))
 
544
                        flags |= FD_WRITE | FD_CLOSE;
 
545
 
 
546
                if (WSAEventSelect(sockets[i], events[i], flags) == SOCKET_ERROR)
 
547
                {
 
548
                        TranslateSocketError();
 
549
                        for (i = 0; i < numevents; i++)
 
550
                                WSACloseEvent(events[i]);
 
551
                        return -1;
 
552
                }
 
553
        }
 
554
 
 
555
        events[numevents] = pgwin32_signal_event;
 
556
        r = WaitForMultipleObjectsEx(numevents + 1, events, FALSE, timeoutval, TRUE);
 
557
        if (r != WAIT_TIMEOUT && r != WAIT_IO_COMPLETION && r != (WAIT_OBJECT_0 + numevents))
 
558
        {
 
559
                /*
 
560
                 * We scan all events, even those not signalled, in case more than one
 
561
                 * event has been tagged but Wait.. can only return one.
 
562
                 */
 
563
                WSANETWORKEVENTS resEvents;
 
564
 
 
565
                for (i = 0; i < numevents; i++)
 
566
                {
 
567
                        ZeroMemory(&resEvents, sizeof(resEvents));
 
568
                        if (WSAEnumNetworkEvents(sockets[i], events[i], &resEvents) == SOCKET_ERROR)
 
569
                                ereport(FATAL,
 
570
                                                (errmsg_internal("failed to enumerate network events: %i", (int) GetLastError())));
 
571
                        /* Read activity? */
 
572
                        if (readfds && FD_ISSET(sockets[i], readfds))
 
573
                        {
 
574
                                if ((resEvents.lNetworkEvents & FD_READ) ||
 
575
                                        (resEvents.lNetworkEvents & FD_ACCEPT) ||
 
576
                                        (resEvents.lNetworkEvents & FD_CLOSE))
 
577
                                {
 
578
                                        FD_SET(sockets[i], &outreadfds);
 
579
 
 
580
                                        nummatches++;
 
581
                                }
 
582
                        }
 
583
                        /* Write activity? */
 
584
                        if (writefds && FD_ISSET(sockets[i], writefds))
 
585
                        {
 
586
                                if ((resEvents.lNetworkEvents & FD_WRITE) ||
 
587
                                        (resEvents.lNetworkEvents & FD_CLOSE))
 
588
                                {
 
589
                                        FD_SET(sockets[i], &outwritefds);
 
590
 
 
591
                                        nummatches++;
 
592
                                }
 
593
                        }
 
594
                }
 
595
        }
 
596
 
 
597
        /* Clean up all handles */
 
598
        for (i = 0; i < numevents; i++)
 
599
        {
 
600
                WSAEventSelect(sockets[i], events[i], 0);
 
601
                WSACloseEvent(events[i]);
 
602
        }
 
603
 
 
604
        if (r == WSA_WAIT_TIMEOUT)
 
605
        {
 
606
                if (readfds)
 
607
                        FD_ZERO(readfds);
 
608
                if (writefds)
 
609
                        FD_ZERO(writefds);
 
610
                return 0;
 
611
        }
 
612
 
 
613
        if (r == WAIT_OBJECT_0 + numevents)
 
614
        {
 
615
                pgwin32_dispatch_queued_signals();
 
616
                errno = EINTR;
 
617
                if (readfds)
 
618
                        FD_ZERO(readfds);
 
619
                if (writefds)
 
620
                        FD_ZERO(writefds);
 
621
                return -1;
 
622
        }
 
623
 
 
624
        /* Overwrite socket sets with our resulting values */
 
625
        if (readfds)
 
626
                memcpy(readfds, &outreadfds, sizeof(fd_set));
 
627
        if (writefds)
 
628
                memcpy(writefds, &outwritefds, sizeof(fd_set));
 
629
        return nummatches;
 
630
}
 
631
 
 
632
 
 
633
/*
 
634
 * Return win32 error string, since strerror can't
 
635
 * handle winsock codes
 
636
 */
 
637
static char wserrbuf[256];
 
638
const char *
 
639
pgwin32_socket_strerror(int err)
 
640
{
 
641
        static HANDLE handleDLL = INVALID_HANDLE_VALUE;
 
642
 
 
643
        if (handleDLL == INVALID_HANDLE_VALUE)
 
644
        {
 
645
                handleDLL = LoadLibraryEx("netmsg.dll", NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
 
646
                if (handleDLL == NULL)
 
647
                        ereport(FATAL,
 
648
                                        (errmsg_internal("Failed to load netmsg.dll: %i", (int) GetLastError())));
 
649
        }
 
650
 
 
651
        ZeroMemory(&wserrbuf, sizeof(wserrbuf));
 
652
        if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE,
 
653
                                          handleDLL,
 
654
                                          err,
 
655
                                          MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
 
656
                                          wserrbuf,
 
657
                                          sizeof(wserrbuf) - 1,
 
658
                                          NULL) == 0)
 
659
        {
 
660
                /* Failed to get id */
 
661
                sprintf(wserrbuf, "Unknown winsock error %i", err);
 
662
        }
 
663
        return wserrbuf;
 
664
}