PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
fe-cancel.c File Reference
#include "postgres_fe.h"
#include <unistd.h>
#include "libpq-fe.h"
#include "libpq-int.h"
#include "port/pg_bswap.h"
Include dependency graph for fe-cancel.c:

Go to the source code of this file.

Data Structures

struct  pg_cancel_conn
 
struct  pg_cancel
 

Functions

PGcancelConnPQcancelCreate (PGconn *conn)
 
int PQcancelBlocking (PGcancelConn *cancelConn)
 
int PQcancelStart (PGcancelConn *cancelConn)
 
PostgresPollingStatusType PQcancelPoll (PGcancelConn *cancelConn)
 
ConnStatusType PQcancelStatus (const PGcancelConn *cancelConn)
 
int PQcancelSocket (const PGcancelConn *cancelConn)
 
char * PQcancelErrorMessage (const PGcancelConn *cancelConn)
 
void PQcancelReset (PGcancelConn *cancelConn)
 
void PQcancelFinish (PGcancelConn *cancelConn)
 
PGcancelPQgetCancel (PGconn *conn)
 
int PQsendCancelRequest (PGconn *cancelConn)
 
void PQfreeCancel (PGcancel *cancel)
 
static bool optional_setsockopt (int fd, int protoid, int optid, int value)
 
int PQcancel (PGcancel *cancel, char *errbuf, int errbufsize)
 
int PQrequestCancel (PGconn *conn)
 

Function Documentation

◆ optional_setsockopt()

static bool optional_setsockopt ( int  fd,
int  protoid,
int  optid,
int  value 
)
static

Definition at line 498 of file fe-cancel.c.

499{
500 if (value < 0)
501 return true;
502 if (setsockopt(fd, protoid, optid, (char *) &value, sizeof(value)) < 0)
503 return false;
504 return true;
505}
static struct @165 value
static int fd(const char *x, int i)
Definition: preproc-init.c:105

References fd(), and value.

Referenced by PQcancel().

◆ PQcancel()

int PQcancel ( PGcancel cancel,
char *  errbuf,
int  errbufsize 
)

Definition at line 530 of file fe-cancel.c.

531{
532 int save_errno = SOCK_ERRNO;
533 pgsocket tmpsock = PGINVALID_SOCKET;
534 int maxlen;
535 char recvbuf;
536 int cancel_pkt_len;
537
538 if (!cancel)
539 {
540 strlcpy(errbuf, "PQcancel() -- no cancel object supplied", errbufsize);
541 /* strlcpy probably doesn't change errno, but be paranoid */
542 SOCK_ERRNO_SET(save_errno);
543 return false;
544 }
545
546 /*
547 * We need to open a temporary connection to the postmaster. Do this with
548 * only kernel calls.
549 */
550 if ((tmpsock = socket(cancel->raddr.addr.ss_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET)
551 {
552 strlcpy(errbuf, "PQcancel() -- socket() failed: ", errbufsize);
553 goto cancel_errReturn;
554 }
555
556 /*
557 * Since this connection will only be used to send a single packet of
558 * data, we don't need NODELAY. We also don't set the socket to
559 * nonblocking mode, because the API definition of PQcancel requires the
560 * cancel to be sent in a blocking way.
561 *
562 * We do set socket options related to keepalives and other TCP timeouts.
563 * This ensures that this function does not block indefinitely when
564 * reasonable keepalive and timeout settings have been provided.
565 */
566 if (cancel->raddr.addr.ss_family != AF_UNIX &&
567 cancel->keepalives != 0)
568 {
569#ifndef WIN32
570 if (!optional_setsockopt(tmpsock, SOL_SOCKET, SO_KEEPALIVE, 1))
571 {
572 strlcpy(errbuf, "PQcancel() -- setsockopt(SO_KEEPALIVE) failed: ", errbufsize);
573 goto cancel_errReturn;
574 }
575
576#ifdef PG_TCP_KEEPALIVE_IDLE
577 if (!optional_setsockopt(tmpsock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE,
578 cancel->keepalives_idle))
579 {
580 strlcpy(errbuf, "PQcancel() -- setsockopt(" PG_TCP_KEEPALIVE_IDLE_STR ") failed: ", errbufsize);
581 goto cancel_errReturn;
582 }
583#endif
584
585#ifdef TCP_KEEPINTVL
586 if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_KEEPINTVL,
587 cancel->keepalives_interval))
588 {
589 strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_KEEPINTVL) failed: ", errbufsize);
590 goto cancel_errReturn;
591 }
592#endif
593
594#ifdef TCP_KEEPCNT
595 if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_KEEPCNT,
596 cancel->keepalives_count))
597 {
598 strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_KEEPCNT) failed: ", errbufsize);
599 goto cancel_errReturn;
600 }
601#endif
602
603#else /* WIN32 */
604
605#ifdef SIO_KEEPALIVE_VALS
606 if (!pqSetKeepalivesWin32(tmpsock,
607 cancel->keepalives_idle,
608 cancel->keepalives_interval))
609 {
610 strlcpy(errbuf, "PQcancel() -- WSAIoctl(SIO_KEEPALIVE_VALS) failed: ", errbufsize);
611 goto cancel_errReturn;
612 }
613#endif /* SIO_KEEPALIVE_VALS */
614#endif /* WIN32 */
615
616 /* TCP_USER_TIMEOUT works the same way on Unix and Windows */
617#ifdef TCP_USER_TIMEOUT
618 if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_USER_TIMEOUT,
619 cancel->pgtcp_user_timeout))
620 {
621 strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_USER_TIMEOUT) failed: ", errbufsize);
622 goto cancel_errReturn;
623 }
624#endif
625 }
626
627retry3:
628 if (connect(tmpsock, (struct sockaddr *) &cancel->raddr.addr,
629 cancel->raddr.salen) < 0)
630 {
631 if (SOCK_ERRNO == EINTR)
632 /* Interrupted system call - we'll just try again */
633 goto retry3;
634 strlcpy(errbuf, "PQcancel() -- connect() failed: ", errbufsize);
635 goto cancel_errReturn;
636 }
637
638 cancel_pkt_len = pg_ntoh32(cancel->cancel_pkt_len);
639
640retry4:
641
642 /*
643 * Send the cancel request packet. It starts with the message length at
644 * cancel_pkt_len, followed by the actual packet.
645 */
646 if (send(tmpsock, (char *) &cancel->cancel_pkt_len, cancel_pkt_len, 0) != cancel_pkt_len)
647 {
648 if (SOCK_ERRNO == EINTR)
649 /* Interrupted system call - we'll just try again */
650 goto retry4;
651 strlcpy(errbuf, "PQcancel() -- send() failed: ", errbufsize);
652 goto cancel_errReturn;
653 }
654
655 /*
656 * Wait for the postmaster to close the connection, which indicates that
657 * it's processed the request. Without this delay, we might issue another
658 * command only to find that our cancel zaps that command instead of the
659 * one we thought we were canceling. Note we don't actually expect this
660 * read to obtain any data, we are just waiting for EOF to be signaled.
661 */
662retry5:
663 if (recv(tmpsock, &recvbuf, 1, 0) < 0)
664 {
665 if (SOCK_ERRNO == EINTR)
666 /* Interrupted system call - we'll just try again */
667 goto retry5;
668 /* we ignore other error conditions */
669 }
670
671 /* All done */
672 closesocket(tmpsock);
673 SOCK_ERRNO_SET(save_errno);
674 return true;
675
676cancel_errReturn:
677
678 /*
679 * Make sure we don't overflow the error buffer. Leave space for the \n at
680 * the end, and for the terminating zero.
681 */
682 maxlen = errbufsize - strlen(errbuf) - 2;
683 if (maxlen >= 0)
684 {
685 /*
686 * We can't invoke strerror here, since it's not signal-safe. Settle
687 * for printing the decimal value of errno. Even that has to be done
688 * the hard way.
689 */
690 int val = SOCK_ERRNO;
691 char buf[32];
692 char *bufp;
693
694 bufp = buf + sizeof(buf) - 1;
695 *bufp = '\0';
696 do
697 {
698 *(--bufp) = (val % 10) + '0';
699 val /= 10;
700 } while (val > 0);
701 bufp -= 6;
702 memcpy(bufp, "error ", 6);
703 strncat(errbuf, bufp, maxlen);
704 strcat(errbuf, "\n");
705 }
706 if (tmpsock != PGINVALID_SOCKET)
707 closesocket(tmpsock);
708 SOCK_ERRNO_SET(save_errno);
709 return false;
710}
static bool optional_setsockopt(int fd, int protoid, int optid, int value)
Definition: fe-cancel.c:498
long val
Definition: informix.c:689
#define SOCK_ERRNO
Definition: libpq-int.h:959
#define SOCK_ERRNO_SET(e)
Definition: libpq-int.h:961
#define pg_ntoh32(x)
Definition: pg_bswap.h:125
static char * buf
Definition: pg_test_fsync.c:72
int pgsocket
Definition: port.h:29
#define PGINVALID_SOCKET
Definition: port.h:31
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define closesocket
Definition: port.h:377
struct sockaddr_storage addr
Definition: pqcomm.h:32
socklen_t salen
Definition: pqcomm.h:33
int pgtcp_user_timeout
Definition: fe-cancel.c:44
int32 cancel_pkt_len
Definition: fe-cancel.c:53
int keepalives_interval
Definition: fe-cancel.c:47
int keepalives_idle
Definition: fe-cancel.c:46
int keepalives_count
Definition: fe-cancel.c:49
SockAddr raddr
Definition: fe-cancel.c:42
int keepalives
Definition: fe-cancel.c:45
#define EINTR
Definition: win32_port.h:364
#define recv(s, buf, len, flags)
Definition: win32_port.h:504
#define send(s, buf, len, flags)
Definition: win32_port.h:505
#define socket(af, type, protocol)
Definition: win32_port.h:498
#define connect(s, name, namelen)
Definition: win32_port.h:502

References SockAddr::addr, buf, pg_cancel::cancel_pkt_len, closesocket, connect, EINTR, pg_cancel::keepalives, pg_cancel::keepalives_count, pg_cancel::keepalives_idle, pg_cancel::keepalives_interval, optional_setsockopt(), pg_ntoh32, PGINVALID_SOCKET, pg_cancel::pgtcp_user_timeout, pg_cancel::raddr, recv, SockAddr::salen, send, SOCK_ERRNO, SOCK_ERRNO_SET, socket, strlcpy(), and val.

Referenced by DisconnectDatabase(), handle_sigint(), PQrequestCancel(), ShutdownWorkersHard(), sigTermHandler(), and test_cancel().

◆ PQcancelBlocking()

int PQcancelBlocking ( PGcancelConn cancelConn)

Definition at line 189 of file fe-cancel.c.

190{
192 return 0;
193 return pqConnectDBComplete(&cancelConn->conn);
194}
static PGcancel *volatile cancelConn
Definition: cancel.c:43
int PQcancelStart(PGcancelConn *cancelConn)
Definition: fe-cancel.c:203
int pqConnectDBComplete(PGconn *conn)
Definition: fe-connect.c:2779

References cancelConn, PQcancelStart(), and pqConnectDBComplete().

Referenced by disconnectDatabase(), test_cancel(), and try_complete_step().

◆ PQcancelCreate()

PGcancelConn * PQcancelCreate ( PGconn conn)

Definition at line 68 of file fe-cancel.c.

69{
71 pg_conn_host originalHost;
72
73 if (cancelConn == NULL)
74 return NULL;
75
76 /* Check we have an open connection */
77 if (!conn)
78 {
79 libpq_append_conn_error(cancelConn, "connection pointer is NULL");
80 return (PGcancelConn *) cancelConn;
81 }
82
84 {
85 libpq_append_conn_error(cancelConn, "connection not open");
86 return (PGcancelConn *) cancelConn;
87 }
88
89 /* Check that we have received a cancellation key */
90 if (conn->be_cancel_key_len == 0)
91 {
92 libpq_append_conn_error(cancelConn, "no cancellation key received");
93 return (PGcancelConn *) cancelConn;
94 }
95
96 /*
97 * Indicate that this connection is used to send a cancellation
98 */
99 cancelConn->cancelRequest = true;
100
102 return (PGcancelConn *) cancelConn;
103
104 /*
105 * Compute derived options
106 */
108 return (PGcancelConn *) cancelConn;
109
110 /*
111 * Copy cancellation token data from the original connection
112 */
114 if (conn->be_cancel_key != NULL)
115 {
116 cancelConn->be_cancel_key = malloc(conn->be_cancel_key_len);
117 if (!conn->be_cancel_key)
118 goto oom_error;
119 memcpy(cancelConn->be_cancel_key, conn->be_cancel_key, conn->be_cancel_key_len);
120 }
121 cancelConn->be_cancel_key_len = conn->be_cancel_key_len;
122 cancelConn->pversion = conn->pversion;
123
124 /*
125 * Cancel requests should not iterate over all possible hosts. The request
126 * needs to be sent to the exact host and address that the original
127 * connection used. So we manually create the host and address arrays with
128 * a single element after freeing the host array that we generated from
129 * the connection options.
130 */
132 cancelConn->nconnhost = 1;
133 cancelConn->naddr = 1;
134
135 cancelConn->connhost = calloc(cancelConn->nconnhost, sizeof(pg_conn_host));
136 if (!cancelConn->connhost)
137 goto oom_error;
138
139 originalHost = conn->connhost[conn->whichhost];
140 if (originalHost.host)
141 {
142 cancelConn->connhost[0].host = strdup(originalHost.host);
143 if (!cancelConn->connhost[0].host)
144 goto oom_error;
145 }
146 if (originalHost.hostaddr)
147 {
148 cancelConn->connhost[0].hostaddr = strdup(originalHost.hostaddr);
149 if (!cancelConn->connhost[0].hostaddr)
150 goto oom_error;
151 }
152 if (originalHost.port)
153 {
154 cancelConn->connhost[0].port = strdup(originalHost.port);
155 if (!cancelConn->connhost[0].port)
156 goto oom_error;
157 }
158 if (originalHost.password)
159 {
160 cancelConn->connhost[0].password = strdup(originalHost.password);
161 if (!cancelConn->connhost[0].password)
162 goto oom_error;
163 }
164
165 cancelConn->addr = calloc(cancelConn->naddr, sizeof(AddrInfo));
166 if (!cancelConn->addr)
167 goto oom_error;
168
169 cancelConn->addr[0].addr = conn->raddr;
170 cancelConn->addr[0].family = conn->raddr.addr.ss_family;
171
173 return (PGcancelConn *) cancelConn;
174
175oom_error:
176 cancelConn->status = CONNECTION_BAD;
177 libpq_append_conn_error(cancelConn, "out of memory");
178 return (PGcancelConn *) cancelConn;
179}
bool pqConnectOptions2(PGconn *conn)
Definition: fe-connect.c:1240
void pqReleaseConnHosts(PGconn *conn)
Definition: fe-connect.c:5127
PGconn * pqMakeEmptyPGconn(void)
Definition: fe-connect.c:4937
bool pqCopyPGconn(PGconn *srcConn, PGconn *dstConn)
Definition: fe-connect.c:1025
void libpq_append_conn_error(PGconn *conn, const char *fmt,...)
Definition: fe-misc.c:1381
#define calloc(a, b)
Definition: header.h:55
#define malloc(a)
Definition: header.h:50
@ CONNECTION_BAD
Definition: libpq-fe.h:85
@ CONNECTION_ALLOCATED
Definition: libpq-fe.h:107
PGconn * conn
Definition: streamutil.c:52
int be_pid
Definition: fe-cancel.c:43
char * host
Definition: libpq-int.h:358
char * password
Definition: libpq-int.h:361
char * port
Definition: libpq-int.h:360
char * hostaddr
Definition: libpq-int.h:359
char * be_cancel_key
Definition: libpq-int.h:550
pgsocket sock
Definition: libpq-int.h:496
ProtocolVersion pversion
Definition: libpq-int.h:500
int be_pid
Definition: libpq-int.h:549
SockAddr raddr
Definition: libpq-int.h:499
uint16 be_cancel_key_len
Definition: libpq-int.h:551
int whichhost
Definition: libpq-int.h:478
pg_conn_host * connhost
Definition: libpq-int.h:479

References SockAddr::addr, pg_conn::be_cancel_key, pg_conn::be_cancel_key_len, pg_cancel::be_pid, pg_conn::be_pid, calloc, cancelConn, conn, CONNECTION_ALLOCATED, CONNECTION_BAD, pg_conn::connhost, pg_conn_host::host, pg_conn_host::hostaddr, libpq_append_conn_error(), malloc, pg_conn_host::password, PGINVALID_SOCKET, pg_conn_host::port, pqConnectOptions2(), pqCopyPGconn(), pqMakeEmptyPGconn(), pqReleaseConnHosts(), pg_conn::pversion, pg_conn::raddr, pg_conn::sock, and pg_conn::whichhost.

Referenced by disconnectDatabase(), libpqsrv_cancel(), test_cancel(), and try_complete_step().

◆ PQcancelErrorMessage()

char * PQcancelErrorMessage ( const PGcancelConn cancelConn)

Definition at line 324 of file fe-cancel.c.

325{
326 return PQerrorMessage(&cancelConn->conn);
327}
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7619

References cancelConn, and PQerrorMessage().

Referenced by libpqsrv_cancel(), test_cancel(), and try_complete_step().

◆ PQcancelFinish()

void PQcancelFinish ( PGcancelConn cancelConn)

Definition at line 352 of file fe-cancel.c.

353{
354 PQfinish(&cancelConn->conn);
355}
void PQfinish(PGconn *conn)
Definition: fe-connect.c:5290

References cancelConn, and PQfinish().

Referenced by disconnectDatabase(), libpqsrv_cancel(), test_cancel(), and try_complete_step().

◆ PQcancelPoll()

PostgresPollingStatusType PQcancelPoll ( PGcancelConn cancelConn)

Definition at line 225 of file fe-cancel.c.

226{
227 PGconn *conn = &cancelConn->conn;
228 int n;
229
230 /*
231 * We leave most of the connection establishment to PQconnectPoll, since
232 * it's very similar to normal connection establishment. But once we get
233 * to the CONNECTION_AWAITING_RESPONSE we need to start doing our own
234 * thing.
235 */
237 {
238 return PQconnectPoll(conn);
239 }
240
241 /*
242 * At this point we are waiting on the server to close the connection,
243 * which is its way of communicating that the cancel has been handled.
244 */
245
246 n = pqReadData(conn);
247
248 if (n == 0)
250
251#ifndef WIN32
252
253 /*
254 * If we receive an error report it, but only if errno is non-zero.
255 * Otherwise we assume it's an EOF, which is what we expect from the
256 * server.
257 *
258 * We skip this for Windows, because Windows is a bit special in its EOF
259 * behaviour for TCP. Sometimes it will error with an ECONNRESET when
260 * there is a clean connection closure. See these threads for details:
261 * https://www.postgresql.org/message-id/flat/90b34057-4176-7bb0-0dbb-9822a5f6425b%40greiz-reinsdorf.de
262 *
263 * https://www.postgresql.org/message-id/flat/CA%2BhUKG%2BOeoETZQ%3DQw5Ub5h3tmwQhBmDA%3DnuNO3KG%3DzWfUypFAw%40mail.gmail.com
264 *
265 * PQcancel ignores such errors and reports success for the cancellation
266 * anyway, so even if this is not always correct we do the same here.
267 */
268 if (n < 0 && errno != 0)
269 {
272 }
273#endif
274
275 /*
276 * We don't expect any data, only connection closure. So if we strangely
277 * do receive some data we consider that an error.
278 */
279 if (n > 0)
280 {
281 libpq_append_conn_error(conn, "unexpected response from server");
284 }
285
286 /*
287 * Getting here means that we received an EOF, which is what we were
288 * expecting -- the cancel request has completed.
289 */
290 cancelConn->conn.status = CONNECTION_OK;
292 return PGRES_POLLING_OK;
293}
PostgresPollingStatusType PQconnectPoll(PGconn *conn)
Definition: fe-connect.c:2905
int pqReadData(PGconn *conn)
Definition: fe-misc.c:580
@ CONNECTION_AWAITING_RESPONSE
Definition: libpq-fe.h:94
@ CONNECTION_OK
Definition: libpq-fe.h:84
@ PGRES_POLLING_OK
Definition: libpq-fe.h:118
@ PGRES_POLLING_READING
Definition: libpq-fe.h:116
@ PGRES_POLLING_FAILED
Definition: libpq-fe.h:115
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:146
PQExpBufferData errorMessage
Definition: libpq-int.h:671
ConnStatusType status
Definition: libpq-int.h:459

References cancelConn, conn, CONNECTION_AWAITING_RESPONSE, CONNECTION_BAD, CONNECTION_OK, pg_conn::errorMessage, libpq_append_conn_error(), PGRES_POLLING_FAILED, PGRES_POLLING_OK, PGRES_POLLING_READING, PQconnectPoll(), pqReadData(), resetPQExpBuffer(), and pg_conn::status.

Referenced by libpqsrv_cancel(), pqConnectDBComplete(), and test_cancel().

◆ PQcancelReset()

void PQcancelReset ( PGcancelConn cancelConn)

Definition at line 336 of file fe-cancel.c.

337{
339 cancelConn->conn.status = CONNECTION_ALLOCATED;
340 cancelConn->conn.whichhost = 0;
341 cancelConn->conn.whichaddr = 0;
342 cancelConn->conn.try_next_host = false;
343 cancelConn->conn.try_next_addr = false;
344}
void pqClosePGconn(PGconn *conn)
Definition: fe-connect.c:5243

References cancelConn, CONNECTION_ALLOCATED, and pqClosePGconn().

Referenced by test_cancel().

◆ PQcancelSocket()

int PQcancelSocket ( const PGcancelConn cancelConn)

Definition at line 312 of file fe-cancel.c.

313{
314 return PQsocket(&cancelConn->conn);
315}
int PQsocket(const PGconn *conn)
Definition: fe-connect.c:7645

References cancelConn, and PQsocket().

Referenced by libpqsrv_cancel(), and test_cancel().

◆ PQcancelStart()

int PQcancelStart ( PGcancelConn cancelConn)

Definition at line 203 of file fe-cancel.c.

204{
205 if (!cancelConn || cancelConn->conn.status == CONNECTION_BAD)
206 return 0;
207
208 if (cancelConn->conn.status != CONNECTION_ALLOCATED)
209 {
211 "cancel request is already being sent on this connection");
212 cancelConn->conn.status = CONNECTION_BAD;
213 return 0;
214 }
215
216 return pqConnectDBStart(&cancelConn->conn);
217}
int pqConnectDBStart(PGconn *conn)
Definition: fe-connect.c:2701

References cancelConn, CONNECTION_ALLOCATED, CONNECTION_BAD, libpq_append_conn_error(), and pqConnectDBStart().

Referenced by libpqsrv_cancel(), PQcancelBlocking(), and test_cancel().

◆ PQcancelStatus()

ConnStatusType PQcancelStatus ( const PGcancelConn cancelConn)

Definition at line 301 of file fe-cancel.c.

302{
303 return PQstatus(&cancelConn->conn);
304}
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7556

References cancelConn, and PQstatus().

Referenced by test_cancel().

◆ PQfreeCancel()

void PQfreeCancel ( PGcancel cancel)

Definition at line 484 of file fe-cancel.c.

485{
486 free(cancel);
487}
#define free(a)
Definition: header.h:65

References free.

Referenced by PQrequestCancel(), ResetCancelConn(), set_archive_cancel_info(), SetCancelConn(), and test_cancel().

◆ PQgetCancel()

PGcancel * PQgetCancel ( PGconn conn)

Definition at line 367 of file fe-cancel.c.

368{
369 PGcancel *cancel;
370 int cancel_req_len;
372
373 if (!conn)
374 return NULL;
375
376 if (conn->sock == PGINVALID_SOCKET)
377 return NULL;
378
379 /* Check that we have received a cancellation key */
380 if (conn->be_cancel_key_len == 0)
381 return NULL;
382
383 cancel_req_len = offsetof(CancelRequestPacket, cancelAuthCode) + conn->be_cancel_key_len;
384 cancel = malloc(offsetof(PGcancel, cancel_req) + cancel_req_len);
385 if (cancel == NULL)
386 return NULL;
387
388 memcpy(&cancel->raddr, &conn->raddr, sizeof(SockAddr));
389
390 /* We use -1 to indicate an unset connection option */
391 cancel->pgtcp_user_timeout = -1;
392 cancel->keepalives = -1;
393 cancel->keepalives_idle = -1;
394 cancel->keepalives_interval = -1;
395 cancel->keepalives_count = -1;
396 if (conn->pgtcp_user_timeout != NULL)
397 {
399 &cancel->pgtcp_user_timeout,
400 conn, "tcp_user_timeout"))
401 goto fail;
402 }
403 if (conn->keepalives != NULL)
404 {
406 &cancel->keepalives,
407 conn, "keepalives"))
408 goto fail;
409 }
410 if (conn->keepalives_idle != NULL)
411 {
413 &cancel->keepalives_idle,
414 conn, "keepalives_idle"))
415 goto fail;
416 }
417 if (conn->keepalives_interval != NULL)
418 {
420 &cancel->keepalives_interval,
421 conn, "keepalives_interval"))
422 goto fail;
423 }
424 if (conn->keepalives_count != NULL)
425 {
427 &cancel->keepalives_count,
428 conn, "keepalives_count"))
429 goto fail;
430 }
431
432 req = (CancelRequestPacket *) &cancel->cancel_req;
436 /* include the length field itself in the length */
437 cancel->cancel_pkt_len = pg_hton32(cancel_req_len + 4);
438
439 return cancel;
440
441fail:
442 free(cancel);
443 return NULL;
444}
bool pqParseIntParam(const char *value, int *result, PGconn *conn, const char *context)
Definition: fe-connect.c:8177
#define pg_hton32(x)
Definition: pg_bswap.h:121
#define CANCEL_REQUEST_CODE
Definition: pqcomm.h:137
ProtocolVersion MsgType
Definition: pqcomm.h:101
MsgType cancelRequestCode
Definition: pqcomm.h:142
uint32 backendPID
Definition: pqcomm.h:143
char cancelAuthCode[FLEXIBLE_ARRAY_MEMBER]
Definition: pqcomm.h:144
char cancel_req[FLEXIBLE_ARRAY_MEMBER]
Definition: fe-cancel.c:54
char * keepalives_idle
Definition: libpq-int.h:398
char * keepalives
Definition: libpq-int.h:397
char * keepalives_interval
Definition: libpq-int.h:399
char * pgtcp_user_timeout
Definition: libpq-int.h:384
char * keepalives_count
Definition: libpq-int.h:401

References CancelRequestPacket::backendPID, pg_conn::be_cancel_key, pg_conn::be_cancel_key_len, pg_conn::be_pid, pg_cancel::cancel_pkt_len, pg_cancel::cancel_req, CANCEL_REQUEST_CODE, CancelRequestPacket::cancelAuthCode, CancelRequestPacket::cancelRequestCode, conn, free, pg_cancel::keepalives, pg_conn::keepalives, pg_cancel::keepalives_count, pg_conn::keepalives_count, pg_cancel::keepalives_idle, pg_conn::keepalives_idle, pg_cancel::keepalives_interval, pg_conn::keepalives_interval, malloc, pg_hton32, PGINVALID_SOCKET, pg_cancel::pgtcp_user_timeout, pg_conn::pgtcp_user_timeout, pqParseIntParam(), pg_cancel::raddr, pg_conn::raddr, and pg_conn::sock.

Referenced by PQrequestCancel(), set_archive_cancel_info(), SetCancelConn(), and test_cancel().

◆ PQrequestCancel()

int PQrequestCancel ( PGconn conn)

Definition at line 725 of file fe-cancel.c.

726{
727 int r;
728 PGcancel *cancel;
729
730 /* Check we have an open connection */
731 if (!conn)
732 return false;
733
734 if (conn->sock == PGINVALID_SOCKET)
735 {
737 "PQrequestCancel() -- connection is not open\n",
740 conn->errorReported = 0;
741
742 return false;
743 }
744
745 cancel = PQgetCancel(conn);
746 if (cancel)
747 {
748 r = PQcancel(cancel, conn->errorMessage.data,
750 PQfreeCancel(cancel);
751 }
752 else
753 {
754 strlcpy(conn->errorMessage.data, "out of memory",
756 r = false;
757 }
758
759 if (!r)
760 {
762 conn->errorReported = 0;
763 }
764
765 return r;
766}
PGcancel * PQgetCancel(PGconn *conn)
Definition: fe-cancel.c:367
int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
Definition: fe-cancel.c:530
void PQfreeCancel(PGcancel *cancel)
Definition: fe-cancel.c:484
int errorReported
Definition: libpq-int.h:672

References conn, PQExpBufferData::data, pg_conn::errorMessage, pg_conn::errorReported, PQExpBufferData::len, PQExpBufferData::maxlen, PGINVALID_SOCKET, PQcancel(), PQfreeCancel(), PQgetCancel(), pg_conn::sock, and strlcpy().

Referenced by test_cancel().

◆ PQsendCancelRequest()

int PQsendCancelRequest ( PGconn cancelConn)

Definition at line 454 of file fe-cancel.c.

455{
457
458 /* Start the message. */
460 return STATUS_ERROR;
461
462 /* Send the message body. */
463 memset(&req, 0, offsetof(CancelRequestPacket, cancelAuthCode));
466 if (pqPutnchar((char *) &req, offsetof(CancelRequestPacket, cancelAuthCode), cancelConn))
467 return STATUS_ERROR;
468 if (pqPutnchar(cancelConn->be_cancel_key, cancelConn->be_cancel_key_len, cancelConn))
469 return STATUS_ERROR;
470
471 /* Finish the message. */
473 return STATUS_ERROR;
474
475 /* Flush to ensure backend gets it. */
476 if (pqFlush(cancelConn))
477 return STATUS_ERROR;
478
479 return STATUS_OK;
480}
#define STATUS_OK
Definition: c.h:1140
#define STATUS_ERROR
Definition: c.h:1141
int pqFlush(PGconn *conn)
Definition: fe-misc.c:968
int pqPutMsgStart(char msg_type, PGconn *conn)
Definition: fe-misc.c:473
int pqPutnchar(const char *s, size_t len, PGconn *conn)
Definition: fe-misc.c:202
int pqPutMsgEnd(PGconn *conn)
Definition: fe-misc.c:532

References CancelRequestPacket::backendPID, pg_cancel::be_pid, CANCEL_REQUEST_CODE, cancelConn, CancelRequestPacket::cancelRequestCode, pg_hton32, pqFlush(), pqPutMsgEnd(), pqPutMsgStart(), pqPutnchar(), STATUS_ERROR, and STATUS_OK.

Referenced by PQconnectPoll().