forked from pgbouncer/pgbouncer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmessages.c
208 lines (163 loc) · 5.56 KB
/
messages.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#include "bouncer.h"
/* Inspect Parse packet to see if it defines a named prepared statement */
PreparedStatementAction inspect_parse_packet(PgSocket *client, PktHdr *pkt)
{
const char *statement;
if (!mbuf_get_string(&pkt->data, &statement))
return PS_INSPECT_FAILED;
if (!*statement) { /* ignore empty statements */
slog_noise(client, "inspect_parse_packet: type=%c, len=%d, statement=<empty>", pkt->type, pkt->len);
return PS_IGNORE;
}
slog_noise(client, "inspect_parse_packet: type=%c, len=%d, statement=%s", pkt->type, pkt->len, statement);
return PS_HANDLE_FULL_PACKET;
}
/* Inspect Bind packet to see if it defines a named prepared statement */
PreparedStatementAction inspect_bind_packet(PgSocket *client, PktHdr *pkt)
{
const char *portal;
const char *statement;
if (!mbuf_get_string(&pkt->data, &portal))
return PS_INSPECT_FAILED;
if (!mbuf_get_string(&pkt->data, &statement))
return PS_INSPECT_FAILED;
if (!*statement) { /* ignore empty statements */
slog_noise(client, "inspect_bind_packet: type=%c, len=%d, statement=<empty>", pkt->type, pkt->len);
return PS_IGNORE;
}
slog_noise(client, "inspect_bind_packet: type=%c, len=%d, statement=%s", pkt->type, pkt->len, statement);
return PS_HANDLE;
}
/* Inspect Describe packet to see if it defines a named prepared statement */
PreparedStatementAction inspect_describe_or_close_packet(PgSocket *client, PktHdr *pkt)
{
char describe;
const char *statement;
if (!mbuf_get_char(&pkt->data, &describe))
return PS_INSPECT_FAILED;
if (describe != 'S') {
slog_noise(client, "inspect_describe_or_close_packet: type=%c, len=%d, P/S=%c", pkt->type, pkt->len, describe);
return PS_IGNORE;
}
if (!mbuf_get_string(&pkt->data, &statement))
return PS_INSPECT_FAILED;
if (!*statement) { /* ignore empty statements */
slog_noise(client, "inspect_describe_or_close_packet: type=%c, len=%d, P/S=%c, statement=<empty>", pkt->type, pkt->len, describe);
return PS_IGNORE;
}
slog_noise(client, "inspect_describe_or_close_packet: type=%c, len=%d, P/S=%c, statement=%s", pkt->type, pkt->len, describe, statement);
return PS_HANDLE;
}
/*
* Unmarshall Parse packet into PgParsePacket struct for further processing.
*
* Note: The PgParsePacket still references the data stored in the PktHdr. So
* the PktHdr should not be freed until the PgParsePacket is not necessary
* anymore.
*/
bool unmarshall_parse_packet(PgSocket *client, PktHdr *pkt, PgParsePacket *parse_packet)
{
const char *statement;
const char *query;
uint16_t num_parameters;
const uint8_t *parameter_types_bytes;
size_t parameters_length;
if (!mbuf_get_string(&pkt->data, &statement))
goto failed;
if (!mbuf_get_string(&pkt->data, &query))
goto failed;
/* number of parameter data types */
if (!mbuf_get_uint16be(&pkt->data, &num_parameters))
goto failed;
parameters_length = (size_t) num_parameters * 4;
if (!mbuf_get_bytes(&pkt->data, parameters_length, ¶meter_types_bytes))
goto failed;
parse_packet->len = pkt->len;
parse_packet->name = statement;
parse_packet->query_and_parameters_len =
strlen(query)
+ 1 /* \0 */
+ sizeof(num_parameters)
+ parameters_length;
parse_packet->query_and_parameters = query;
return true;
failed:
disconnect_client(client, true, "broken Parse packet");
return false;
}
/*
* Unmarshall (partial) Bind packet into PgBindPacket struct for further processing
*
* Note: The PgBindPacket still references the data stored in the PktHdr. So
* the PktHdr should not be freed until the PgBindPacket is not necessary
* anymore.
*/
bool unmarshall_bind_packet(PgSocket *client, PktHdr *pkt, PgBindPacket *bind_packet)
{
const char *portal;
const char *statement;
if (!mbuf_get_string(&pkt->data, &portal))
goto failed;
if (!mbuf_get_string(&pkt->data, &statement))
goto failed;
bind_packet->len = pkt->len;
bind_packet->portal = portal;
bind_packet->name = statement;
return true;
failed:
disconnect_client(client, true, "broken Bind packet");
return false;
}
/*
* Unmarshall Describe packet into PgDescribePacket struct for further processing
*
* Note: The PgDescribePacket still references the data stored in the PktHdr. So
* the PktHdr should not be freed until the PgDescribePacket is not necessary
* anymore.
*/
bool unmarshall_describe_packet(PgSocket *client, PktHdr *pkt, PgDescribePacket *describe_packet)
{
char describe;
const char *statement;
if (incomplete_pkt(pkt))
return false;
if (!mbuf_get_char(&pkt->data, &describe))
goto failed;
if (!mbuf_get_string(&pkt->data, &statement))
goto failed;
describe_packet->type = describe;
describe_packet->name = statement;
return true;
failed:
disconnect_client(client, true, "broken Describe packet");
return false;
}
/*
* Unmarshall Close packet into PgClosePacket struct for further processing
*
* Note: The PgClosePacket still references the data stored in the PktHdr. So
* the PktHdr should not be freed until the PgClosePacket is not necessary
* anymore.
*/
bool unmarshall_close_packet(PgSocket *client, PktHdr *pkt, PgClosePacket *close_packet)
{
char type;
const char *name;
if (incomplete_pkt(pkt))
return false;
if (!mbuf_get_char(&pkt->data, &type))
goto failed;
if (!mbuf_get_string(&pkt->data, &name))
goto failed;
close_packet->type = type;
close_packet->name = name;
slog_noise(client, "unmarshall_close_packet: type=%c, len=%d, S/P=%c, name=%s", pkt->type, pkt->len, type, name);
return true;
failed:
disconnect_client(client, true, "broken Close packet");
return false;
}
bool is_close_named_statement_packet(PgClosePacket *close_packet)
{
return close_packet->type == 'S' && *close_packet->name;
}