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.
This commit is contained in:
parent
8bf61820f0
commit
a0659e3e2c
|
@ -4,7 +4,7 @@
|
||||||
<FirstName>Phil</FirstName>
|
<FirstName>Phil</FirstName>
|
||||||
<Surname>Thompson</Surname>
|
<Surname>Thompson</Surname>
|
||||||
</Author>
|
</Author>
|
||||||
<Date>1998-05-04</Date>
|
<Date>1998-07-07</Date>
|
||||||
</DocInfo>
|
</DocInfo>
|
||||||
<Title>Frontend/Backend Protocol</Title>
|
<Title>Frontend/Backend Protocol</Title>
|
||||||
|
|
||||||
|
@ -54,8 +54,10 @@ invalid database name).
|
||||||
|
|
||||||
<Para>
|
<Para>
|
||||||
Subsequent communications are query and result packets exchanged between the
|
Subsequent communications are query and result packets exchanged between the
|
||||||
frontend and the backend. The postmaster takes no further part in the
|
frontend and the backend. The postmaster takes no further part in ordinary
|
||||||
communication.
|
query/result communication. (However, the postmaster is involved when the
|
||||||
|
frontend wishes to cancel a query currently being executed by its backend.
|
||||||
|
Further details about that appear below.)
|
||||||
|
|
||||||
<Para>
|
<Para>
|
||||||
When the frontend wishes to disconnect it sends an appropriate packet and
|
When the frontend wishes to disconnect it sends an appropriate packet and
|
||||||
|
@ -182,6 +184,20 @@ The possible messages from the backend during this phase are:
|
||||||
<Para>
|
<Para>
|
||||||
<VariableList>
|
<VariableList>
|
||||||
<VarListEntry>
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
BackendKeyData
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
This message is issued after successful backend startup.
|
||||||
|
It provides secret-key data that the frontend must save
|
||||||
|
if it wants to be able to issue cancel requests later.
|
||||||
|
The frontend should not respond to this message, but should
|
||||||
|
continue listening for a ReadyForQuery message.
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
<VarListEntry>
|
||||||
<Term>
|
<Term>
|
||||||
ReadyForQuery
|
ReadyForQuery
|
||||||
</Term>
|
</Term>
|
||||||
|
@ -218,6 +234,14 @@ The possible messages from the backend during this phase are:
|
||||||
</VariableList>
|
</VariableList>
|
||||||
</Para>
|
</Para>
|
||||||
|
|
||||||
|
<Para>
|
||||||
|
The ReadyForQuery message is the same one that the backend will issue after
|
||||||
|
each query cycle. Depending on the coding needs of the frontend, it is
|
||||||
|
reasonable to consider ReadyForQuery as starting a query cycle (and then
|
||||||
|
BackendKeyData indicates successful conclusion of the startup phase),
|
||||||
|
or to consider ReadyForQuery as ending the startup phase and each subsequent
|
||||||
|
query cycle.
|
||||||
|
|
||||||
|
|
||||||
<Sect2>
|
<Sect2>
|
||||||
<Title>Query</Title>
|
<Title>Query</Title>
|
||||||
|
@ -453,7 +477,7 @@ NotificationResponse messages at any time; see below.
|
||||||
<Para>
|
<Para>
|
||||||
If a frontend issues a listen(l) command, then the backend will send a
|
If a frontend issues a listen(l) command, then the backend will send a
|
||||||
NotificationResponse message (not to be confused with NoticeResponse!)
|
NotificationResponse message (not to be confused with NoticeResponse!)
|
||||||
whenever a notify(l) command is executed for the same relation name.
|
whenever a notify(l) command is executed for the same notification name.
|
||||||
|
|
||||||
<Para>
|
<Para>
|
||||||
Notification responses are permitted at any point in the protocol (after
|
Notification responses are permitted at any point in the protocol (after
|
||||||
|
@ -470,8 +494,8 @@ NotificationResponse messages even when it is not engaged in a query.
|
||||||
</Term>
|
</Term>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<Para>
|
<Para>
|
||||||
A notify(l) command has been executed for a relation for
|
A notify(l) command has been executed for a name for which
|
||||||
which a previous listen(l) command was executed. Notifications
|
a previous listen(l) command was executed. Notifications
|
||||||
may be sent at any time.
|
may be sent at any time.
|
||||||
</Para>
|
</Para>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
@ -479,29 +503,77 @@ NotificationResponse messages even when it is not engaged in a query.
|
||||||
</VariableList>
|
</VariableList>
|
||||||
</Para>
|
</Para>
|
||||||
|
|
||||||
|
<Para>
|
||||||
|
It may be worth pointing out that the names used in listen and notify
|
||||||
|
commands need not have anything to do with names of relations (tables)
|
||||||
|
in the SQL database. Notification names are simply arbitrarily chosen
|
||||||
|
condition names.
|
||||||
|
|
||||||
|
|
||||||
<Sect2>
|
<Sect2>
|
||||||
<Title>Cancelling Requests in Progress</Title>
|
<Title>Cancelling Requests in Progress</Title>
|
||||||
|
|
||||||
<Para>
|
<Para>
|
||||||
During the processing of a query, the frontend may request cancellation of the
|
During the processing of a query, the frontend may request cancellation of the
|
||||||
query by sending a single byte of OOB (out-of-band) data. The contents of the
|
query by sending an appropriate request to the postmaster. The cancel request
|
||||||
data byte should be zero (although the backend does not currently check this).
|
is not sent directly to the backend for reasons of implementation efficiency:
|
||||||
If the cancellation is effective, it results in the current command being
|
we don't want to have the backend constantly checking for new input from
|
||||||
terminated with an error message. Note that the backend makes no specific
|
the frontend during query processing. Cancel requests should be relatively
|
||||||
reply to the cancel request itself. If the cancel request is ineffective
|
infrequent, so we make them slightly cumbersome in order to avoid a penalty
|
||||||
(say, because it arrived after processing was complete) then it will have
|
in the normal case.
|
||||||
no visible effect at all. Thus, the frontend must continue with its normal
|
|
||||||
processing of query cycle responses after issuing a cancel request.
|
<Para>
|
||||||
|
To issue a cancel request, the frontend opens a new connection to the
|
||||||
|
postmaster and sends a CancelRequest message, rather than the StartupPacket
|
||||||
|
message that would ordinarily be sent across a new connection. The postmaster
|
||||||
|
will process this request and then close the connection. For security
|
||||||
|
reasons, no direct reply is made to the cancel request message.
|
||||||
|
|
||||||
|
<Para>
|
||||||
|
A CancelRequest message will be ignored unless it contains the same key data
|
||||||
|
(PID and secret key) passed to the frontend during connection startup. If the
|
||||||
|
request matches the PID and secret key for a currently executing backend, the
|
||||||
|
postmaster signals the backend to abort processing of the current query.
|
||||||
|
|
||||||
|
<Para>
|
||||||
|
The cancellation signal may or may not have any effect --- for example, if it
|
||||||
|
arrives after the backend has finished processing the query, then it will have
|
||||||
|
no effect. If the cancellation is effective, it results in the current
|
||||||
|
command being terminated early with an error message.
|
||||||
|
|
||||||
|
<Para>
|
||||||
|
The upshot of all this is that for reasons of both security and efficiency,
|
||||||
|
the frontend has no direct way to tell whether a cancel request has succeeded.
|
||||||
|
It must continue to wait for the backend to respond to the query. Issuing a
|
||||||
|
cancel simply improves the odds that the current query will finish soon,
|
||||||
|
and improves the odds that it will fail with an error message instead of
|
||||||
|
succeeding.
|
||||||
|
|
||||||
|
<Para>
|
||||||
|
Since the cancel request is sent to the postmaster and not across the
|
||||||
|
regular frontend/backend communication link, it is possible for the cancel
|
||||||
|
request to be issued by any process, not just the frontend whose query is
|
||||||
|
to be canceled. This may have some benefits of flexibility in building
|
||||||
|
multiple-process applications. It also introduces a security risk, in that
|
||||||
|
unauthorized persons might try to cancel queries. The security risk is
|
||||||
|
addressed by requiring a dynamically generated secret key to be supplied
|
||||||
|
in cancel requests.
|
||||||
|
|
||||||
|
|
||||||
<Sect2>
|
<Sect2>
|
||||||
<Title>Termination</Title>
|
<Title>Termination</Title>
|
||||||
|
|
||||||
<Para>
|
<Para>
|
||||||
The frontend sends a Terminate message and immediately closes the connection.
|
The normal, graceful termination procedure is that the frontend sends a
|
||||||
On receipt of the message, the backend immediately closes the connection and
|
Terminate message and immediately closes the connection. On receipt of the
|
||||||
terminates.
|
message, the backend immediately closes the connection and terminates.
|
||||||
|
|
||||||
|
<Para>
|
||||||
|
An ungraceful termination may occur due to software failure (i.e., core dump)
|
||||||
|
at either end. If either frontend or backend sees an unexpected closure of
|
||||||
|
the connection, it should clean up and terminate. The frontend has the option
|
||||||
|
of launching a new backend by recontacting the postmaster, if it doesn't want
|
||||||
|
to terminate itself.
|
||||||
|
|
||||||
|
|
||||||
<Sect1>
|
<Sect1>
|
||||||
|
@ -824,6 +896,52 @@ AuthenticationEncryptedPassword (B)
|
||||||
</VarListEntry>
|
</VarListEntry>
|
||||||
</VariableList>
|
</VariableList>
|
||||||
|
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
BackendKeyData (B)
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
|
||||||
|
<VariableList>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
Byte1('K')
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
Identifies the message as cancellation key data.
|
||||||
|
The frontend must save these values if it wishes to be
|
||||||
|
able to issue CancelRequest messages later.
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
Int32
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
The process ID of this backend.
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
Int32
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
The secret key of this backend.
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
</VariableList>
|
||||||
|
|
||||||
|
|
||||||
</Para>
|
</Para>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</VarListEntry>
|
</VarListEntry>
|
||||||
|
@ -892,6 +1010,63 @@ BinaryRow (B)
|
||||||
</VarListEntry>
|
</VarListEntry>
|
||||||
</VariableList>
|
</VariableList>
|
||||||
|
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
CancelRequest (F)
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
|
||||||
|
<VariableList>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
Int32(16)
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
The size of the packet in bytes.
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
Int32(80877102)
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
The cancel request code. The value is chosen to contain
|
||||||
|
"1234" in the most significant 16 bits, and "5678" in the
|
||||||
|
least 16 significant bits. (To avoid confusion, this code
|
||||||
|
must not be the same as any protocol version number.)
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
Int32
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
The process ID of the target backend.
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
Int32
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
The secret key for the target backend.
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
</VariableList>
|
||||||
|
|
||||||
|
|
||||||
</Para>
|
</Para>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</VarListEntry>
|
</VarListEntry>
|
||||||
|
@ -1092,31 +1267,6 @@ EncryptedPasswordPacket (F)
|
||||||
</VariableList>
|
</VariableList>
|
||||||
|
|
||||||
|
|
||||||
</Para>
|
|
||||||
</ListItem>
|
|
||||||
</VarListEntry>
|
|
||||||
<VarListEntry>
|
|
||||||
<Term>
|
|
||||||
ReadyForQuery (B)
|
|
||||||
</Term>
|
|
||||||
<ListItem>
|
|
||||||
<Para>
|
|
||||||
|
|
||||||
<VariableList>
|
|
||||||
<VarListEntry>
|
|
||||||
<Term>
|
|
||||||
Byte1('Z')
|
|
||||||
</Term>
|
|
||||||
<ListItem>
|
|
||||||
<Para>
|
|
||||||
Identifies the message type. ReadyForQuery is sent
|
|
||||||
whenever the backend is ready for a new query cycle.
|
|
||||||
</Para>
|
|
||||||
</ListItem>
|
|
||||||
</VarListEntry>
|
|
||||||
</VariableList>
|
|
||||||
|
|
||||||
|
|
||||||
</Para>
|
</Para>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</VarListEntry>
|
</VarListEntry>
|
||||||
|
@ -1449,6 +1599,31 @@ Query (F)
|
||||||
</VariableList>
|
</VariableList>
|
||||||
|
|
||||||
|
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
ReadyForQuery (B)
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
|
||||||
|
<VariableList>
|
||||||
|
<VarListEntry>
|
||||||
|
<Term>
|
||||||
|
Byte1('Z')
|
||||||
|
</Term>
|
||||||
|
<ListItem>
|
||||||
|
<Para>
|
||||||
|
Identifies the message type. ReadyForQuery is sent
|
||||||
|
whenever the backend is ready for a new query cycle.
|
||||||
|
</Para>
|
||||||
|
</ListItem>
|
||||||
|
</VarListEntry>
|
||||||
|
</VariableList>
|
||||||
|
|
||||||
|
|
||||||
</Para>
|
</Para>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</VarListEntry>
|
</VarListEntry>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.34 1998/06/27 04:53:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.35 1998/07/09 03:28:44 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -21,11 +21,11 @@
|
||||||
* 2.a If the process is the same as the backend process that issued
|
* 2.a If the process is the same as the backend process that issued
|
||||||
* notification (we are notifying something that we are listening),
|
* notification (we are notifying something that we are listening),
|
||||||
* signal the corresponding frontend over the comm channel.
|
* signal the corresponding frontend over the comm channel.
|
||||||
* 2.b For all other listening processes, we send kill(2) to wake up
|
* 2.b For all other listening processes, we send kill(SIGUSR2) to wake up
|
||||||
* the listening backend.
|
* the listening backend.
|
||||||
* 3. Upon receiving a kill(2) signal from another backend process notifying
|
* 3. Upon receiving a kill(SIGUSR2) signal from another backend process
|
||||||
* that one of the relation that we are listening is being notified,
|
* notifying that one of the relation that we are listening is being
|
||||||
* we can be in either of two following states:
|
* notified, we can be in either of two following states:
|
||||||
* 3.a We are sleeping, wake up and signal our frontend.
|
* 3.a We are sleeping, wake up and signal our frontend.
|
||||||
* 3.b We are in middle of another transaction, wait until the end of
|
* 3.b We are in middle of another transaction, wait until the end of
|
||||||
* of the current transaction and signal our frontend.
|
* of the current transaction and signal our frontend.
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
* (which takes place after commit) to all listeners on this relation.
|
* (which takes place after commit) to all listeners on this relation.
|
||||||
*
|
*
|
||||||
* 3. Async. notification results in all backends listening on relation
|
* 3. Async. notification results in all backends listening on relation
|
||||||
* to be woken up, by a process signal kill(2), with name of relation
|
* to be woken up, by a process signal kill(SIGUSR2), with name of relation
|
||||||
* passed in shared memory.
|
* passed in shared memory.
|
||||||
*
|
*
|
||||||
* 4. Each backend notifies its respective frontend over the comm
|
* 4. Each backend notifies its respective frontend over the comm
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.28 1998/06/13 04:27:14 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.29 1998/07/09 03:28:45 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -40,13 +40,13 @@
|
||||||
#include <libpq/crypt.h>
|
#include <libpq/crypt.h>
|
||||||
|
|
||||||
|
|
||||||
static void sendAuthRequest(Port *port, AuthRequest areq, void (*handler) ());
|
static void sendAuthRequest(Port *port, AuthRequest areq, PacketDoneProc handler);
|
||||||
static void handle_done_auth(Port *port);
|
static int handle_done_auth(void *arg, PacketLen len, void *pkt);
|
||||||
static void handle_krb4_auth(Port *port);
|
static int handle_krb4_auth(void *arg, PacketLen len, void *pkt);
|
||||||
static void handle_krb5_auth(Port *port);
|
static int handle_krb5_auth(void *arg, PacketLen len, void *pkt);
|
||||||
static void handle_password_auth(Port *port);
|
static int handle_password_auth(void *arg, PacketLen len, void *pkt);
|
||||||
static void readPasswordPacket(char *arg, PacketLen len, char *pkt);
|
static int readPasswordPacket(void *arg, PacketLen len, void *pkt);
|
||||||
static void pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt);
|
static int pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt);
|
||||||
static int checkPassword(Port *port, char *user, char *password);
|
static int checkPassword(Port *port, char *user, char *password);
|
||||||
static int old_be_recvauth(Port *port);
|
static int old_be_recvauth(Port *port);
|
||||||
static int map_old_to_new(Port *port, UserAuth old, int status);
|
static int map_old_to_new(Port *port, UserAuth old, int status);
|
||||||
|
@ -327,8 +327,8 @@ pg_krb5_recvauth(Port *port)
|
||||||
* Handle a v0 password packet.
|
* Handle a v0 password packet.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static int
|
||||||
pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt)
|
pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt)
|
||||||
{
|
{
|
||||||
Port *port;
|
Port *port;
|
||||||
PasswordPacketV0 *pp;
|
PasswordPacketV0 *pp;
|
||||||
|
@ -393,6 +393,8 @@ pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt)
|
||||||
if (map_old_to_new(port, uaPassword, status) != STATUS_OK)
|
if (map_old_to_new(port, uaPassword, status) != STATUS_OK)
|
||||||
auth_failed(port);
|
auth_failed(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (STATUS_OK); /* don't close the connection yet */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -433,7 +435,7 @@ be_recvauth(Port *port)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AuthRequest areq;
|
AuthRequest areq;
|
||||||
void (*auth_handler) ();
|
PacketDoneProc auth_handler;
|
||||||
|
|
||||||
/* Keep the compiler quiet. */
|
/* Keep the compiler quiet. */
|
||||||
|
|
||||||
|
@ -499,7 +501,7 @@ be_recvauth(Port *port)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sendAuthRequest(Port *port, AuthRequest areq, void (*handler) ())
|
sendAuthRequest(Port *port, AuthRequest areq, PacketDoneProc handler)
|
||||||
{
|
{
|
||||||
char *dp,
|
char *dp,
|
||||||
*sp;
|
*sp;
|
||||||
|
@ -527,7 +529,7 @@ sendAuthRequest(Port *port, AuthRequest areq, void (*handler) ())
|
||||||
i += 2;
|
i += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketSendSetup(&port->pktInfo, i, handler, (char *) port);
|
PacketSendSetup(&port->pktInfo, i, handler, (void *) port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -535,8 +537,8 @@ sendAuthRequest(Port *port, AuthRequest areq, void (*handler) ())
|
||||||
* Called when we have told the front end that it is authorised.
|
* Called when we have told the front end that it is authorised.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static int
|
||||||
handle_done_auth(Port *port)
|
handle_done_auth(void *arg, PacketLen len, void *pkt)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -544,7 +546,7 @@ handle_done_auth(Port *port)
|
||||||
* start.
|
* start.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return;
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -553,13 +555,17 @@ handle_done_auth(Port *port)
|
||||||
* authentication.
|
* authentication.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static int
|
||||||
handle_krb4_auth(Port *port)
|
handle_krb4_auth(void *arg, PacketLen len, void *pkt)
|
||||||
{
|
{
|
||||||
|
Port *port = (Port *) arg;
|
||||||
|
|
||||||
if (pg_krb4_recvauth(port) != STATUS_OK)
|
if (pg_krb4_recvauth(port) != STATUS_OK)
|
||||||
auth_failed(port);
|
auth_failed(port);
|
||||||
else
|
else
|
||||||
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
|
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
|
||||||
|
|
||||||
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -568,13 +574,17 @@ handle_krb4_auth(Port *port)
|
||||||
* authentication.
|
* authentication.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static int
|
||||||
handle_krb5_auth(Port *port)
|
handle_krb5_auth(void *arg, PacketLen len, void *pkt)
|
||||||
{
|
{
|
||||||
|
Port *port = (Port *) arg;
|
||||||
|
|
||||||
if (pg_krb5_recvauth(port) != STATUS_OK)
|
if (pg_krb5_recvauth(port) != STATUS_OK)
|
||||||
auth_failed(port);
|
auth_failed(port);
|
||||||
else
|
else
|
||||||
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
|
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
|
||||||
|
|
||||||
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -583,12 +593,16 @@ handle_krb5_auth(Port *port)
|
||||||
* authentication.
|
* authentication.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static int
|
||||||
handle_password_auth(Port *port)
|
handle_password_auth(void *arg, PacketLen len, void *pkt)
|
||||||
{
|
{
|
||||||
|
Port *port = (Port *) arg;
|
||||||
|
|
||||||
/* Set up the read of the password packet. */
|
/* Set up the read of the password packet. */
|
||||||
|
|
||||||
PacketReceiveSetup(&port->pktInfo, readPasswordPacket, (char *) port);
|
PacketReceiveSetup(&port->pktInfo, readPasswordPacket, (void *) port);
|
||||||
|
|
||||||
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -596,13 +610,11 @@ handle_password_auth(Port *port)
|
||||||
* Called when we have received the password packet.
|
* Called when we have received the password packet.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static int
|
||||||
readPasswordPacket(char *arg, PacketLen len, char *pkt)
|
readPasswordPacket(void *arg, PacketLen len, void *pkt)
|
||||||
{
|
{
|
||||||
char password[sizeof(PasswordPacket) + 1];
|
char password[sizeof(PasswordPacket) + 1];
|
||||||
Port *port;
|
Port *port = (Port *) arg;
|
||||||
|
|
||||||
port = (Port *) arg;
|
|
||||||
|
|
||||||
/* Silently truncate a password that is too big. */
|
/* Silently truncate a password that is too big. */
|
||||||
|
|
||||||
|
@ -615,6 +627,8 @@ readPasswordPacket(char *arg, PacketLen len, char *pkt)
|
||||||
auth_failed(port);
|
auth_failed(port);
|
||||||
else
|
else
|
||||||
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
|
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
|
||||||
|
|
||||||
|
return (STATUS_OK); /* don't close the connection yet */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -662,7 +676,7 @@ old_be_recvauth(Port *port)
|
||||||
|
|
||||||
case STARTUP_PASSWORD_MSG:
|
case STARTUP_PASSWORD_MSG:
|
||||||
PacketReceiveSetup(&port->pktInfo, pg_passwordv0_recvauth,
|
PacketReceiveSetup(&port->pktInfo, pg_passwordv0_recvauth,
|
||||||
(char *) port);
|
(void *) port);
|
||||||
|
|
||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.47 1998/06/27 04:53:30 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.48 1998/07/09 03:28:46 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -30,7 +30,6 @@
|
||||||
* pq_getinserv - initialize address from host and service name
|
* pq_getinserv - initialize address from host and service name
|
||||||
* pq_connect - create remote input / output connection
|
* pq_connect - create remote input / output connection
|
||||||
* pq_accept - accept remote input / output connection
|
* pq_accept - accept remote input / output connection
|
||||||
* pq_async_notify - receive notification from backend.
|
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* These functions are used by both frontend applications and
|
* These functions are used by both frontend applications and
|
||||||
|
@ -79,7 +78,6 @@
|
||||||
FILE *Pfout,
|
FILE *Pfout,
|
||||||
*Pfin;
|
*Pfin;
|
||||||
FILE *Pfdebug; /* debugging libpq */
|
FILE *Pfdebug; /* debugging libpq */
|
||||||
int PQAsyncNotifyWaiting; /* for async. notification */
|
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* pq_init - open portal file descriptors
|
* pq_init - open portal file descriptors
|
||||||
|
@ -160,9 +158,7 @@ pq_close()
|
||||||
fclose(Pfout);
|
fclose(Pfout);
|
||||||
Pfout = NULL;
|
Pfout = NULL;
|
||||||
}
|
}
|
||||||
PQAsyncNotifyWaiting = 0;
|
|
||||||
PQnotifies_init();
|
PQnotifies_init();
|
||||||
pq_unregoob();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
|
@ -418,29 +414,6 @@ pq_putint(int i, int b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---
|
|
||||||
* pq_sendoob - send a string over the out-of-band channel
|
|
||||||
* pq_recvoob - receive a string over the oob channel
|
|
||||||
* NB: Fortunately, the out-of-band channel doesn't conflict with
|
|
||||||
* buffered I/O because it is separate from regular com. channel.
|
|
||||||
* ---
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
pq_sendoob(char *msg, int len)
|
|
||||||
{
|
|
||||||
int fd = fileno(Pfout);
|
|
||||||
|
|
||||||
return send(fd, msg, len, MSG_OOB);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
pq_recvoob(char *msgPtr, int len)
|
|
||||||
{
|
|
||||||
int fd = fileno(Pfout);
|
|
||||||
|
|
||||||
return recv(fd, msgPtr, len, MSG_OOB);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* pq_getinaddr - initialize address from host and port number
|
* pq_getinaddr - initialize address from host and port number
|
||||||
* --------------------------------
|
* --------------------------------
|
||||||
|
@ -507,55 +480,6 @@ pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
|
||||||
return (pq_getinaddr(sin, host, ntohs(ss->s_port)));
|
return (pq_getinaddr(sin, host, ntohs(ss->s_port)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* register an out-of-band listener proc--at most one allowed.
|
|
||||||
* This is used for receiving async. notification from the backend.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pq_regoob(void (*fptr) ())
|
|
||||||
{
|
|
||||||
int fd = fileno(Pfout);
|
|
||||||
|
|
||||||
#if defined(hpux)
|
|
||||||
ioctl(fd, FIOSSAIOOWN, MyProcPid);
|
|
||||||
#elif defined(sco)
|
|
||||||
ioctl(fd, SIOCSPGRP, MyProcPid);
|
|
||||||
#else
|
|
||||||
fcntl(fd, F_SETOWN, MyProcPid);
|
|
||||||
#endif /* hpux */
|
|
||||||
pqsignal(SIGURG, fptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pq_unregoob()
|
|
||||||
{
|
|
||||||
pqsignal(SIGURG, SIG_DFL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
pq_async_notify()
|
|
||||||
{
|
|
||||||
char msg[20];
|
|
||||||
|
|
||||||
/* int len = sizeof(msg); */
|
|
||||||
int len = 20;
|
|
||||||
|
|
||||||
if (pq_recvoob(msg, len) >= 0)
|
|
||||||
{
|
|
||||||
/* debugging */
|
|
||||||
printf("received notification: %s\n", msg);
|
|
||||||
PQAsyncNotifyWaiting = 1;
|
|
||||||
/* PQappendNotify(msg+1); */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
extern int errno;
|
|
||||||
|
|
||||||
printf("SIGURG but no data: len = %d, err=%d\n", len, errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Streams -- wrapper around Unix socket system calls
|
* Streams -- wrapper around Unix socket system calls
|
||||||
*
|
*
|
||||||
|
@ -620,7 +544,7 @@ StreamServerPort(char *hostName, short portName, int *fdP)
|
||||||
pqdebug("%s", PQerrormsg);
|
pqdebug("%s", PQerrormsg);
|
||||||
return (STATUS_ERROR);
|
return (STATUS_ERROR);
|
||||||
}
|
}
|
||||||
bzero(&saddr, sizeof(saddr));
|
MemSet((char *) &saddr, 0, sizeof(saddr));
|
||||||
saddr.sa.sa_family = family;
|
saddr.sa.sa_family = family;
|
||||||
if (family == AF_UNIX)
|
if (family == AF_UNIX)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.15 1998/02/26 04:31:56 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.16 1998/07/09 03:28:46 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
* Set up a packet read for the postmaster event loop.
|
* Set up a packet read for the postmaster event loop.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void PacketReceiveSetup(Packet *pkt, void (*iodone) (), char *arg)
|
void PacketReceiveSetup(Packet *pkt, PacketDoneProc iodone, void *arg)
|
||||||
{
|
{
|
||||||
pkt->nrtodo = sizeof(pkt->len);
|
pkt->nrtodo = sizeof(pkt->len);
|
||||||
pkt->ptr = (char *) &pkt->len;
|
pkt->ptr = (char *) &pkt->len;
|
||||||
|
@ -94,8 +94,8 @@ PacketReceiveFragment(Packet *pkt, int sock)
|
||||||
if (pkt->iodone == NULL)
|
if (pkt->iodone == NULL)
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
|
|
||||||
(*pkt->iodone) (pkt->arg, pkt->len - sizeof(pkt->len),
|
return (*pkt->iodone) (pkt->arg, pkt->len - sizeof(pkt->len),
|
||||||
(char *) &pkt->pkt);
|
(void *) &pkt->pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
|
@ -107,7 +107,7 @@ PacketReceiveFragment(Packet *pkt, int sock)
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
|
|
||||||
fprintf(stderr, "read() system call failed\n");
|
perror("PacketReceiveFragment: read() failed");
|
||||||
|
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,9 @@ PacketReceiveFragment(Packet *pkt, int sock)
|
||||||
* Set up a packet write for the postmaster event loop.
|
* Set up a packet write for the postmaster event loop.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void PacketSendSetup(Packet *pkt, int nbytes, void (*iodone) (), char *arg)
|
void PacketSendSetup(Packet *pkt, int nbytes, PacketDoneProc iodone, void *arg)
|
||||||
{
|
{
|
||||||
|
pkt->len = (PacketLen) nbytes;
|
||||||
pkt->nrtodo = nbytes;
|
pkt->nrtodo = nbytes;
|
||||||
pkt->ptr = (char *) &pkt->pkt;
|
pkt->ptr = (char *) &pkt->pkt;
|
||||||
pkt->iodone = iodone;
|
pkt->iodone = iodone;
|
||||||
|
@ -153,7 +154,8 @@ PacketSendFragment(Packet *pkt, int sock)
|
||||||
if (pkt->iodone == NULL)
|
if (pkt->iodone == NULL)
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
|
|
||||||
(*pkt->iodone) (pkt->arg);
|
return (*pkt->iodone) (pkt->arg, pkt->len,
|
||||||
|
(void *) &pkt->pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
|
@ -165,7 +167,7 @@ PacketSendFragment(Packet *pkt, int sock)
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
|
|
||||||
fprintf(stderr, "write() system call failed\n");
|
perror("PacketSendFragment: write() failed");
|
||||||
|
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.92 1998/06/27 14:06:40 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.93 1998/07/09 03:28:47 scrappy Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
*
|
*
|
||||||
|
@ -206,7 +206,6 @@ static int orgsigmask = sigblock(0);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static unsigned int random_seed = 0;
|
static unsigned int random_seed = 0;
|
||||||
long MyCancelKey = 0;
|
|
||||||
|
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
extern int optind,
|
extern int optind,
|
||||||
|
@ -228,7 +227,8 @@ static void ExitPostmaster(int status);
|
||||||
static void usage(const char *);
|
static void usage(const char *);
|
||||||
static int ServerLoop(void);
|
static int ServerLoop(void);
|
||||||
static int BackendStartup(Port *port);
|
static int BackendStartup(Port *port);
|
||||||
static void readStartupPacket(char *arg, PacketLen len, char *pkt);
|
static int readStartupPacket(void *arg, PacketLen len, void *pkt);
|
||||||
|
static int processCancelRequest(Port *port, PacketLen len, void *pkt);
|
||||||
static int initMasks(fd_set *rmask, fd_set *wmask);
|
static int initMasks(fd_set *rmask, fd_set *wmask);
|
||||||
static long PostmasterRandom(void);
|
static long PostmasterRandom(void);
|
||||||
static void RandomSalt(char *salt);
|
static void RandomSalt(char *salt);
|
||||||
|
@ -518,6 +518,10 @@ PostmasterMain(int argc, char *argv[])
|
||||||
if (silentflag)
|
if (silentflag)
|
||||||
pmdaemonize();
|
pmdaemonize();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up signal handlers for the postmaster process.
|
||||||
|
*/
|
||||||
|
|
||||||
pqsignal(SIGINT, pmdie);
|
pqsignal(SIGINT, pmdie);
|
||||||
pqsignal(SIGCHLD, reaper);
|
pqsignal(SIGCHLD, reaper);
|
||||||
pqsignal(SIGTTIN, SIG_IGN);
|
pqsignal(SIGTTIN, SIG_IGN);
|
||||||
|
@ -657,14 +661,14 @@ ServerLoop(void)
|
||||||
(port = ConnCreate(ServerSock_UNIX)) != NULL)
|
(port = ConnCreate(ServerSock_UNIX)) != NULL)
|
||||||
PacketReceiveSetup(&port->pktInfo,
|
PacketReceiveSetup(&port->pktInfo,
|
||||||
readStartupPacket,
|
readStartupPacket,
|
||||||
(char *) port);
|
(void *) port);
|
||||||
|
|
||||||
if (ServerSock_INET != INVALID_SOCK &&
|
if (ServerSock_INET != INVALID_SOCK &&
|
||||||
FD_ISSET(ServerSock_INET, &rmask) &&
|
FD_ISSET(ServerSock_INET, &rmask) &&
|
||||||
(port = ConnCreate(ServerSock_INET)) != NULL)
|
(port = ConnCreate(ServerSock_INET)) != NULL)
|
||||||
PacketReceiveSetup(&port->pktInfo,
|
PacketReceiveSetup(&port->pktInfo,
|
||||||
readStartupPacket,
|
readStartupPacket,
|
||||||
(char *) port);
|
(void *) port);
|
||||||
|
|
||||||
/* Build up new masks for select(). */
|
/* Build up new masks for select(). */
|
||||||
|
|
||||||
|
@ -790,8 +794,8 @@ initMasks(fd_set *rmask, fd_set *wmask)
|
||||||
* Called when the startup packet has been read.
|
* Called when the startup packet has been read.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static int
|
||||||
readStartupPacket(char *arg, PacketLen len, char *pkt)
|
readStartupPacket(void *arg, PacketLen len, void *pkt)
|
||||||
{
|
{
|
||||||
Port *port;
|
Port *port;
|
||||||
StartupPacket *si;
|
StartupPacket *si;
|
||||||
|
@ -799,6 +803,28 @@ readStartupPacket(char *arg, PacketLen len, char *pkt)
|
||||||
port = (Port *) arg;
|
port = (Port *) arg;
|
||||||
si = (StartupPacket *) pkt;
|
si = (StartupPacket *) pkt;
|
||||||
|
|
||||||
|
/* The first field is either a protocol version number or
|
||||||
|
* a special request code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
port->proto = ntohl(si->protoVersion);
|
||||||
|
|
||||||
|
if (port->proto == CANCEL_REQUEST_CODE)
|
||||||
|
return processCancelRequest(port, len, pkt);
|
||||||
|
|
||||||
|
/* Could add additional special packet types here */
|
||||||
|
|
||||||
|
/* Check we can handle the protocol the frontend is using. */
|
||||||
|
|
||||||
|
if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
|
||||||
|
PG_PROTOCOL_MAJOR(port->proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
|
||||||
|
(PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
|
||||||
|
PG_PROTOCOL_MINOR(port->proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
|
||||||
|
{
|
||||||
|
PacketSendError(&port->pktInfo, "Unsupported frontend protocol.");
|
||||||
|
return STATUS_OK; /* don't close the connection yet */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the parameters from the startup packet as C strings. The
|
* Get the parameters from the startup packet as C strings. The
|
||||||
* packet destination was cleared first so a short packet has zeros
|
* packet destination was cleared first so a short packet has zeros
|
||||||
|
@ -815,31 +841,74 @@ readStartupPacket(char *arg, PacketLen len, char *pkt)
|
||||||
if (port->database[0] == '\0')
|
if (port->database[0] == '\0')
|
||||||
StrNCpy(port->database, si->user, sizeof(port->database) - 1);
|
StrNCpy(port->database, si->user, sizeof(port->database) - 1);
|
||||||
|
|
||||||
/* Check we can handle the protocol the frontend is using. */
|
|
||||||
|
|
||||||
port->proto = ntohl(si->protoVersion);
|
|
||||||
|
|
||||||
if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
|
|
||||||
PG_PROTOCOL_MAJOR(port->proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
|
|
||||||
(PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
|
|
||||||
PG_PROTOCOL_MINOR(port->proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
|
|
||||||
{
|
|
||||||
PacketSendError(&port->pktInfo, "Unsupported frontend protocol.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check a user name was given. */
|
/* Check a user name was given. */
|
||||||
|
|
||||||
if (port->user[0] == '\0')
|
if (port->user[0] == '\0')
|
||||||
{
|
{
|
||||||
PacketSendError(&port->pktInfo,
|
PacketSendError(&port->pktInfo,
|
||||||
"No Postgres username specified in startup packet.");
|
"No Postgres username specified in startup packet.");
|
||||||
return;
|
return STATUS_OK; /* don't close the connection yet */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start the authentication itself. */
|
/* Start the authentication itself. */
|
||||||
|
|
||||||
be_recvauth(port);
|
be_recvauth(port);
|
||||||
|
|
||||||
|
return STATUS_OK; /* don't close the connection yet */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The client has sent a cancel request packet, not a normal
|
||||||
|
* start-a-new-backend packet. Perform the necessary processing.
|
||||||
|
* Note that in any case, we return STATUS_ERROR to close the
|
||||||
|
* connection immediately. Nothing is sent back to the client.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
processCancelRequest(Port *port, PacketLen len, void *pkt)
|
||||||
|
{
|
||||||
|
CancelRequestPacket *canc = (CancelRequestPacket *) pkt;
|
||||||
|
int backendPID;
|
||||||
|
long cancelAuthCode;
|
||||||
|
Dlelem *curr;
|
||||||
|
Backend *bp;
|
||||||
|
|
||||||
|
backendPID = (int) ntohl(canc->backendPID);
|
||||||
|
cancelAuthCode = (long) ntohl(canc->cancelAuthCode);
|
||||||
|
|
||||||
|
/* See if we have a matching backend */
|
||||||
|
|
||||||
|
for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
|
||||||
|
{
|
||||||
|
bp = (Backend *) DLE_VAL(curr);
|
||||||
|
if (bp->pid == backendPID)
|
||||||
|
{
|
||||||
|
if (bp->cancel_key == cancelAuthCode)
|
||||||
|
{
|
||||||
|
/* Found a match; signal that backend to cancel current op */
|
||||||
|
if (DebugLvl)
|
||||||
|
fprintf(stderr, "%s: processCancelRequest: sending SIGINT to process %d\n",
|
||||||
|
progname, bp->pid);
|
||||||
|
kill(bp->pid, SIGINT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Right PID, wrong key: no way, Jose */
|
||||||
|
if (DebugLvl)
|
||||||
|
fprintf(stderr, "%s: processCancelRequest: bad key in cancel request for process %d\n",
|
||||||
|
progname, bp->pid);
|
||||||
|
}
|
||||||
|
return STATUS_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No matching backend */
|
||||||
|
if (DebugLvl)
|
||||||
|
fprintf(stderr, "%s: processCancelRequest: bad PID in cancel request for process %d\n",
|
||||||
|
progname, backendPID);
|
||||||
|
|
||||||
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1221,6 +1290,8 @@ DoBackend(Port *port)
|
||||||
char dbbuf[ARGV_SIZE + 1];
|
char dbbuf[ARGV_SIZE + 1];
|
||||||
int ac = 0;
|
int ac = 0;
|
||||||
int i;
|
int i;
|
||||||
|
struct timeval now;
|
||||||
|
struct timezone tz;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Let's clean up ourselves as the postmaster child
|
* Let's clean up ourselves as the postmaster child
|
||||||
|
@ -1254,7 +1325,16 @@ DoBackend(Port *port)
|
||||||
if (NetServer)
|
if (NetServer)
|
||||||
StreamClose(ServerSock_INET);
|
StreamClose(ServerSock_INET);
|
||||||
StreamClose(ServerSock_UNIX);
|
StreamClose(ServerSock_UNIX);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't want backend to be able to see the postmaster random number
|
||||||
|
* generator state. We have to clobber the static random_seed *and*
|
||||||
|
* start a new random sequence in the random() library function.
|
||||||
|
*/
|
||||||
|
random_seed = 0;
|
||||||
|
gettimeofday(&now, &tz);
|
||||||
|
srandom(now.tv_usec);
|
||||||
|
|
||||||
/* Now, on to standard postgres stuff */
|
/* Now, on to standard postgres stuff */
|
||||||
|
|
||||||
MyProcPid = getpid();
|
MyProcPid = getpid();
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.78 1998/06/27 04:53:43 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.79 1998/07/09 03:28:48 scrappy Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* this is the "main" module of the postgres backend and
|
||||||
|
@ -724,7 +724,7 @@ pg_exec_query_dest(char *query_string, /* string to execute */
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* signal handler routines used in PostgresMain()
|
* signal handler routines used in PostgresMain()
|
||||||
*
|
*
|
||||||
* handle_warn() is used to catch kill(getpid(),1) which
|
* handle_warn() is used to catch kill(getpid(), SIGHUP) which
|
||||||
* occurs when elog(ERROR) is called.
|
* occurs when elog(ERROR) is called.
|
||||||
*
|
*
|
||||||
* quickdie() occurs when signalled by the postmaster.
|
* quickdie() occurs when signalled by the postmaster.
|
||||||
|
@ -777,7 +777,7 @@ FloatExceptionHandler(SIGNAL_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* signal handler for query cancel */
|
/* signal handler for query cancel signal from postmaster */
|
||||||
static void
|
static void
|
||||||
QueryCancelHandler(SIGNAL_ARGS)
|
QueryCancelHandler(SIGNAL_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -787,12 +787,9 @@ QueryCancelHandler(SIGNAL_ARGS)
|
||||||
void
|
void
|
||||||
CancelQuery(void)
|
CancelQuery(void)
|
||||||
{
|
{
|
||||||
char dummy;
|
/* QueryCancel flag will be reset in main loop, which we reach by
|
||||||
|
* longjmp from elog().
|
||||||
/* throw it away */
|
*/
|
||||||
while (pq_recvoob(&dummy, 1) > 0)
|
|
||||||
;
|
|
||||||
/* QueryCancel reset in longjump after elog() call */
|
|
||||||
elog(ERROR, "Query was cancelled.");
|
elog(ERROR, "Query was cancelled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1261,7 +1258,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
||||||
}
|
}
|
||||||
pq_init(Portfd);
|
pq_init(Portfd);
|
||||||
whereToSendOutput = Remote;
|
whereToSendOutput = Remote;
|
||||||
pq_regoob(QueryCancelHandler); /* we do it here so the backend it connected */
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
whereToSendOutput = Debug;
|
whereToSendOutput = Debug;
|
||||||
|
@ -1287,6 +1283,24 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* Set up handler for cancel-request signal, and
|
||||||
|
* send this backend's cancellation info to the frontend.
|
||||||
|
* This should not be done until we are sure startup is successful.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
pqsignal(SIGINT, QueryCancelHandler);
|
||||||
|
|
||||||
|
if (whereToSendOutput == Remote &&
|
||||||
|
PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
|
||||||
|
{
|
||||||
|
pq_putnchar("K", 1);
|
||||||
|
pq_putint((int32) MyProcPid, sizeof(int32));
|
||||||
|
pq_putint((int32) MyCancelKey, sizeof(int32));
|
||||||
|
/* Need not flush since ReadyForQuery will do it. */
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* if an exception is encountered, processing resumes here
|
* if an exception is encountered, processing resumes here
|
||||||
* so we abort the current transaction and start a new one.
|
* so we abort the current transaction and start a new one.
|
||||||
|
@ -1294,7 +1308,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
||||||
* so that the slaves signal the master to abort the transaction
|
* so that the slaves signal the master to abort the transaction
|
||||||
* rather than calling AbortCurrentTransaction() themselves.
|
* rather than calling AbortCurrentTransaction() themselves.
|
||||||
*
|
*
|
||||||
* Note: elog(ERROR) causes a kill(getpid(),1) to occur sending
|
* Note: elog(ERROR) causes a kill(getpid(), SIGHUP) to occur sending
|
||||||
* us back here.
|
* us back here.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
@ -1325,7 +1339,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
puts("\nPOSTGRES backend interactive interface");
|
puts("\nPOSTGRES backend interactive interface");
|
||||||
puts("$Revision: 1.78 $ $Date: 1998/06/27 04:53:43 $");
|
puts("$Revision: 1.79 $ $Date: 1998/07/09 03:28:48 $");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -1431,7 +1445,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "unknown frontend message was recieved");
|
elog(ERROR, "unknown frontend message was received");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.23 1998/05/29 17:00:18 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.24 1998/07/09 03:28:51 scrappy Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Globals used all over the place should be declared here and not
|
* Globals used all over the place should be declared here and not
|
||||||
|
@ -44,6 +44,8 @@ bool QueryCancel = false;
|
||||||
|
|
||||||
int MyProcPid;
|
int MyProcPid;
|
||||||
|
|
||||||
|
long MyCancelKey;
|
||||||
|
|
||||||
char *DataDir;
|
char *DataDir;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.146 1998/06/16 07:29:38 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.147 1998/07/09 03:28:53 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -291,15 +291,27 @@ PSQLexec(PsqlSettings *pset, char *query)
|
||||||
* If interactive, we enable a SIGINT signal catcher that sends
|
* If interactive, we enable a SIGINT signal catcher that sends
|
||||||
* a cancel request to the backend.
|
* a cancel request to the backend.
|
||||||
* Note that sending the cancel directly from the signal handler
|
* Note that sending the cancel directly from the signal handler
|
||||||
* is safe only because the cancel is sent as an OOB message.
|
* is safe only because PQrequestCancel is carefully written to
|
||||||
* If it were inline data, then we'd risk inserting it into the
|
* make it so. We have to be very careful what else we do in the
|
||||||
* middle of a normal data message by doing this.
|
* signal handler.
|
||||||
* (It's probably not too cool to write on stderr, for that matter...
|
* Writing on stderr is potentially dangerous, if the signal interrupted
|
||||||
* but for debugging purposes we'll risk that.)
|
* some stdio operation on stderr. On Unix we can avoid trouble by using
|
||||||
|
* write() instead; on Windows that's probably not workable, but we can
|
||||||
|
* at least avoid trusting printf by using the more primitive fputs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static PGconn * cancelConn = NULL; /* connection to try cancel on */
|
static PGconn * cancelConn = NULL; /* connection to try cancel on */
|
||||||
|
|
||||||
|
static void
|
||||||
|
safe_write_stderr (const char * s)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
fputs(s, stderr);
|
||||||
|
#else
|
||||||
|
write(fileno(stderr), s, strlen(s));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_sigint (SIGNAL_ARGS)
|
handle_sigint (SIGNAL_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -307,11 +319,13 @@ handle_sigint (SIGNAL_ARGS)
|
||||||
exit(1); /* accept signal if no connection */
|
exit(1); /* accept signal if no connection */
|
||||||
/* Try to send cancel request */
|
/* Try to send cancel request */
|
||||||
if (PQrequestCancel(cancelConn))
|
if (PQrequestCancel(cancelConn))
|
||||||
fprintf(stderr, "\nCANCEL request sent\n");
|
{
|
||||||
|
safe_write_stderr("\nCANCEL request sent\n");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "\nCannot send cancel request:\n%s\n",
|
safe_write_stderr("\nCannot send cancel request:\n");
|
||||||
PQerrorMessage(cancelConn));
|
safe_write_stderr(PQerrorMessage(cancelConn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: dbcommands.h,v 1.1 1997/11/24 05:32:51 momjian Exp $
|
* $Id: dbcommands.h,v 1.2 1998/07/09 03:28:56 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -17,8 +17,7 @@
|
||||||
* Originally from tmp/daemon.h. The functions declared in daemon.h does not
|
* Originally from tmp/daemon.h. The functions declared in daemon.h does not
|
||||||
* exist; hence removed. -- AY 7/29/94
|
* exist; hence removed. -- AY 7/29/94
|
||||||
*/
|
*/
|
||||||
#define SIGKILLDAEMON1 SIGINT
|
#define SIGKILLDAEMON1 SIGTERM
|
||||||
#define SIGKILLDAEMON2 SIGTERM
|
|
||||||
|
|
||||||
extern void createdb(char *dbname, char *dbpath);
|
extern void createdb(char *dbname, char *dbpath);
|
||||||
extern void destroydb(char *dbname);
|
extern void destroydb(char *dbname);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: libpq-be.h,v 1.10 1998/02/26 04:41:49 momjian Exp $
|
* $Id: libpq-be.h,v 1.11 1998/07/09 03:29:00 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -68,16 +68,20 @@ typedef enum
|
||||||
WritingPacket
|
WritingPacket
|
||||||
} PacketState;
|
} PacketState;
|
||||||
|
|
||||||
|
typedef int (*PacketDoneProc) (void * arg, PacketLen pktlen, void * pktdata);
|
||||||
|
|
||||||
typedef struct Packet
|
typedef struct Packet
|
||||||
{
|
{
|
||||||
PacketState state; /* What's in progress. */
|
PacketState state; /* What's in progress. */
|
||||||
PacketLen len; /* Actual length */
|
PacketLen len; /* Actual length */
|
||||||
int nrtodo; /* Bytes still to transfer */
|
int nrtodo; /* Bytes still to transfer */
|
||||||
char *ptr; /* Buffer pointer */
|
char *ptr; /* Buffer pointer */
|
||||||
void (*iodone) (); /* I/O complete callback */
|
PacketDoneProc iodone; /* I/O complete callback */
|
||||||
char *arg; /* Argument to callback */
|
void *arg; /* Argument to callback */
|
||||||
|
|
||||||
/* A union of all the different packets. */
|
/* We declare the data buffer as a union of the allowed packet types,
|
||||||
|
* mainly to ensure that enough space is allocated for the largest one.
|
||||||
|
*/
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
@ -89,6 +93,7 @@ typedef struct Packet
|
||||||
/* These are incoming and have a packet length prepended. */
|
/* These are incoming and have a packet length prepended. */
|
||||||
|
|
||||||
StartupPacket si;
|
StartupPacket si;
|
||||||
|
CancelRequestPacket canc;
|
||||||
PasswordPacketV0 pwv0;
|
PasswordPacketV0 pwv0;
|
||||||
PasswordPacket pw;
|
PasswordPacket pw;
|
||||||
} pkt;
|
} pkt;
|
||||||
|
@ -126,16 +131,15 @@ typedef struct Port
|
||||||
|
|
||||||
extern FILE *Pfout,
|
extern FILE *Pfout,
|
||||||
*Pfin;
|
*Pfin;
|
||||||
extern int PQAsyncNotifyWaiting;
|
|
||||||
extern ProtocolVersion FrontendProtocol;
|
extern ProtocolVersion FrontendProtocol;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* prototypes for functions in pqpacket.c
|
* prototypes for functions in pqpacket.c
|
||||||
*/
|
*/
|
||||||
void PacketReceiveSetup(Packet *pkt, void (*iodone) (), char *arg);
|
void PacketReceiveSetup(Packet *pkt, PacketDoneProc iodone, void *arg);
|
||||||
int PacketReceiveFragment(Packet *pkt, int sock);
|
int PacketReceiveFragment(Packet *pkt, int sock);
|
||||||
void PacketSendSetup(Packet *pkt, int nbytes, void (*iodone) (), char *arg);
|
void PacketSendSetup(Packet *pkt, int nbytes, PacketDoneProc iodone, void *arg);
|
||||||
int PacketSendFragment(Packet *pkt, int sock);
|
int PacketSendFragment(Packet *pkt, int sock);
|
||||||
void PacketSendError(Packet *pkt, char *errormsg);
|
void PacketSendError(Packet *pkt, char *errormsg);
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: libpq.h,v 1.16 1998/06/16 07:29:41 momjian Exp $
|
* $Id: libpq.h,v 1.17 1998/07/09 03:29:01 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -126,8 +126,7 @@ extern size_t portals_array_size;
|
||||||
*/
|
*/
|
||||||
typedef struct PQNotifyList
|
typedef struct PQNotifyList
|
||||||
{
|
{
|
||||||
char relname[NAMEDATALEN]; /* name of relation containing
|
char relname[NAMEDATALEN]; /* listen/notify name */
|
||||||
* data */
|
|
||||||
int be_pid; /* process id of backend */
|
int be_pid; /* process id of backend */
|
||||||
int valid; /* has this already been handled by user. */
|
int valid; /* has this already been handled by user. */
|
||||||
/* SLNode Node; */
|
/* SLNode Node; */
|
||||||
|
@ -268,8 +267,6 @@ extern int pq_getint(int b);
|
||||||
extern void pq_putstr(char *s);
|
extern void pq_putstr(char *s);
|
||||||
extern void pq_putnchar(char *s, int n);
|
extern void pq_putnchar(char *s, int n);
|
||||||
extern void pq_putint(int i, int b);
|
extern void pq_putint(int i, int b);
|
||||||
extern int pq_sendoob(char *msg, int len);
|
|
||||||
extern int pq_recvoob(char *msgPtr, int len);
|
|
||||||
extern int pq_getinaddr(struct sockaddr_in * sin, char *host, int port);
|
extern int pq_getinaddr(struct sockaddr_in * sin, char *host, int port);
|
||||||
extern int pq_getinserv(struct sockaddr_in * sin, char *host, char *serv);
|
extern int pq_getinserv(struct sockaddr_in * sin, char *host, char *serv);
|
||||||
|
|
||||||
|
@ -281,10 +278,7 @@ extern int
|
||||||
pq_connect(char *dbname, char *user, char *args, char *hostName,
|
pq_connect(char *dbname, char *user, char *args, char *hostName,
|
||||||
char *debugTty, char *execFile, short portName);
|
char *debugTty, char *execFile, short portName);
|
||||||
extern int StreamOpen(char *hostName, short portName, Port *port);
|
extern int StreamOpen(char *hostName, short portName, Port *port);
|
||||||
extern void pq_regoob(void (*fptr) ());
|
extern void StreamDoUnlink(void);
|
||||||
extern void pq_unregoob(void);
|
|
||||||
extern void pq_async_notify(void);
|
|
||||||
extern void StreamDoUnlink();
|
|
||||||
extern int StreamServerPort(char *hostName, short portName, int *fdP);
|
extern int StreamServerPort(char *hostName, short portName, int *fdP);
|
||||||
extern int StreamConnection(int server_fd, Port *port);
|
extern int StreamConnection(int server_fd, Port *port);
|
||||||
extern void StreamClose(int sock);
|
extern void StreamClose(int sock);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: pqcomm.h,v 1.25 1998/05/06 23:50:32 momjian Exp $
|
* $Id: pqcomm.h,v 1.26 1998/07/09 03:29:01 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -122,6 +122,25 @@ typedef uint32 AuthRequest;
|
||||||
typedef ProtocolVersion MsgType;
|
typedef ProtocolVersion MsgType;
|
||||||
|
|
||||||
|
|
||||||
|
/* A client can also send a cancel-current-operation request to the postmaster.
|
||||||
|
* This is uglier than sending it directly to the client's backend, but it
|
||||||
|
* avoids depending on out-of-band communication facilities.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The cancel request code must not match any protocol version number
|
||||||
|
* we're ever likely to use. This random choice should do.
|
||||||
|
*/
|
||||||
|
#define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678)
|
||||||
|
|
||||||
|
typedef struct CancelRequestPacket
|
||||||
|
{
|
||||||
|
/* Note that each field is stored in network byte order! */
|
||||||
|
MsgType cancelRequestCode; /* code to identify a cancel request */
|
||||||
|
uint32 backendPID; /* PID of client's backend */
|
||||||
|
uint32 cancelAuthCode; /* secret key to authorize cancel */
|
||||||
|
} CancelRequestPacket;
|
||||||
|
|
||||||
|
|
||||||
/* in pqcompriv.c */
|
/* in pqcompriv.c */
|
||||||
int pqGetShort(int *, FILE *);
|
int pqGetShort(int *, FILE *);
|
||||||
int pqGetLong(int *, FILE *);
|
int pqGetLong(int *, FILE *);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: miscadmin.h,v 1.26 1998/06/09 17:13:06 momjian Exp $
|
* $Id: miscadmin.h,v 1.27 1998/07/09 03:28:55 scrappy Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* some of the information in this file will be moved to
|
* some of the information in this file will be moved to
|
||||||
|
@ -42,6 +42,8 @@ extern char *DataDir;
|
||||||
|
|
||||||
extern int MyProcPid;
|
extern int MyProcPid;
|
||||||
|
|
||||||
|
extern long MyCancelKey;
|
||||||
|
|
||||||
extern char OutputFileName[];
|
extern char OutputFileName[];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include <limits.h> /* For _POSIX_PATH_MAX */
|
#include <limits.h> /* For _POSIX_PATH_MAX */
|
||||||
|
|
||||||
#define MAXPATHLEN _POSIX_PATH_MAX
|
#define MAXPATHLEN _POSIX_PATH_MAX
|
||||||
#define SIGURG SIGUSR1
|
|
||||||
|
|
||||||
#define NOFILE NOFILES_MIN
|
#define NOFILE NOFILES_MIN
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
PGresult *res;
|
||||||
struct hostent *hp;
|
struct hostent *hp;
|
||||||
|
|
||||||
StartupPacket sp;
|
StartupPacket sp;
|
||||||
AuthRequest areq;
|
AuthRequest areq;
|
||||||
int laddrlen = sizeof(SockAddr);
|
int laddrlen = sizeof(SockAddr);
|
||||||
int portno,
|
int portno,
|
||||||
family,
|
family;
|
||||||
len;
|
|
||||||
char beresp;
|
char beresp;
|
||||||
int on = 1;
|
int on = 1;
|
||||||
|
|
||||||
|
@ -561,11 +559,11 @@ connectDB(PGconn *conn)
|
||||||
(char *) hp->h_addr,
|
(char *) hp->h_addr,
|
||||||
hp->h_length);
|
hp->h_length);
|
||||||
conn->raddr.in.sin_port = htons((unsigned short) (portno));
|
conn->raddr.in.sin_port = htons((unsigned short) (portno));
|
||||||
len = sizeof(struct sockaddr_in);
|
conn->raddr_len = sizeof(struct sockaddr_in);
|
||||||
}
|
}
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
else
|
else
|
||||||
len = UNIXSOCK_PATH(conn->raddr.un, portno);
|
conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -577,7 +575,7 @@ connectDB(PGconn *conn)
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
goto connect_errReturn;
|
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,
|
(void) sprintf(conn->errorMessage,
|
||||||
"connectDB() failed: Is the postmaster running and accepting%s connections at '%s' on port '%s'?\n",
|
"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,
|
* A ReadyForQuery message indicates that startup is successful,
|
||||||
* but we might also get an Error message indicating failure.
|
* but we might also get an Error message indicating failure.
|
||||||
* (Notice messages indicating nonfatal warnings are also allowed
|
* (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.
|
* 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.
|
* 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.
|
* PacketSend() -- send a single-packet message.
|
||||||
* this is like PacketSend(), defined in backend/libpq/pqpacket.c
|
* this is like PacketSend(), defined in backend/libpq/pqpacket.c
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.55 1998/07/03 04:24:13 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.56 1998/07/09 03:29:08 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -361,6 +361,16 @@ parseInput(PGconn *conn)
|
||||||
PGRES_EMPTY_QUERY);
|
PGRES_EMPTY_QUERY);
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
conn->asyncStatus = PGASYNC_READY;
|
||||||
break;
|
break;
|
||||||
|
case 'K': /* secret key data from the backend */
|
||||||
|
/* This is expected only during backend startup,
|
||||||
|
* but it's just as easy to handle it as part of the
|
||||||
|
* main loop. Save the data and continue processing.
|
||||||
|
*/
|
||||||
|
if (pqGetInt(&(conn->be_pid), 4, conn))
|
||||||
|
return;
|
||||||
|
if (pqGetInt(&(conn->be_key), 4, conn))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
case 'N': /* notices from the backend */
|
case 'N': /* notices from the backend */
|
||||||
if (getNotice(conn))
|
if (getNotice(conn))
|
||||||
return;
|
return;
|
||||||
|
@ -761,44 +771,6 @@ PQexec(PGconn *conn, const char *query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
PQrequestCancel(PGconn *conn)
|
|
||||||
{
|
|
||||||
char msg[1];
|
|
||||||
|
|
||||||
if (!conn)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (conn->sock < 0)
|
|
||||||
{
|
|
||||||
sprintf(conn->errorMessage,
|
|
||||||
"PQrequestCancel() -- connection is not open\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg[0] = '\0';
|
|
||||||
|
|
||||||
if (send(conn->sock, msg, 1, MSG_OOB) < 0)
|
|
||||||
{
|
|
||||||
sprintf(conn->errorMessage,
|
|
||||||
"PQrequestCancel() -- couldn't send OOB data: errno=%d\n%s\n",
|
|
||||||
errno, strerror(errno));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attempt to read a Notice response message.
|
* Attempt to read a Notice response message.
|
||||||
* This is possible in several places, so we break it out as a subroutine.
|
* This is possible in several places, so we break it out as a subroutine.
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: libpq-fe.h,v 1.30 1998/06/16 07:29:49 momjian Exp $
|
* $Id: libpq-fe.h,v 1.31 1998/07/09 03:29:09 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -174,8 +174,11 @@ extern "C"
|
||||||
int sock; /* Unix FD for socket, -1 if not connected */
|
int sock; /* Unix FD for socket, -1 if not connected */
|
||||||
SockAddr laddr; /* Local address */
|
SockAddr laddr; /* Local address */
|
||||||
SockAddr raddr; /* Remote address */
|
SockAddr raddr; /* Remote address */
|
||||||
|
int raddr_len; /* Length of remote address */
|
||||||
|
|
||||||
/* Miscellaneous stuff */
|
/* Miscellaneous stuff */
|
||||||
|
int be_pid; /* PID of backend --- needed for cancels */
|
||||||
|
int be_key; /* key of backend --- needed for cancels */
|
||||||
char salt[2]; /* password salt received from backend */
|
char salt[2]; /* password salt received from backend */
|
||||||
PGlobjfuncs *lobjfuncs; /* private state for large-object access fns */
|
PGlobjfuncs *lobjfuncs; /* private state for large-object access fns */
|
||||||
|
|
||||||
|
@ -273,6 +276,8 @@ extern "C"
|
||||||
#define PQsetdb(M_PGHOST,M_PGPORT,M_PGOPT,M_PGTTY,M_DBNAME) PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, NULL, NULL)
|
#define PQsetdb(M_PGHOST,M_PGPORT,M_PGOPT,M_PGTTY,M_DBNAME) PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, NULL, NULL)
|
||||||
/* close the current connection and free the PGconn data structure */
|
/* close the current connection and free the PGconn data structure */
|
||||||
extern void PQfinish(PGconn *conn);
|
extern void PQfinish(PGconn *conn);
|
||||||
|
/* issue a cancel request */
|
||||||
|
extern int PQrequestCancel(PGconn *conn);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close the current connection and restablish a new one with the same
|
* close the current connection and restablish a new one with the same
|
||||||
|
@ -305,7 +310,6 @@ extern "C"
|
||||||
/* Routines for managing an asychronous query */
|
/* Routines for managing an asychronous query */
|
||||||
extern int PQisBusy(PGconn *conn);
|
extern int PQisBusy(PGconn *conn);
|
||||||
extern void PQconsumeInput(PGconn *conn);
|
extern void PQconsumeInput(PGconn *conn);
|
||||||
extern int PQrequestCancel(PGconn *conn);
|
|
||||||
/* Routines for copy in/out */
|
/* Routines for copy in/out */
|
||||||
extern int PQgetline(PGconn *conn, char *string, int length);
|
extern int PQgetline(PGconn *conn, char *string, int length);
|
||||||
extern void PQputline(PGconn *conn, const char *string);
|
extern void PQputline(PGconn *conn, const char *string);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
.\" This is -*-nroff-*-
|
.\" This is -*-nroff-*-
|
||||||
.\" XXX standard disclaimer belongs here....
|
.\" XXX standard disclaimer belongs here....
|
||||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/listen.l,v 1.6 1998/06/24 13:21:27 momjian Exp $
|
.\" $Header: /cvsroot/pgsql/src/man/Attic/listen.l,v 1.7 1998/07/09 03:29:09 scrappy Exp $
|
||||||
.TH "LISTEN" SQL 03/12/94 PostgreSQL PostgreSQL
|
.TH "LISTEN" SQL 03/12/94 PostgreSQL PostgreSQL
|
||||||
.SH NAME
|
.SH NAME
|
||||||
listen - listen for notification on a relation
|
listen - listen for notification on a relation
|
||||||
|
@ -21,9 +21,7 @@ is cleared.
|
||||||
.PP
|
.PP
|
||||||
This event notification is performed through the Libpq protocol
|
This event notification is performed through the Libpq protocol
|
||||||
and frontend application interface. The application program
|
and frontend application interface. The application program
|
||||||
must explicitly poll a Libpq global variable,
|
must call the routine
|
||||||
.IR PQAsyncNotifyWaiting ,
|
|
||||||
and call the routine
|
|
||||||
.IR PQnotifies
|
.IR PQnotifies
|
||||||
in order to find out the name of the class to which a given
|
in order to find out the name of the class to which a given
|
||||||
notification corresponds. If this code is not included in
|
notification corresponds. If this code is not included in
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
.\" This is -*-nroff-*-
|
.\" This is -*-nroff-*-
|
||||||
.\" XXX standard disclaimer belongs here....
|
.\" XXX standard disclaimer belongs here....
|
||||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/notify.l,v 1.4 1998/06/24 13:21:27 momjian Exp $
|
.\" $Header: /cvsroot/pgsql/src/man/Attic/notify.l,v 1.5 1998/07/09 03:29:11 scrappy Exp $
|
||||||
.TH "NOTIFY" SQL 11/05/95 PostgreSQL PostgreSQL
|
.TH "NOTIFY" SQL 11/05/95 PostgreSQL PostgreSQL
|
||||||
.SH NAME
|
.SH NAME
|
||||||
notify - signal all frontends and backends listening on a class
|
notify - signal all frontends and backends listening on a class
|
||||||
|
@ -32,11 +32,14 @@ does is indicate that some backend wishes its peers to examine
|
||||||
.IR class_name
|
.IR class_name
|
||||||
in some application-specific way.
|
in some application-specific way.
|
||||||
.PP
|
.PP
|
||||||
|
In fact,
|
||||||
|
.IR class_name
|
||||||
|
need not be the name of an SQL class at all. It is best thought of
|
||||||
|
as a condition name that the application programmer selects.
|
||||||
|
.PP
|
||||||
This event notification is performed through the Libpq protocol
|
This event notification is performed through the Libpq protocol
|
||||||
and frontend application interface. The application program
|
and frontend application interface. The application program
|
||||||
must explicitly poll a Libpq global variable,
|
must call the routine
|
||||||
.IR PQAsyncNotifyWaiting ,
|
|
||||||
and call the routine
|
|
||||||
.IR PQnotifies
|
.IR PQnotifies
|
||||||
in order to find out the name of the class to which a given
|
in order to find out the name of the class to which a given
|
||||||
notification corresponds. If this code is not included in
|
notification corresponds. If this code is not included in
|
||||||
|
|
Loading…
Reference in New Issue