summaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-connect.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1998-07-09 03:29:11 +0000
committerMarc G. Fournier <scrappy@hub.org>1998-07-09 03:29:11 +0000
commita0659e3e2c79be49feb4aa527d823c71d7bcaf07 (patch)
tree7dc58e872cdfce999dd0848000fcd3f2e4edbafa /src/interfaces/libpq/fe-connect.c
parent8bf61820f033d7df0e89433a0272d7b2567378b8 (diff)
From: Tom Lane <tgl@sss.pgh.pa.us>
Making PQrequestCancel safe to call in a signal handler turned out to be much easier than I feared. So here are the diffs. Some notes: * I modified the postmaster's packet "iodone" callback interface to allow the callback routine to return a continue-or-drop-connection return code; this was necessary to allow the connection to be closed after receiving a Cancel, rather than proceeding to launch a new backend... Being a neatnik, I also made the iodone proc have a typechecked parameter list. * I deleted all code I could find that had to do with OOB. * I made some edits to ensure that all signals mentioned in the code are referred to symbolically not by numbers ("SIGUSR2" not "2"). I think Bruce may have already done at least some of the same edits; I hope that merging these patches is not too painful.
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r--src/interfaces/libpq/fe-connect.c107
1 files changed, 99 insertions, 8 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 672948a287a..47aa2b9bca0 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.72 1998/07/07 18:00:09 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.73 1998/07/09 03:29:07 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -499,13 +499,11 @@ connectDB(PGconn *conn)
{
PGresult *res;
struct hostent *hp;
-
StartupPacket sp;
AuthRequest areq;
int laddrlen = sizeof(SockAddr);
int portno,
- family,
- len;
+ family;
char beresp;
int on = 1;
@@ -561,11 +559,11 @@ connectDB(PGconn *conn)
(char *) hp->h_addr,
hp->h_length);
conn->raddr.in.sin_port = htons((unsigned short) (portno));
- len = sizeof(struct sockaddr_in);
+ conn->raddr_len = sizeof(struct sockaddr_in);
}
#ifndef WIN32
else
- len = UNIXSOCK_PATH(conn->raddr.un, portno);
+ conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
#endif
@@ -577,7 +575,7 @@ connectDB(PGconn *conn)
errno, strerror(errno));
goto connect_errReturn;
}
- if (connect(conn->sock, &conn->raddr.sa, len) < 0)
+ if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
{
(void) sprintf(conn->errorMessage,
"connectDB() failed: Is the postmaster running and accepting%s connections at '%s' on port '%s'?\n",
@@ -724,7 +722,7 @@ connectDB(PGconn *conn)
* A ReadyForQuery message indicates that startup is successful,
* but we might also get an Error message indicating failure.
* (Notice messages indicating nonfatal warnings are also allowed
- * by the protocol.)
+ * by the protocol, as is a BackendKeyData message.)
* Easiest way to handle this is to let PQgetResult() read the messages.
* We just have to fake it out about the state of the connection.
*/
@@ -994,6 +992,99 @@ PQreset(PGconn *conn)
}
}
+
+/*
+ * PQrequestCancel: attempt to request cancellation of the current operation.
+ *
+ * The return value is TRUE if the cancel request was successfully
+ * dispatched, FALSE if not (in which case errorMessage is set).
+ * Note: successful dispatch is no guarantee that there will be any effect at
+ * the backend. The application must read the operation result as usual.
+ *
+ * CAUTION: we want this routine to be safely callable from a signal handler
+ * (for example, an application might want to call it in a SIGINT handler).
+ * This means we cannot use any C library routine that might be non-reentrant.
+ * malloc/free are often non-reentrant, and anything that might call them is
+ * just as dangerous. We avoid sprintf here for that reason. Building up
+ * error messages with strcpy/strcat is tedious but should be quite safe.
+ */
+
+int
+PQrequestCancel(PGconn *conn)
+{
+ int tmpsock = -1;
+ struct {
+ uint32 packetlen;
+ CancelRequestPacket cp;
+ } crp;
+
+ /* Check we have an open connection */
+ if (!conn)
+ return FALSE;
+
+ if (conn->sock < 0)
+ {
+ strcpy(conn->errorMessage,
+ "PQrequestCancel() -- connection is not open\n");
+ return FALSE;
+ }
+
+ /*
+ * We need to open a temporary connection to the postmaster.
+ * Use the information saved by connectDB to do this with
+ * only kernel calls.
+ */
+ if ((tmpsock = socket(conn->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0)
+ {
+ strcpy(conn->errorMessage, "PQrequestCancel() -- socket() failed: ");
+ goto cancel_errReturn;
+ }
+ if (connect(tmpsock, &conn->raddr.sa, conn->raddr_len) < 0)
+ {
+ strcpy(conn->errorMessage, "PQrequestCancel() -- connect() failed: ");
+ goto cancel_errReturn;
+ }
+ /*
+ * We needn't set nonblocking I/O or NODELAY options here.
+ */
+
+ /* Create and send the cancel request packet. */
+
+ crp.packetlen = htonl((uint32) sizeof(crp));
+ crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE);
+ crp.cp.backendPID = htonl(conn->be_pid);
+ crp.cp.cancelAuthCode = htonl(conn->be_key);
+
+ if (send(tmpsock, (char*) &crp, sizeof(crp), 0) != (int) sizeof(crp))
+ {
+ strcpy(conn->errorMessage, "PQrequestCancel() -- send() failed: ");
+ goto cancel_errReturn;
+ }
+
+ /* Sent it, done */
+#ifdef WIN32
+ closesocket(tmpsock);
+#else
+ close(tmpsock);
+#endif
+
+ return TRUE;
+
+cancel_errReturn:
+ strcat(conn->errorMessage, strerror(errno));
+ strcat(conn->errorMessage, "\n");
+ if (tmpsock >= 0)
+ {
+#ifdef WIN32
+ closesocket(tmpsock);
+#else
+ close(tmpsock);
+#endif
+ }
+ return FALSE;
+}
+
+
/*
* PacketSend() -- send a single-packet message.
* this is like PacketSend(), defined in backend/libpq/pqpacket.c