On Sun, Apr 6, 2014 at 11:45:59AM +0530, Amit Kapila wrote:
> On Tue, Apr 1, 2014 at 6:31 AM, Bruce Momjian <[email protected]> wrote:
> > I reviewed this patch and you are correct that we are not handling
> > socket() and accept() returns properly on Windows. We were doing it
> > properly in most place in the backend, but your patch fixes the
> > remaining places:
> >
> >
> > http://msdn.microsoft.com/en-us/library/windows/desktop/ms740516%28v=vs.85%29.aspx
> >
> > However, libpq doesn't seem to be doing much to handle Windows properly
> > in this area. I have adjusted libpq to map socket to -1, but the proper
> > fix is to distribute pgsocket and PGINVALID_SOCKET checks throughout the
> > libpq code. I am not sure how to handle PQsocket() --- should it still
> > return -1?
>
> I think changing PQsocket() can impact all existing applications as
> it is mentioned in docs that "result of -1 indicates that no server
> connection is currently open.". Do you see any compelling need to
> change return value of PQSocket() after your patch?
No, I do not. In fact, the SSL_get_fd() call in secure_read() returns a
signed integer too, and that is passed around like a socket, so in fact
the SSL API doesn't even allow us to get an unsigned value on Windows in
all cases.
> > Having the return value be conditional on the operating
> > system is ugly. How much of this should be backpatched?
>
> I think it's okay to back patch all the changes.
> Is there any part in patch which you feel is risky to back patch?
Well, we would not backpatch this if it is just a stylistic fix, and I
am starting to think it just a style issue. This MSDN website says -1,
SOCKET_ERROR, and INVALID_SOCKET are very similar:
http://msdn.microsoft.com/en-us/library/windows/desktop/cc507522%28v=vs.85%29.aspx
and this Stackoverflow thread says the same:
http://stackoverflow.com/questions/10817252/why-is-invalid-socket-defined-as-0-in-winsock2-h-c
In fact, this C program compiled by gcc on Debian issues no compiler
warnings and returns 'hello', showing that -1 and ~0 compare as equal:
int
main(int argc, char **argv)
{
int i;
unsigned int j;
i = -1;
j = ~0;
if (i == j)
printf("hello\n");
return 0;
}
meaning our incorrect syntax is computed correctly.
> > Why aren't we
> > getting warnings on Windows about assigning the socket() return value to
> > an integer?
>
> I think by default Windows doesn't give warning for such code even at Warning
> level 4. I have found one related link:
> http://stackoverflow.com/questions/75385/make-vs-compiler-catch-signed-unsigned-assignments
>
> > Updated patch attached.
>
> It seems you have missed to change at below places.
>
> 1.
> int
> pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
> sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
> if (sock == SOCKET_ERROR)
Well, the actual problem here is that WSASocket() returns INVALID_SOCKET
per the documentation, not SOCKET_ERROR. I did not use PGINVALID_SOCKET
here because this is Windows-specific code, defining 'sock' as SOCKET.
We could have sock defined as pgsocket, but because this is Windows code
already, it doesn't seem wise to mix portability code in there.
> 2.
> pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout)
> {
> static HANDLE waitevent = INVALID_HANDLE_VALUE;
> static SOCKET current_socket = -1;
Yes, that -1 is wrong and I have changed it to INVALID_SOCKET, again
using the same rules that say PGINVALID_SOCKET doesn't make sense here
as it is Windows-specific code.
I am attaching an updated patch, which explains the PQsocket() return
value issue, and fixes the items listed above. I am inclined to apply
this just to head for correctness, and modify libpq to use pgsocket
consistently in a follow-up patch.
This is not like the readdir() fix we had to backpatch because that was
clearly not catching errors.
--
Bruce Momjian <[email protected]> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ Everyone has their own god. +
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
new file mode 100644
index d062c1d..8fa9aa7
*** a/src/backend/libpq/auth.c
--- b/src/backend/libpq/auth.c
*************** ident_inet(hbaPort *port)
*** 1463,1469 ****
sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype,
ident_serv->ai_protocol);
! if (sock_fd < 0)
{
ereport(LOG,
(errcode_for_socket_access(),
--- 1463,1469 ----
sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype,
ident_serv->ai_protocol);
! if (sock_fd == PGINVALID_SOCKET)
{
ereport(LOG,
(errcode_for_socket_access(),
*************** ident_inet(hbaPort *port)
*** 1543,1549 ****
ident_response)));
ident_inet_done:
! if (sock_fd >= 0)
closesocket(sock_fd);
pg_freeaddrinfo_all(remote_addr.addr.ss_family, ident_serv);
pg_freeaddrinfo_all(local_addr.addr.ss_family, la);
--- 1543,1549 ----
ident_response)));
ident_inet_done:
! if (sock_fd != PGINVALID_SOCKET)
closesocket(sock_fd);
pg_freeaddrinfo_all(remote_addr.addr.ss_family, ident_serv);
pg_freeaddrinfo_all(local_addr.addr.ss_family, la);
*************** CheckRADIUSAuth(Port *port)
*** 2361,2367 ****
packet->length = htons(packet->length);
sock = socket(serveraddrs[0].ai_family, SOCK_DGRAM, 0);
! if (sock < 0)
{
ereport(LOG,
(errmsg("could not create RADIUS socket: %m")));
--- 2361,2367 ----
packet->length = htons(packet->length);
sock = socket(serveraddrs[0].ai_family, SOCK_DGRAM, 0);
! if (sock == PGINVALID_SOCKET)
{
ereport(LOG,
(errmsg("could not create RADIUS socket: %m")));
diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ip.c
new file mode 100644
index 7e8fc78..acdbab0
*** a/src/backend/libpq/ip.c
--- b/src/backend/libpq/ip.c
*************** pg_foreach_ifaddr(PgIfAddrCallback callb
*** 547,553 ****
int error;
sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
! if (sock == SOCKET_ERROR)
return -1;
while (n_ii < 1024)
--- 547,553 ----
int error;
sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
! if (sock == INVALID_SOCKET)
return -1;
while (n_ii < 1024)
*************** pg_foreach_ifaddr(PgIfAddrCallback callb
*** 670,676 ****
total;
sock = socket(AF_INET, SOCK_DGRAM, 0);
! if (sock == -1)
return -1;
while (n_buffer < 1024 * 100)
--- 670,676 ----
total;
sock = socket(AF_INET, SOCK_DGRAM, 0);
! if (sock == PGINVALID_SOCKET)
return -1;
while (n_buffer < 1024 * 100)
*************** pg_foreach_ifaddr(PgIfAddrCallback callb
*** 711,717 ****
#ifdef HAVE_IPV6
/* We'll need an IPv6 socket too for the SIOCGLIFNETMASK ioctls */
sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
! if (sock6 == -1)
{
free(buffer);
close(sock);
--- 711,717 ----
#ifdef HAVE_IPV6
/* We'll need an IPv6 socket too for the SIOCGLIFNETMASK ioctls */
sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
! if (sock6 == PGINVALID_SOCKET)
{
free(buffer);
close(sock);
*************** pg_foreach_ifaddr(PgIfAddrCallback callb
*** 788,797 ****
char *ptr,
*buffer = NULL;
size_t n_buffer = 1024;
! int sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
! if (sock == -1)
return -1;
while (n_buffer < 1024 * 100)
--- 788,797 ----
char *ptr,
*buffer = NULL;
size_t n_buffer = 1024;
! pgsocket sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
! if (sock == PGINVALID_SOCKET)
return -1;
while (n_buffer < 1024 * 100)
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
new file mode 100644
index 1eae183..0179451
*** a/src/backend/libpq/pqcomm.c
--- b/src/backend/libpq/pqcomm.c
*************** StreamServerPort(int family, char *hostN
*** 392,398 ****
break;
}
! if ((fd = socket(addr->ai_family, SOCK_STREAM, 0)) < 0)
{
ereport(LOG,
(errcode_for_socket_access(),
--- 392,398 ----
break;
}
! if ((fd = socket(addr->ai_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET)
{
ereport(LOG,
(errcode_for_socket_access(),
*************** StreamConnection(pgsocket server_fd, Por
*** 632,638 ****
port->raddr.salen = sizeof(port->raddr.addr);
if ((port->sock = accept(server_fd,
(struct sockaddr *) & port->raddr.addr,
! &port->raddr.salen)) < 0)
{
ereport(LOG,
(errcode_for_socket_access(),
--- 632,638 ----
port->raddr.salen = sizeof(port->raddr.addr);
if ((port->sock = accept(server_fd,
(struct sockaddr *) & port->raddr.addr,
! &port->raddr.salen)) == PGINVALID_SOCKET)
{
ereport(LOG,
(errcode_for_socket_access(),
diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.c
new file mode 100644
index 4f1099f..adc0e02
*** a/src/backend/port/win32/socket.c
--- b/src/backend/port/win32/socket.c
*************** int
*** 132,138 ****
pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout)
{
static HANDLE waitevent = INVALID_HANDLE_VALUE;
! static SOCKET current_socket = -1;
static int isUDP = 0;
HANDLE events[2];
int r;
--- 132,138 ----
pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout)
{
static HANDLE waitevent = INVALID_HANDLE_VALUE;
! static SOCKET current_socket = INVALID_SOCKET;
static int isUDP = 0;
HANDLE events[2];
int r;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
new file mode 100644
index bb771a6..b573fd8
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
*************** ConnCreate(int serverFd)
*** 2169,2175 ****
if (StreamConnection(serverFd, port) != STATUS_OK)
{
! if (port->sock >= 0)
StreamClose(port->sock);
ConnFree(port);
return NULL;
--- 2169,2175 ----
if (StreamConnection(serverFd, port) != STATUS_OK)
{
! if (port->sock != PGINVALID_SOCKET)
StreamClose(port->sock);
ConnFree(port);
return NULL;
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
new file mode 100644
index d53c41f..459e4a4
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
*************** keep_going: /* We will come back to
*** 1632,1639 ****
conn->raddr.salen = addr_cur->ai_addrlen;
/* Open a socket */
! conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
! if (conn->sock < 0)
{
/*
* ignore socket() failure if we have more addresses
--- 1632,1654 ----
conn->raddr.salen = addr_cur->ai_addrlen;
/* Open a socket */
! {
! /*
! * While we use 'pgsocket' as the socket type in the
! * backend, we use 'int' for libpq socket values.
! * This requires us to map PGINVALID_SOCKET to -1
! * on Windows.
! * See http://msdn.microsoft.com/en-us/library/windows/desktop/ms740516%28v=vs.85%29.aspx
! */
! pgsocket sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
! #ifdef WIN32
! if (sock == PGINVALID_SOCKET)
! conn->sock = -1;
! else
! #endif
! conn->sock = sock;
! }
! if (conn->sock == -1)
{
/*
* ignore socket() failure if we have more addresses
*************** internal_cancel(SockAddr *raddr, int be_
*** 3136,3142 ****
char *errbuf, int errbufsize)
{
int save_errno = SOCK_ERRNO;
! int tmpsock = -1;
char sebuf[256];
int maxlen;
struct
--- 3151,3157 ----
char *errbuf, int errbufsize)
{
int save_errno = SOCK_ERRNO;
! pgsocket tmpsock = PGINVALID_SOCKET;
char sebuf[256];
int maxlen;
struct
*************** internal_cancel(SockAddr *raddr, int be_
*** 3149,3155 ****
* We need to open a temporary connection to the postmaster. Do this with
* only kernel calls.
*/
! if ((tmpsock = socket(raddr->addr.ss_family, SOCK_STREAM, 0)) < 0)
{
strlcpy(errbuf, "PQcancel() -- socket() failed: ", errbufsize);
goto cancel_errReturn;
--- 3164,3170 ----
* We need to open a temporary connection to the postmaster. Do this with
* only kernel calls.
*/
! if ((tmpsock = socket(raddr->addr.ss_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET)
{
strlcpy(errbuf, "PQcancel() -- socket() failed: ", errbufsize);
goto cancel_errReturn;
*************** cancel_errReturn:
*** 3220,3226 ****
maxlen);
strcat(errbuf, "\n");
}
! if (tmpsock >= 0)
closesocket(tmpsock);
SOCK_ERRNO_SET(save_errno);
return FALSE;
--- 3235,3241 ----
maxlen);
strcat(errbuf, "\n");
}
! if (tmpsock != PGINVALID_SOCKET)
closesocket(tmpsock);
SOCK_ERRNO_SET(save_errno);
return FALSE;
*************** PQerrorMessage(const PGconn *conn)
*** 5300,5308 ****
--- 5315,5333 ----
return conn->errorMessage.data;
}
+ /*
+ * In Windows, socket values are unsigned, and an invalid socket value
+ * (INVALID_SOCKET) is ~0, which equals -1 in comparisons (with no compiler
+ * warning). Ideally we would return an unsigned value for PQsocket() on
+ * Windows, but that would cause the function's return value to differ from
+ * Unix, so we just return -1 for invalid sockets.
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/cc507522%28v=vs.85%29.aspx
+ * http://stackoverflow.com/questions/10817252/why-is-invalid-socket-defined-as-0-in-winsock2-h-c
+ */
int
PQsocket(const PGconn *conn)
{
+
if (!conn)
return -1;
return conn->sock;
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
new file mode 100644
index 22bbe4a..ee975d4
*** a/src/interfaces/libpq/libpq-int.h
--- b/src/interfaces/libpq/libpq-int.h
*************** struct pg_conn
*** 364,369 ****
--- 364,370 ----
PGnotify *notifyTail; /* newest unreported Notify msg */
/* Connection data */
+ /* See PQconnectPoll() for how we use 'int' and not 'pgsocket'. */
int sock; /* Unix FD for socket, -1 if not connected */
SockAddr laddr; /* Local address */
SockAddr raddr; /* Remote address */
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers