1 /*-------------------------------------------------------------------------
4 * Microsoft Windows Win32 Socket Functions
6 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
9 * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.14 2006/10/13 13:59:47 teodor Exp $
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();
106 isDataGram(SOCKET s) {
108 int typelen = sizeof(type);
110 if ( getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &typelen) )
113 return ( type == SOCK_DGRAM ) ? 1 : 0;
117 pgwin32_waitforsinglesocket(SOCKET s, int what)
119 static HANDLE waitevent = INVALID_HANDLE_VALUE;
120 static SOCKET current_socket = -1;
121 static int isUDP = 0;
125 if (waitevent == INVALID_HANDLE_VALUE)
127 waitevent = CreateEvent(NULL, TRUE, FALSE, NULL);
129 if (waitevent == INVALID_HANDLE_VALUE)
131 (errmsg_internal("Failed to create socket waiting event: %i", (int) GetLastError())));
133 else if (!ResetEvent(waitevent))
135 (errmsg_internal("Failed to reset socket waiting event: %i", (int) GetLastError())));
138 * make sure we don't multiplex this kernel event object with a different
139 * socket from a previous call
142 if (current_socket != s)
144 if ( current_socket != -1 )
145 WSAEventSelect(current_socket, waitevent, 0);
146 isUDP = isDataGram(s);
151 if (WSAEventSelect(s, waitevent, what) == SOCKET_ERROR)
153 TranslateSocketError();
157 events[0] = pgwin32_signal_event;
158 events[1] = waitevent;
161 * Just a workaround of unknown locking problem with writing
162 * in UDP socket under high load:
163 * Client's pgsql backend sleeps infinitely in
164 * WaitForMultipleObjectsEx, pgstat process sleeps in
165 * pgwin32_select(). So, we will wait with small
166 * timeout(0.1 sec) and if sockect is still blocked,
167 * try WSASend (see comments in pgwin32_select) and wait again.
169 if ((what & FD_WRITE) && isUDP)
173 r = WaitForMultipleObjectsEx(2, events, FALSE, 100, TRUE);
175 if ( r == WAIT_TIMEOUT )
184 r = WSASend(s, &buf, 1, &sent, 0, NULL, NULL);
185 if (r == 0) /* Completed - means things are fine! */
187 else if ( WSAGetLastError() != WSAEWOULDBLOCK )
189 TranslateSocketError();
198 r = WaitForMultipleObjectsEx(2, events, FALSE, INFINITE, TRUE);
200 if (r == WAIT_OBJECT_0 || r == WAIT_IO_COMPLETION)
202 pgwin32_dispatch_queued_signals();
206 if (r == WAIT_OBJECT_0 + 1)
209 (errmsg_internal("Bad return from WaitForMultipleObjects: %i (%i)", r, (int) GetLastError())));
214 * Create a socket, setting it to overlapped and non-blocking
217 pgwin32_socket(int af, int type, int protocol)
220 unsigned long on = 1;
222 s = WSASocket(af, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
223 if (s == INVALID_SOCKET)
225 TranslateSocketError();
226 return INVALID_SOCKET;
229 if (ioctlsocket(s, FIONBIO, &on))
231 TranslateSocketError();
232 return INVALID_SOCKET;
241 pgwin32_accept(SOCKET s, struct sockaddr * addr, int *addrlen)
246 * Poll for signals, but don't return with EINTR, since we don't handle
249 pgwin32_poll_signals();
251 rs = WSAAccept(s, addr, addrlen, NULL, 0);
252 if (rs == INVALID_SOCKET)
254 TranslateSocketError();
255 return INVALID_SOCKET;
261 /* No signal delivery during connect. */
263 pgwin32_connect(SOCKET s, const struct sockaddr * addr, int addrlen)
267 r = WSAConnect(s, addr, addrlen, NULL, NULL, NULL, NULL);
271 if (WSAGetLastError() != WSAEWOULDBLOCK)
273 TranslateSocketError();
277 while (pgwin32_waitforsinglesocket(s, FD_CONNECT) == 0)
279 /* Loop endlessly as long as we are just delivering signals */
286 pgwin32_recv(SOCKET s, char *buf, int len, int f)
293 if (pgwin32_poll_signals())
299 r = WSARecv(s, &wbuf, 1, &b, &flags, NULL, NULL);
300 if (r != SOCKET_ERROR && b > 0)
301 /* Read succeeded right away */
304 if (r == SOCKET_ERROR &&
305 WSAGetLastError() != WSAEWOULDBLOCK)
307 TranslateSocketError();
311 /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */
313 if (pgwin32_waitforsinglesocket(s, FD_READ | FD_CLOSE | FD_ACCEPT) == 0)
316 r = WSARecv(s, &wbuf, 1, &b, &flags, NULL, NULL);
317 if (r == SOCKET_ERROR)
319 TranslateSocketError();
326 pgwin32_send(SOCKET s, char *buf, int len, int flags)
332 if (pgwin32_poll_signals())
339 * Readiness of socket to send data to UDP socket
340 * may be not true: socket can become busy again! So loop
341 * until send or error occurs.
344 r = WSASend(s, &wbuf, 1, &b, flags, NULL, NULL);
345 if (r != SOCKET_ERROR && b > 0)
346 /* Write succeeded right away */
349 if (r == SOCKET_ERROR &&
350 WSAGetLastError() != WSAEWOULDBLOCK)
352 TranslateSocketError();
356 /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */
358 if (pgwin32_waitforsinglesocket(s, FD_WRITE | FD_CLOSE) == 0)
367 * Wait for activity on one or more sockets.
368 * While waiting, allow signals to run
370 * NOTE! Currently does not implement exceptfds check,
371 * since it is not used in postgresql!
374 pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval * timeout)
376 WSAEVENT events[FD_SETSIZE * 2]; /* worst case is readfds totally
377 * different from writefds, so
378 * 2*FD_SETSIZE sockets */
379 SOCKET sockets[FD_SETSIZE * 2];
383 DWORD timeoutval = WSA_INFINITE;
388 Assert(exceptfds == NULL);
390 if (pgwin32_poll_signals())
393 FD_ZERO(&outreadfds);
394 FD_ZERO(&outwritefds);
397 * Write FDs are different in the way that it is only flagged by
398 * WSASelectEvent() if we have tried to write to them first. So try an
403 for (i = 0; i < writefds->fd_count; i++)
412 r = WSASend(writefds->fd_array[i], &buf, 1, &sent, 0, NULL, NULL);
413 if (r == 0) /* Completed - means things are fine! */
414 FD_SET(writefds->fd_array[i], &outwritefds);
416 { /* Not completed */
417 if (WSAGetLastError() != WSAEWOULDBLOCK)
420 * Not completed, and not just "would block", so an error
423 FD_SET(writefds->fd_array[i], &outwritefds);
426 if (outwritefds.fd_count > 0)
428 memcpy(writefds, &outwritefds, sizeof(fd_set));
431 return outwritefds.fd_count;
436 /* Now set up for an actual select */
440 /* timeoutval is in milliseconds */
441 timeoutval = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
446 for (i = 0; i < readfds->fd_count; i++)
448 events[numevents] = WSACreateEvent();
449 sockets[numevents] = readfds->fd_array[i];
453 if (writefds != NULL)
455 for (i = 0; i < writefds->fd_count; i++)
458 !FD_ISSET(writefds->fd_array[i], readfds))
460 /* If the socket is not in the read list */
461 events[numevents] = WSACreateEvent();
462 sockets[numevents] = writefds->fd_array[i];
468 for (i = 0; i < numevents; i++)
472 if (readfds && FD_ISSET(sockets[i], readfds))
473 flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
475 if (writefds && FD_ISSET(sockets[i], writefds))
476 flags |= FD_WRITE | FD_CLOSE;
478 if (WSAEventSelect(sockets[i], events[i], flags) == SOCKET_ERROR)
480 TranslateSocketError();
481 for (i = 0; i < numevents; i++)
482 WSACloseEvent(events[i]);
487 events[numevents] = pgwin32_signal_event;
488 r = WaitForMultipleObjectsEx(numevents + 1, events, FALSE, timeoutval, TRUE);
489 if (r != WAIT_TIMEOUT && r != WAIT_IO_COMPLETION && r != (WAIT_OBJECT_0 + numevents))
492 * We scan all events, even those not signalled, in case more than one
493 * event has been tagged but Wait.. can only return one.
495 WSANETWORKEVENTS resEvents;
497 for (i = 0; i < numevents; i++)
499 ZeroMemory(&resEvents, sizeof(resEvents));
500 if (WSAEnumNetworkEvents(sockets[i], events[i], &resEvents) == SOCKET_ERROR)
502 (errmsg_internal("failed to enumerate network events: %i", (int) GetLastError())));
504 if (readfds && FD_ISSET(sockets[i], readfds))
506 if ((resEvents.lNetworkEvents & FD_READ) ||
507 (resEvents.lNetworkEvents & FD_ACCEPT) ||
508 (resEvents.lNetworkEvents & FD_CLOSE))
510 FD_SET(sockets[i], &outreadfds);
514 /* Write activity? */
515 if (writefds && FD_ISSET(sockets[i], writefds))
517 if ((resEvents.lNetworkEvents & FD_WRITE) ||
518 (resEvents.lNetworkEvents & FD_CLOSE))
520 FD_SET(sockets[i], &outwritefds);
527 /* Clean up all handles */
528 for (i = 0; i < numevents; i++)
530 WSAEventSelect(sockets[i], events[i], 0);
531 WSACloseEvent(events[i]);
534 if (r == WSA_WAIT_TIMEOUT)
543 if (r == WAIT_OBJECT_0 + numevents)
545 pgwin32_dispatch_queued_signals();
554 /* Overwrite socket sets with our resulting values */
556 memcpy(readfds, &outreadfds, sizeof(fd_set));
558 memcpy(writefds, &outwritefds, sizeof(fd_set));
564 * Return win32 error string, since strerror can't
565 * handle winsock codes
567 static char wserrbuf[256];
569 pgwin32_socket_strerror(int err)
571 static HANDLE handleDLL = INVALID_HANDLE_VALUE;
573 if (handleDLL == INVALID_HANDLE_VALUE)
575 handleDLL = LoadLibraryEx("netmsg.dll", NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
576 if (handleDLL == NULL)
578 (errmsg_internal("Failed to load netmsg.dll: %i", (int) GetLastError())));
581 ZeroMemory(&wserrbuf, sizeof(wserrbuf));
582 if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE,
585 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
587 sizeof(wserrbuf) - 1,
590 /* Failed to get id */
591 sprintf(wserrbuf, "Unknown winsock error %i", err);