#include "postgres.h"
Go to the source code of this file.
Functions | |
static void | TranslateSocketError (void) |
static int | pgwin32_poll_signals (void) |
static int | isDataGram (SOCKET s) |
int | pgwin32_waitforsinglesocket (SOCKET s, int what, int timeout) |
SOCKET | pgwin32_socket (int af, int type, int protocol) |
SOCKET | pgwin32_accept (SOCKET s, struct sockaddr *addr, int *addrlen) |
int | pgwin32_connect (SOCKET s, const struct sockaddr *addr, int addrlen) |
int | pgwin32_recv (SOCKET s, char *buf, int len, int f) |
int | pgwin32_send (SOCKET s, const void *buf, int len, int flags) |
int | pgwin32_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout) |
const char * | pgwin32_socket_strerror (int err) |
Variables | |
int | pgwin32_noblock = 0 |
static char | wserrbuf [256] |
static int isDataGram | ( | SOCKET | s | ) | [static] |
Definition at line 120 of file socket.c.
Referenced by pgwin32_waitforsinglesocket().
{ int type; int typelen = sizeof(type); if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &type, &typelen)) return 1; return (type == SOCK_DGRAM) ? 1 : 0; }
SOCKET pgwin32_accept | ( | SOCKET | s, | |
struct sockaddr * | addr, | |||
int * | addrlen | |||
) |
Definition at line 266 of file socket.c.
References NULL, pgwin32_poll_signals(), and TranslateSocketError().
{ SOCKET rs; /* * Poll for signals, but don't return with EINTR, since we don't handle * that in pqcomm.c */ pgwin32_poll_signals(); rs = WSAAccept(s, addr, addrlen, NULL, 0); if (rs == INVALID_SOCKET) { TranslateSocketError(); return INVALID_SOCKET; } return rs; }
int pgwin32_connect | ( | SOCKET | s, | |
const struct sockaddr * | addr, | |||
int | addrlen | |||
) |
Definition at line 288 of file socket.c.
References NULL, pgwin32_waitforsinglesocket(), and TranslateSocketError().
{ int r; r = WSAConnect(s, addr, addrlen, NULL, NULL, NULL, NULL); if (r == 0) return 0; if (WSAGetLastError() != WSAEWOULDBLOCK) { TranslateSocketError(); return -1; } while (pgwin32_waitforsinglesocket(s, FD_CONNECT, INFINITE) == 0) { /* Loop endlessly as long as we are just delivering signals */ } return 0; }
static int pgwin32_poll_signals | ( | void | ) | [static] |
Definition at line 108 of file socket.c.
References pgwin32_dispatch_queued_signals(), and UNBLOCKED_SIGNAL_QUEUE.
Referenced by pgwin32_accept(), pgwin32_recv(), pgwin32_select(), and pgwin32_send().
{ if (UNBLOCKED_SIGNAL_QUEUE()) { pgwin32_dispatch_queued_signals(); errno = EINTR; return 1; } return 0; }
int pgwin32_recv | ( | SOCKET | s, | |
char * | buf, | |||
int | len, | |||
int | f | |||
) |
Definition at line 311 of file socket.c.
References ereport, errmsg_internal(), NOTICE, NULL, pg_usleep(), pgwin32_noblock, pgwin32_poll_signals(), pgwin32_waitforsinglesocket(), and TranslateSocketError().
{ WSABUF wbuf; int r; DWORD b; DWORD flags = f; int n; if (pgwin32_poll_signals()) return -1; wbuf.len = len; wbuf.buf = buf; r = WSARecv(s, &wbuf, 1, &b, &flags, NULL, NULL); if (r != SOCKET_ERROR && b > 0) /* Read succeeded right away */ return b; if (r == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) { TranslateSocketError(); return -1; } if (pgwin32_noblock) { /* * No data received, and we are in "emulated non-blocking mode", so * return indicating that we'd block if we were to continue. */ errno = EWOULDBLOCK; return -1; } /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */ for (n = 0; n < 5; n++) { if (pgwin32_waitforsinglesocket(s, FD_READ | FD_CLOSE | FD_ACCEPT, INFINITE) == 0) return -1; /* errno already set */ r = WSARecv(s, &wbuf, 1, &b, &flags, NULL, NULL); if (r == SOCKET_ERROR) { if (WSAGetLastError() == WSAEWOULDBLOCK) { /* * There seem to be cases on win2k (at least) where WSARecv * can return WSAEWOULDBLOCK even when * pgwin32_waitforsinglesocket claims the socket is readable. * In this case, just sleep for a moment and try again. We try * up to 5 times - if it fails more than that it's not likely * to ever come back. */ pg_usleep(10000); continue; } TranslateSocketError(); return -1; } return b; } ereport(NOTICE, (errmsg_internal("could not read from ready socket (after retries)"))); errno = EWOULDBLOCK; return -1; }
int pgwin32_select | ( | int | nfds, | |
fd_set * | readfds, | |||
fd_set * | writefds, | |||
fd_set * | exceptfds, | |||
const struct timeval * | timeout | |||
) |
Definition at line 451 of file socket.c.
References Assert, buf, elog, ERROR, FALSE, i, NULL, pgwin32_dispatch_queued_signals(), pgwin32_poll_signals(), pgwin32_signal_event, TranslateSocketError(), and TRUE.
{ WSAEVENT events[FD_SETSIZE * 2]; /* worst case is readfds totally * different from writefds, so * 2*FD_SETSIZE sockets */ SOCKET sockets[FD_SETSIZE * 2]; int numevents = 0; int i; int r; DWORD timeoutval = WSA_INFINITE; FD_SET outreadfds; FD_SET outwritefds; int nummatches = 0; Assert(exceptfds == NULL); if (pgwin32_poll_signals()) return -1; FD_ZERO(&outreadfds); FD_ZERO(&outwritefds); /* * Write FDs are different in the way that it is only flagged by * WSASelectEvent() if we have tried to write to them first. So try an * empty write */ if (writefds) { for (i = 0; i < writefds->fd_count; i++) { char c; WSABUF buf; DWORD sent; buf.buf = &c; buf.len = 0; r = WSASend(writefds->fd_array[i], &buf, 1, &sent, 0, NULL, NULL); if (r == 0) /* Completed - means things are fine! */ FD_SET(writefds->fd_array[i], &outwritefds); else { /* Not completed */ if (WSAGetLastError() != WSAEWOULDBLOCK) /* * Not completed, and not just "would block", so an error * occurred */ FD_SET(writefds->fd_array[i], &outwritefds); } } if (outwritefds.fd_count > 0) { memcpy(writefds, &outwritefds, sizeof(fd_set)); if (readfds) FD_ZERO(readfds); return outwritefds.fd_count; } } /* Now set up for an actual select */ if (timeout != NULL) { /* timeoutval is in milliseconds */ timeoutval = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; } if (readfds != NULL) { for (i = 0; i < readfds->fd_count; i++) { events[numevents] = WSACreateEvent(); sockets[numevents] = readfds->fd_array[i]; numevents++; } } if (writefds != NULL) { for (i = 0; i < writefds->fd_count; i++) { if (!readfds || !FD_ISSET(writefds->fd_array[i], readfds)) { /* If the socket is not in the read list */ events[numevents] = WSACreateEvent(); sockets[numevents] = writefds->fd_array[i]; numevents++; } } } for (i = 0; i < numevents; i++) { int flags = 0; if (readfds && FD_ISSET(sockets[i], readfds)) flags |= FD_READ | FD_ACCEPT | FD_CLOSE; if (writefds && FD_ISSET(sockets[i], writefds)) flags |= FD_WRITE | FD_CLOSE; if (WSAEventSelect(sockets[i], events[i], flags) != 0) { TranslateSocketError(); /* release already-assigned event objects */ while (--i >= 0) WSAEventSelect(sockets[i], NULL, 0); for (i = 0; i < numevents; i++) WSACloseEvent(events[i]); return -1; } } events[numevents] = pgwin32_signal_event; r = WaitForMultipleObjectsEx(numevents + 1, events, FALSE, timeoutval, TRUE); if (r != WAIT_TIMEOUT && r != WAIT_IO_COMPLETION && r != (WAIT_OBJECT_0 + numevents)) { /* * We scan all events, even those not signalled, in case more than one * event has been tagged but Wait.. can only return one. */ WSANETWORKEVENTS resEvents; for (i = 0; i < numevents; i++) { ZeroMemory(&resEvents, sizeof(resEvents)); if (WSAEnumNetworkEvents(sockets[i], events[i], &resEvents) != 0) elog(ERROR, "failed to enumerate network events: error code %u", WSAGetLastError()); /* Read activity? */ if (readfds && FD_ISSET(sockets[i], readfds)) { if ((resEvents.lNetworkEvents & FD_READ) || (resEvents.lNetworkEvents & FD_ACCEPT) || (resEvents.lNetworkEvents & FD_CLOSE)) { FD_SET(sockets[i], &outreadfds); nummatches++; } } /* Write activity? */ if (writefds && FD_ISSET(sockets[i], writefds)) { if ((resEvents.lNetworkEvents & FD_WRITE) || (resEvents.lNetworkEvents & FD_CLOSE)) { FD_SET(sockets[i], &outwritefds); nummatches++; } } } } /* Clean up all the event objects */ for (i = 0; i < numevents; i++) { WSAEventSelect(sockets[i], NULL, 0); WSACloseEvent(events[i]); } if (r == WSA_WAIT_TIMEOUT) { if (readfds) FD_ZERO(readfds); if (writefds) FD_ZERO(writefds); return 0; } if (r == WAIT_OBJECT_0 + numevents) { pgwin32_dispatch_queued_signals(); errno = EINTR; if (readfds) FD_ZERO(readfds); if (writefds) FD_ZERO(writefds); return -1; } /* Overwrite socket sets with our resulting values */ if (readfds) memcpy(readfds, &outreadfds, sizeof(fd_set)); if (writefds) memcpy(writefds, &outwritefds, sizeof(fd_set)); return nummatches; }
int pgwin32_send | ( | SOCKET | s, | |
const void * | buf, | |||
int | len, | |||
int | flags | |||
) |
Definition at line 393 of file socket.c.
References NULL, pgwin32_noblock, pgwin32_poll_signals(), pgwin32_waitforsinglesocket(), and TranslateSocketError().
{ WSABUF wbuf; int r; DWORD b; if (pgwin32_poll_signals()) return -1; wbuf.len = len; wbuf.buf = (char *) buf; /* * Readiness of socket to send data to UDP socket may be not true: socket * can become busy again! So loop until send or error occurs. */ for (;;) { r = WSASend(s, &wbuf, 1, &b, flags, NULL, NULL); if (r != SOCKET_ERROR && b > 0) /* Write succeeded right away */ return b; if (r == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) { TranslateSocketError(); return -1; } if (pgwin32_noblock) { /* * No data sent, and we are in "emulated non-blocking mode", so * return indicating that we'd block if we were to continue. */ errno = EWOULDBLOCK; return -1; } /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */ if (pgwin32_waitforsinglesocket(s, FD_WRITE | FD_CLOSE, INFINITE) == 0) return -1; } return -1; }
SOCKET pgwin32_socket | ( | int | af, | |
int | type, | |||
int | protocol | |||
) |
Definition at line 242 of file socket.c.
References NULL, and TranslateSocketError().
{ SOCKET s; unsigned long on = 1; s = WSASocket(af, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED); if (s == INVALID_SOCKET) { TranslateSocketError(); return INVALID_SOCKET; } if (ioctlsocket(s, FIONBIO, &on)) { TranslateSocketError(); return INVALID_SOCKET; } errno = 0; return s; }
const char* pgwin32_socket_strerror | ( | int | err | ) |
Definition at line 652 of file socket.c.
References ereport, errmsg_internal(), FATAL, NULL, and wserrbuf.
Referenced by useful_strerror().
{ static HANDLE handleDLL = INVALID_HANDLE_VALUE; if (handleDLL == INVALID_HANDLE_VALUE) { handleDLL = LoadLibraryEx("netmsg.dll", NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); if (handleDLL == NULL) ereport(FATAL, (errmsg_internal("could not load netmsg.dll: error code %lu", GetLastError()))); } ZeroMemory(&wserrbuf, sizeof(wserrbuf)); if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, handleDLL, err, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), wserrbuf, sizeof(wserrbuf) - 1, NULL) == 0) { /* Failed to get id */ sprintf(wserrbuf, "unrecognized winsock error %d", err); } return wserrbuf; }
int pgwin32_waitforsinglesocket | ( | SOCKET | s, | |
int | what, | |||
int | timeout | |||
) |
Definition at line 132 of file socket.c.
References buf, ereport, errmsg_internal(), ERROR, FALSE, isDataGram(), NULL, pgwin32_dispatch_queued_signals(), pgwin32_signal_event, TranslateSocketError(), and TRUE.
Referenced by pgwin32_connect(), pgwin32_recv(), pgwin32_send(), secure_read(), and secure_write().
{ static HANDLE waitevent = INVALID_HANDLE_VALUE; static SOCKET current_socket = -1; static int isUDP = 0; HANDLE events[2]; int r; /* Create an event object just once and use it on all future calls */ if (waitevent == INVALID_HANDLE_VALUE) { waitevent = CreateEvent(NULL, TRUE, FALSE, NULL); if (waitevent == INVALID_HANDLE_VALUE) ereport(ERROR, (errmsg_internal("could not create socket waiting event: error code %lu", GetLastError()))); } else if (!ResetEvent(waitevent)) ereport(ERROR, (errmsg_internal("could not reset socket waiting event: error code %lu", GetLastError()))); /* * Track whether socket is UDP or not. (NB: most likely, this is both * useless and wrong; there is no reason to think that the behavior of * WSAEventSelect is different for TCP and UDP.) */ if (current_socket != s) isUDP = isDataGram(s); current_socket = s; /* * Attach event to socket. NOTE: we must detach it again before * returning, since other bits of code may try to attach other events to * the socket. */ if (WSAEventSelect(s, waitevent, what) != 0) { TranslateSocketError(); return 0; } events[0] = pgwin32_signal_event; events[1] = waitevent; /* * Just a workaround of unknown locking problem with writing in UDP socket * under high load: Client's pgsql backend sleeps infinitely in * WaitForMultipleObjectsEx, pgstat process sleeps in pgwin32_select(). * So, we will wait with small timeout(0.1 sec) and if sockect is still * blocked, try WSASend (see comments in pgwin32_select) and wait again. */ if ((what & FD_WRITE) && isUDP) { for (;;) { r = WaitForMultipleObjectsEx(2, events, FALSE, 100, TRUE); if (r == WAIT_TIMEOUT) { char c; WSABUF buf; DWORD sent; buf.buf = &c; buf.len = 0; r = WSASend(s, &buf, 1, &sent, 0, NULL, NULL); if (r == 0) /* Completed - means things are fine! */ { WSAEventSelect(s, NULL, 0); return 1; } else if (WSAGetLastError() != WSAEWOULDBLOCK) { TranslateSocketError(); WSAEventSelect(s, NULL, 0); return 0; } } else break; } } else r = WaitForMultipleObjectsEx(2, events, FALSE, timeout, TRUE); WSAEventSelect(s, NULL, 0); if (r == WAIT_OBJECT_0 || r == WAIT_IO_COMPLETION) { pgwin32_dispatch_queued_signals(); errno = EINTR; return 0; } if (r == WAIT_OBJECT_0 + 1) return 1; if (r == WAIT_TIMEOUT) { errno = EWOULDBLOCK; return 0; } ereport(ERROR, (errmsg_internal("unrecognized return value from WaitForMultipleObjects: %d (error code %lu)", r, GetLastError()))); return 0; }
static void TranslateSocketError | ( | void | ) | [static] |
Definition at line 46 of file socket.c.
References ereport, errmsg_internal(), and NOTICE.
Referenced by pgwin32_accept(), pgwin32_connect(), pgwin32_recv(), pgwin32_select(), pgwin32_send(), pgwin32_socket(), and pgwin32_waitforsinglesocket().
{ switch (WSAGetLastError()) { case WSANOTINITIALISED: case WSAENETDOWN: case WSAEINPROGRESS: case WSAEINVAL: case WSAESOCKTNOSUPPORT: case WSAEFAULT: case WSAEINVALIDPROVIDER: case WSAEINVALIDPROCTABLE: case WSAEMSGSIZE: errno = EINVAL; break; case WSAEAFNOSUPPORT: errno = EAFNOSUPPORT; break; case WSAEMFILE: errno = EMFILE; break; case WSAENOBUFS: errno = ENOBUFS; break; case WSAEPROTONOSUPPORT: case WSAEPROTOTYPE: errno = EPROTONOSUPPORT; break; case WSAECONNREFUSED: errno = ECONNREFUSED; break; case WSAEINTR: errno = EINTR; break; case WSAENOTSOCK: errno = EBADFD; break; case WSAEOPNOTSUPP: errno = EOPNOTSUPP; break; case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break; case WSAEACCES: errno = EACCES; break; case WSAENOTCONN: case WSAENETRESET: case WSAECONNRESET: case WSAESHUTDOWN: case WSAECONNABORTED: case WSAEDISCON: errno = ECONNREFUSED; /* ENOTCONN? */ break; default: ereport(NOTICE, (errmsg_internal("unrecognized win32 socket error code: %d", WSAGetLastError()))); errno = EINVAL; } }
int pgwin32_noblock = 0 |
Definition at line 28 of file socket.c.
Referenced by PgstatCollectorMain(), pgwin32_recv(), pgwin32_send(), and pq_set_nonblocking().
char wserrbuf[256] [static] |
Definition at line 650 of file socket.c.
Referenced by pgwin32_socket_strerror().