1 /*-------------------------------------------------------------------------
4 * functions related to setting up a connection to the backend
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/interfaces/libpq/fe-cancel.c
13 *-------------------------------------------------------------------------
16 #include "postgres_fe.h"
21 #include "libpq-int.h"
22 #include "port/pg_bswap.h"
26 * pg_cancel (backing struct for PGcancel) stores all data necessary to send a
31 SockAddr raddr
; /* Remote address */
32 int be_pid
; /* PID of to-be-canceled backend */
33 int be_key
; /* cancel key of to-be-canceled backend */
34 int pgtcp_user_timeout
; /* tcp user timeout */
35 int keepalives
; /* use TCP keepalives? */
36 int keepalives_idle
; /* time between TCP keepalives */
37 int keepalives_interval
; /* time between TCP keepalive
39 int keepalives_count
; /* maximum number of TCP keepalive
45 * PQgetCancel: get a PGcancel structure corresponding to a connection.
47 * A copy is needed to be able to cancel a running query from a different
48 * thread. If the same structure is used all structure members would have
49 * to be individually locked (if the entire structure was locked, it would
50 * be impossible to cancel a synchronous query because the structure would
51 * have to stay locked for the duration of the query).
54 PQgetCancel(PGconn
*conn
)
61 if (conn
->sock
== PGINVALID_SOCKET
)
64 cancel
= malloc(sizeof(PGcancel
));
68 memcpy(&cancel
->raddr
, &conn
->raddr
, sizeof(SockAddr
));
69 cancel
->be_pid
= conn
->be_pid
;
70 cancel
->be_key
= conn
->be_key
;
71 /* We use -1 to indicate an unset connection option */
72 cancel
->pgtcp_user_timeout
= -1;
73 cancel
->keepalives
= -1;
74 cancel
->keepalives_idle
= -1;
75 cancel
->keepalives_interval
= -1;
76 cancel
->keepalives_count
= -1;
77 if (conn
->pgtcp_user_timeout
!= NULL
)
79 if (!pqParseIntParam(conn
->pgtcp_user_timeout
,
80 &cancel
->pgtcp_user_timeout
,
81 conn
, "tcp_user_timeout"))
84 if (conn
->keepalives
!= NULL
)
86 if (!pqParseIntParam(conn
->keepalives
,
91 if (conn
->keepalives_idle
!= NULL
)
93 if (!pqParseIntParam(conn
->keepalives_idle
,
94 &cancel
->keepalives_idle
,
95 conn
, "keepalives_idle"))
98 if (conn
->keepalives_interval
!= NULL
)
100 if (!pqParseIntParam(conn
->keepalives_interval
,
101 &cancel
->keepalives_interval
,
102 conn
, "keepalives_interval"))
105 if (conn
->keepalives_count
!= NULL
)
107 if (!pqParseIntParam(conn
->keepalives_count
,
108 &cancel
->keepalives_count
,
109 conn
, "keepalives_count"))
120 /* PQfreeCancel: free a cancel structure */
122 PQfreeCancel(PGcancel
*cancel
)
129 * Sets an integer socket option on a TCP socket, if the provided value is
130 * not negative. Returns false if setsockopt fails for some reason.
132 * CAUTION: This needs to be signal safe, since it's used by PQcancel.
134 #if defined(TCP_USER_TIMEOUT) || !defined(WIN32)
136 optional_setsockopt(int fd
, int protoid
, int optid
, int value
)
140 if (setsockopt(fd
, protoid
, optid
, (char *) &value
, sizeof(value
)) < 0)
148 * PQcancel: request query cancel
150 * The return value is true if the cancel request was successfully
151 * dispatched, false if not (in which case an error message is available).
152 * Note: successful dispatch is no guarantee that there will be any effect at
153 * the backend. The application must read the operation result as usual.
155 * On failure, an error message is stored in *errbuf, which must be of size
156 * errbufsize (recommended size is 256 bytes). *errbuf is not changed on
159 * CAUTION: we want this routine to be safely callable from a signal handler
160 * (for example, an application might want to call it in a SIGINT handler).
161 * This means we cannot use any C library routine that might be non-reentrant.
162 * malloc/free are often non-reentrant, and anything that might call them is
163 * just as dangerous. We avoid sprintf here for that reason. Building up
164 * error messages with strcpy/strcat is tedious but should be quite safe.
165 * We also save/restore errno in case the signal handler support doesn't.
168 PQcancel(PGcancel
*cancel
, char *errbuf
, int errbufsize
)
170 int save_errno
= SOCK_ERRNO
;
171 pgsocket tmpsock
= PGINVALID_SOCKET
;
176 CancelRequestPacket cp
;
181 strlcpy(errbuf
, "PQcancel() -- no cancel object supplied", errbufsize
);
182 /* strlcpy probably doesn't change errno, but be paranoid */
183 SOCK_ERRNO_SET(save_errno
);
188 * We need to open a temporary connection to the postmaster. Do this with
191 if ((tmpsock
= socket(cancel
->raddr
.addr
.ss_family
, SOCK_STREAM
, 0)) == PGINVALID_SOCKET
)
193 strlcpy(errbuf
, "PQcancel() -- socket() failed: ", errbufsize
);
194 goto cancel_errReturn
;
198 * Since this connection will only be used to send a single packet of
199 * data, we don't need NODELAY. We also don't set the socket to
200 * nonblocking mode, because the API definition of PQcancel requires the
201 * cancel to be sent in a blocking way.
203 * We do set socket options related to keepalives and other TCP timeouts.
204 * This ensures that this function does not block indefinitely when
205 * reasonable keepalive and timeout settings have been provided.
207 if (cancel
->raddr
.addr
.ss_family
!= AF_UNIX
&&
208 cancel
->keepalives
!= 0)
211 if (!optional_setsockopt(tmpsock
, SOL_SOCKET
, SO_KEEPALIVE
, 1))
213 strlcpy(errbuf
, "PQcancel() -- setsockopt(SO_KEEPALIVE) failed: ", errbufsize
);
214 goto cancel_errReturn
;
217 #ifdef PG_TCP_KEEPALIVE_IDLE
218 if (!optional_setsockopt(tmpsock
, IPPROTO_TCP
, PG_TCP_KEEPALIVE_IDLE
,
219 cancel
->keepalives_idle
))
221 strlcpy(errbuf
, "PQcancel() -- setsockopt(" PG_TCP_KEEPALIVE_IDLE_STR
") failed: ", errbufsize
);
222 goto cancel_errReturn
;
227 if (!optional_setsockopt(tmpsock
, IPPROTO_TCP
, TCP_KEEPINTVL
,
228 cancel
->keepalives_interval
))
230 strlcpy(errbuf
, "PQcancel() -- setsockopt(TCP_KEEPINTVL) failed: ", errbufsize
);
231 goto cancel_errReturn
;
236 if (!optional_setsockopt(tmpsock
, IPPROTO_TCP
, TCP_KEEPCNT
,
237 cancel
->keepalives_count
))
239 strlcpy(errbuf
, "PQcancel() -- setsockopt(TCP_KEEPCNT) failed: ", errbufsize
);
240 goto cancel_errReturn
;
246 #ifdef SIO_KEEPALIVE_VALS
247 if (!pqSetKeepalivesWin32(tmpsock
,
248 cancel
->keepalives_idle
,
249 cancel
->keepalives_interval
))
251 strlcpy(errbuf
, "PQcancel() -- WSAIoctl(SIO_KEEPALIVE_VALS) failed: ", errbufsize
);
252 goto cancel_errReturn
;
254 #endif /* SIO_KEEPALIVE_VALS */
257 /* TCP_USER_TIMEOUT works the same way on Unix and Windows */
258 #ifdef TCP_USER_TIMEOUT
259 if (!optional_setsockopt(tmpsock
, IPPROTO_TCP
, TCP_USER_TIMEOUT
,
260 cancel
->pgtcp_user_timeout
))
262 strlcpy(errbuf
, "PQcancel() -- setsockopt(TCP_USER_TIMEOUT) failed: ", errbufsize
);
263 goto cancel_errReturn
;
269 if (connect(tmpsock
, (struct sockaddr
*) &cancel
->raddr
.addr
,
270 cancel
->raddr
.salen
) < 0)
272 if (SOCK_ERRNO
== EINTR
)
273 /* Interrupted system call - we'll just try again */
275 strlcpy(errbuf
, "PQcancel() -- connect() failed: ", errbufsize
);
276 goto cancel_errReturn
;
279 /* Create and send the cancel request packet. */
281 crp
.packetlen
= pg_hton32((uint32
) sizeof(crp
));
282 crp
.cp
.cancelRequestCode
= (MsgType
) pg_hton32(CANCEL_REQUEST_CODE
);
283 crp
.cp
.backendPID
= pg_hton32(cancel
->be_pid
);
284 crp
.cp
.cancelAuthCode
= pg_hton32(cancel
->be_key
);
287 if (send(tmpsock
, (char *) &crp
, sizeof(crp
), 0) != (int) sizeof(crp
))
289 if (SOCK_ERRNO
== EINTR
)
290 /* Interrupted system call - we'll just try again */
292 strlcpy(errbuf
, "PQcancel() -- send() failed: ", errbufsize
);
293 goto cancel_errReturn
;
297 * Wait for the postmaster to close the connection, which indicates that
298 * it's processed the request. Without this delay, we might issue another
299 * command only to find that our cancel zaps that command instead of the
300 * one we thought we were canceling. Note we don't actually expect this
301 * read to obtain any data, we are just waiting for EOF to be signaled.
304 if (recv(tmpsock
, (char *) &crp
, 1, 0) < 0)
306 if (SOCK_ERRNO
== EINTR
)
307 /* Interrupted system call - we'll just try again */
309 /* we ignore other error conditions */
313 closesocket(tmpsock
);
314 SOCK_ERRNO_SET(save_errno
);
320 * Make sure we don't overflow the error buffer. Leave space for the \n at
321 * the end, and for the terminating zero.
323 maxlen
= errbufsize
- strlen(errbuf
) - 2;
327 * We can't invoke strerror here, since it's not signal-safe. Settle
328 * for printing the decimal value of errno. Even that has to be done
331 int val
= SOCK_ERRNO
;
335 bufp
= buf
+ sizeof(buf
) - 1;
339 *(--bufp
) = (val
% 10) + '0';
343 memcpy(bufp
, "error ", 6);
344 strncat(errbuf
, bufp
, maxlen
);
345 strcat(errbuf
, "\n");
347 if (tmpsock
!= PGINVALID_SOCKET
)
348 closesocket(tmpsock
);
349 SOCK_ERRNO_SET(save_errno
);
354 * PQrequestCancel: old, not thread-safe function for requesting query cancel
356 * Returns true if able to send the cancel request, false if not.
358 * On failure, the error message is saved in conn->errorMessage; this means
359 * that this can't be used when there might be other active operations on
360 * the connection object.
362 * NOTE: error messages will be cut off at the current size of the
363 * error message buffer, since we dare not try to expand conn->errorMessage!
366 PQrequestCancel(PGconn
*conn
)
371 /* Check we have an open connection */
375 if (conn
->sock
== PGINVALID_SOCKET
)
377 strlcpy(conn
->errorMessage
.data
,
378 "PQrequestCancel() -- connection is not open\n",
379 conn
->errorMessage
.maxlen
);
380 conn
->errorMessage
.len
= strlen(conn
->errorMessage
.data
);
381 conn
->errorReported
= 0;
386 cancel
= PQgetCancel(conn
);
389 r
= PQcancel(cancel
, conn
->errorMessage
.data
,
390 conn
->errorMessage
.maxlen
);
391 PQfreeCancel(cancel
);
395 strlcpy(conn
->errorMessage
.data
, "out of memory",
396 conn
->errorMessage
.maxlen
);
402 conn
->errorMessage
.len
= strlen(conn
->errorMessage
.data
);
403 conn
->errorReported
= 0;