1 /*-------------------------------------------------------------------------
4 * Microsoft Windows Win32 Socket Functions
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
11 *-------------------------------------------------------------------------
24 * Blocking socket functions implemented so they listen on both
25 * the socket and the signal event, required for signal handling.
29 * Convert the last socket error code into errno
32 TranslateSocketError(void)
34 switch (WSAGetLastError())
36 case WSANOTINITIALISED
:
40 case WSAESOCKTNOSUPPORT
:
42 case WSAEINVALIDPROVIDER
:
43 case WSAEINVALIDPROCTABLE
:
56 case WSAEPROTONOSUPPORT
:
58 errno
= EPROTONOSUPPORT
;
84 errno
= ECONNREFUSED
; /* ENOTCONN? */
88 (errmsg_internal("Unknown win32 socket error code: %i", WSAGetLastError())));
94 pgwin32_poll_signals(void)
96 if (UNBLOCKED_SIGNAL_QUEUE())
98 pgwin32_dispatch_queued_signals();
109 int typelen
= sizeof(type
);
111 if (getsockopt(s
, SOL_SOCKET
, SO_TYPE
, (char *) &type
, &typelen
))
114 return (type
== SOCK_DGRAM
) ? 1 : 0;
118 pgwin32_waitforsinglesocket(SOCKET s
, int what
, int timeout
)
120 static HANDLE waitevent
= INVALID_HANDLE_VALUE
;
121 static SOCKET current_socket
= -1;
122 static int isUDP
= 0;
126 if (waitevent
== INVALID_HANDLE_VALUE
)
128 waitevent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
130 if (waitevent
== INVALID_HANDLE_VALUE
)
132 (errmsg_internal("Failed to create socket waiting event: %i", (int) GetLastError())));
134 else if (!ResetEvent(waitevent
))
136 (errmsg_internal("Failed to reset socket waiting event: %i", (int) GetLastError())));
139 * make sure we don't multiplex this kernel event object with a different
140 * socket from a previous call
143 if (current_socket
!= s
)
145 if (current_socket
!= -1)
146 WSAEventSelect(current_socket
, waitevent
, 0);
147 isUDP
= isDataGram(s
);
152 if (WSAEventSelect(s
, waitevent
, what
) == SOCKET_ERROR
)
154 TranslateSocketError();
158 events
[0] = pgwin32_signal_event
;
159 events
[1] = waitevent
;
162 * Just a workaround of unknown locking problem with writing in UDP socket
163 * under high load: Client's pgsql backend sleeps infinitely in
164 * WaitForMultipleObjectsEx, pgstat process sleeps in pgwin32_select().
165 * So, we will wait with small timeout(0.1 sec) and if sockect is still
166 * blocked, try WSASend (see comments in pgwin32_select) and wait again.
168 if ((what
& FD_WRITE
) && isUDP
)
172 r
= WaitForMultipleObjectsEx(2, events
, FALSE
, 100, TRUE
);
174 if (r
== WAIT_TIMEOUT
)
183 r
= WSASend(s
, &buf
, 1, &sent
, 0, NULL
, NULL
);
184 if (r
== 0) /* Completed - means things are fine! */
186 else if (WSAGetLastError() != WSAEWOULDBLOCK
)
188 TranslateSocketError();
197 r
= WaitForMultipleObjectsEx(2, events
, FALSE
, timeout
, TRUE
);
199 if (r
== WAIT_OBJECT_0
|| r
== WAIT_IO_COMPLETION
)
201 pgwin32_dispatch_queued_signals();
205 if (r
== WAIT_OBJECT_0
+ 1)
207 if (r
== WAIT_TIMEOUT
)
210 (errmsg_internal("Bad return from WaitForMultipleObjects: %i (%i)", r
, (int) GetLastError())));
215 * Create a socket, setting it to overlapped and non-blocking
218 pgwin32_socket(int af
, int type
, int protocol
)
221 unsigned long on
= 1;
223 s
= WSASocket(af
, type
, protocol
, NULL
, 0, WSA_FLAG_OVERLAPPED
);
224 if (s
== INVALID_SOCKET
)
226 TranslateSocketError();
227 return INVALID_SOCKET
;
230 if (ioctlsocket(s
, FIONBIO
, &on
))
232 TranslateSocketError();
233 return INVALID_SOCKET
;
242 pgwin32_accept(SOCKET s
, struct sockaddr
* addr
, int *addrlen
)
247 * Poll for signals, but don't return with EINTR, since we don't handle
250 pgwin32_poll_signals();
252 rs
= WSAAccept(s
, addr
, addrlen
, NULL
, 0);
253 if (rs
== INVALID_SOCKET
)
255 TranslateSocketError();
256 return INVALID_SOCKET
;
262 /* No signal delivery during connect. */
264 pgwin32_connect(SOCKET s
, const struct sockaddr
* addr
, int addrlen
)
268 r
= WSAConnect(s
, addr
, addrlen
, NULL
, NULL
, NULL
, NULL
);
272 if (WSAGetLastError() != WSAEWOULDBLOCK
)
274 TranslateSocketError();
278 while (pgwin32_waitforsinglesocket(s
, FD_CONNECT
, INFINITE
) == 0)
280 /* Loop endlessly as long as we are just delivering signals */
287 pgwin32_recv(SOCKET s
, char *buf
, int len
, int f
)
295 if (pgwin32_poll_signals())
301 r
= WSARecv(s
, &wbuf
, 1, &b
, &flags
, NULL
, NULL
);
302 if (r
!= SOCKET_ERROR
&& b
> 0)
303 /* Read succeeded right away */
306 if (r
== SOCKET_ERROR
&&
307 WSAGetLastError() != WSAEWOULDBLOCK
)
309 TranslateSocketError();
313 /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */
315 for (n
= 0; n
< 5; n
++)
317 if (pgwin32_waitforsinglesocket(s
, FD_READ
| FD_CLOSE
| FD_ACCEPT
,
319 return -1; /* errno already set */
321 r
= WSARecv(s
, &wbuf
, 1, &b
, &flags
, NULL
, NULL
);
322 if (r
== SOCKET_ERROR
)
324 if (WSAGetLastError() == WSAEWOULDBLOCK
)
327 * There seem to be cases on win2k (at least) where WSARecv
328 * can return WSAEWOULDBLOCK even when
329 * pgwin32_waitforsinglesocket claims the socket is readable.
330 * In this case, just sleep for a moment and try again. We try
331 * up to 5 times - if it fails more than that it's not likely
337 TranslateSocketError();
343 (errmsg_internal("Failed to read from ready socket (after retries)")));
349 pgwin32_send(SOCKET s
, char *buf
, int len
, int flags
)
355 if (pgwin32_poll_signals())
362 * Readiness of socket to send data to UDP socket may be not true: socket
363 * can become busy again! So loop until send or error occurs.
367 r
= WSASend(s
, &wbuf
, 1, &b
, flags
, NULL
, NULL
);
368 if (r
!= SOCKET_ERROR
&& b
> 0)
369 /* Write succeeded right away */
372 if (r
== SOCKET_ERROR
&&
373 WSAGetLastError() != WSAEWOULDBLOCK
)
375 TranslateSocketError();
379 /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */
381 if (pgwin32_waitforsinglesocket(s
, FD_WRITE
| FD_CLOSE
, INFINITE
) == 0)
390 * Wait for activity on one or more sockets.
391 * While waiting, allow signals to run
393 * NOTE! Currently does not implement exceptfds check,
394 * since it is not used in postgresql!
397 pgwin32_select(int nfds
, fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
, const struct timeval
* timeout
)
399 WSAEVENT events
[FD_SETSIZE
* 2]; /* worst case is readfds totally
400 * different from writefds, so
401 * 2*FD_SETSIZE sockets */
402 SOCKET sockets
[FD_SETSIZE
* 2];
406 DWORD timeoutval
= WSA_INFINITE
;
411 Assert(exceptfds
== NULL
);
413 if (pgwin32_poll_signals())
416 FD_ZERO(&outreadfds
);
417 FD_ZERO(&outwritefds
);
420 * Write FDs are different in the way that it is only flagged by
421 * WSASelectEvent() if we have tried to write to them first. So try an
426 for (i
= 0; i
< writefds
->fd_count
; i
++)
435 r
= WSASend(writefds
->fd_array
[i
], &buf
, 1, &sent
, 0, NULL
, NULL
);
436 if (r
== 0) /* Completed - means things are fine! */
437 FD_SET (writefds
->fd_array
[i
], &outwritefds
);
440 { /* Not completed */
441 if (WSAGetLastError() != WSAEWOULDBLOCK
)
444 * Not completed, and not just "would block", so an error
447 FD_SET (writefds
->fd_array
[i
], &outwritefds
);
450 if (outwritefds
.fd_count
> 0)
452 memcpy(writefds
, &outwritefds
, sizeof(fd_set
));
455 return outwritefds
.fd_count
;
460 /* Now set up for an actual select */
464 /* timeoutval is in milliseconds */
465 timeoutval
= timeout
->tv_sec
* 1000 + timeout
->tv_usec
/ 1000;
470 for (i
= 0; i
< readfds
->fd_count
; i
++)
472 events
[numevents
] = WSACreateEvent();
473 sockets
[numevents
] = readfds
->fd_array
[i
];
477 if (writefds
!= NULL
)
479 for (i
= 0; i
< writefds
->fd_count
; i
++)
482 !FD_ISSET(writefds
->fd_array
[i
], readfds
))
484 /* If the socket is not in the read list */
485 events
[numevents
] = WSACreateEvent();
486 sockets
[numevents
] = writefds
->fd_array
[i
];
492 for (i
= 0; i
< numevents
; i
++)
496 if (readfds
&& FD_ISSET(sockets
[i
], readfds
))
497 flags
|= FD_READ
| FD_ACCEPT
| FD_CLOSE
;
499 if (writefds
&& FD_ISSET(sockets
[i
], writefds
))
500 flags
|= FD_WRITE
| FD_CLOSE
;
502 if (WSAEventSelect(sockets
[i
], events
[i
], flags
) == SOCKET_ERROR
)
504 TranslateSocketError();
505 for (i
= 0; i
< numevents
; i
++)
506 WSACloseEvent(events
[i
]);
511 events
[numevents
] = pgwin32_signal_event
;
512 r
= WaitForMultipleObjectsEx(numevents
+ 1, events
, FALSE
, timeoutval
, TRUE
);
513 if (r
!= WAIT_TIMEOUT
&& r
!= WAIT_IO_COMPLETION
&& r
!= (WAIT_OBJECT_0
+ numevents
))
516 * We scan all events, even those not signalled, in case more than one
517 * event has been tagged but Wait.. can only return one.
519 WSANETWORKEVENTS resEvents
;
521 for (i
= 0; i
< numevents
; i
++)
523 ZeroMemory(&resEvents
, sizeof(resEvents
));
524 if (WSAEnumNetworkEvents(sockets
[i
], events
[i
], &resEvents
) == SOCKET_ERROR
)
526 (errmsg_internal("failed to enumerate network events: %i", (int) GetLastError())));
528 if (readfds
&& FD_ISSET(sockets
[i
], readfds
))
530 if ((resEvents
.lNetworkEvents
& FD_READ
) ||
531 (resEvents
.lNetworkEvents
& FD_ACCEPT
) ||
532 (resEvents
.lNetworkEvents
& FD_CLOSE
))
534 FD_SET (sockets
[i
], &outreadfds
);
539 /* Write activity? */
540 if (writefds
&& FD_ISSET(sockets
[i
], writefds
))
542 if ((resEvents
.lNetworkEvents
& FD_WRITE
) ||
543 (resEvents
.lNetworkEvents
& FD_CLOSE
))
545 FD_SET (sockets
[i
], &outwritefds
);
553 /* Clean up all handles */
554 for (i
= 0; i
< numevents
; i
++)
556 WSAEventSelect(sockets
[i
], events
[i
], 0);
557 WSACloseEvent(events
[i
]);
560 if (r
== WSA_WAIT_TIMEOUT
)
569 if (r
== WAIT_OBJECT_0
+ numevents
)
571 pgwin32_dispatch_queued_signals();
580 /* Overwrite socket sets with our resulting values */
582 memcpy(readfds
, &outreadfds
, sizeof(fd_set
));
584 memcpy(writefds
, &outwritefds
, sizeof(fd_set
));
590 * Return win32 error string, since strerror can't
591 * handle winsock codes
593 static char wserrbuf
[256];
595 pgwin32_socket_strerror(int err
)
597 static HANDLE handleDLL
= INVALID_HANDLE_VALUE
;
599 if (handleDLL
== INVALID_HANDLE_VALUE
)
601 handleDLL
= LoadLibraryEx("netmsg.dll", NULL
, DONT_RESOLVE_DLL_REFERENCES
| LOAD_LIBRARY_AS_DATAFILE
);
602 if (handleDLL
== NULL
)
604 (errmsg_internal("Failed to load netmsg.dll: %i", (int) GetLastError())));
607 ZeroMemory(&wserrbuf
, sizeof(wserrbuf
));
608 if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_FROM_HMODULE
,
611 MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
),
613 sizeof(wserrbuf
) - 1,
616 /* Failed to get id */
617 sprintf(wserrbuf
, "Unknown winsock error %i", err
);