1 /*
2  * PgBouncer - Lightweight connection pooler for PostgreSQL.
3  *
4  * Copyright (c) 2007-2009  Marko Kreen, Skype Technologies OÜ
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Safe & easy creation of PostgreSQL packets.
21  */
22 
23 typedef struct PktBuf PktBuf;
24 struct PktBuf {
25 	uint8_t *buf;
26 	int buf_len;
27 	int write_pos;
28 	int pktlen_pos;
29 
30 	int send_pos;
31 	struct event *ev;
32 	PgSocket *queued_dst;
33 
34 	bool failed:1;
35 	bool sending:1;
36 	bool fixed_buf:1;
37 };
38 
39 /*
40  * pktbuf creation
41  */
42 PktBuf *pktbuf_dynamic(int start_len)	_MUSTCHECK;
43 void pktbuf_static(PktBuf *buf, uint8_t *data, int len);
44 
45 void pktbuf_free(PktBuf *buf);
46 
47 void pktbuf_reset(struct PktBuf *pkt);
48 struct PktBuf *pktbuf_temp(void);
49 
50 
51 /*
52  * sending
53  */
54 bool pktbuf_send_immediate(PktBuf *buf, PgSocket *sk)	_MUSTCHECK;
55 bool pktbuf_send_queued(PktBuf *buf, PgSocket *sk)  _MUSTCHECK;
56 
57 /*
58  * low-level ops
59  */
60 void pktbuf_start_packet(PktBuf *buf, int type);
61 void pktbuf_put_char(PktBuf *buf, char val);
62 void pktbuf_put_uint16(PktBuf *buf, uint16_t val);
63 void pktbuf_put_uint32(PktBuf *buf, uint32_t val);
64 void pktbuf_put_uint64(PktBuf *buf, uint64_t val);
65 void pktbuf_put_string(PktBuf *buf, const char *str);
66 void pktbuf_put_bytes(PktBuf *buf, const void *data, int len);
67 void pktbuf_finish_packet(PktBuf *buf);
68 #define pktbuf_written(buf) ((buf)->write_pos)
69 
70 
71 /*
72  * Packet writing
73  */
74 void pktbuf_write_generic(PktBuf *buf, int type, const char *fmt, ...);
75 void pktbuf_write_RowDescription(PktBuf *buf, const char *tupdesc, ...);
76 void pktbuf_write_DataRow(PktBuf *buf, const char *tupdesc, ...);
77 void pktbuf_write_ExtQuery(PktBuf *buf, const char *query, int nargs, ...);
78 
79 /*
80  * Shortcuts for actual packets.
81  */
82 #define pktbuf_write_ParameterStatus(buf, key, val) \
83 	pktbuf_write_generic(buf, 'S', "ss", key, val)
84 
85 #define pktbuf_write_AuthenticationOk(buf) \
86 	pktbuf_write_generic(buf, 'R', "i", 0)
87 
88 #define pktbuf_write_ReadyForQuery(buf) \
89 	pktbuf_write_generic(buf, 'Z', "c", 'I')
90 
91 #define pktbuf_write_CommandComplete(buf, desc) \
92 	pktbuf_write_generic(buf, 'C', "s", desc)
93 
94 #define pktbuf_write_BackendKeyData(buf, key) \
95 	pktbuf_write_generic(buf, 'K', "b", key, 8)
96 
97 #define pktbuf_write_CancelRequest(buf, key) \
98 	pktbuf_write_generic(buf, PKT_CANCEL, "b", key, 8)
99 
100 #define pktbuf_write_StartupMessage(buf, user, parms, parms_len) \
101 	pktbuf_write_generic(buf, PKT_STARTUP, "bsss", parms, parms_len, "user", user, "")
102 
103 #define pktbuf_write_PasswordMessage(buf, psw) \
104 	pktbuf_write_generic(buf, 'p', "s", psw)
105 
106 #define pkgbuf_write_SASLInitialResponseMessage(buf, mech, cir) \
107 	pktbuf_write_generic(buf, 'p', "sib", mech, strlen(cir), cir, strlen(cir))
108 
109 #define pkgbuf_write_SASLResponseMessage(buf, cr) \
110 	pktbuf_write_generic(buf, 'p', "b", cr, strlen(cr))
111 
112 #define pktbuf_write_Notice(buf, msg) \
113 	pktbuf_write_generic(buf, 'N', "sscss", "SNOTICE", "C00000", 'M', msg, "");
114 
115 #define pktbuf_write_SSLRequest(buf) \
116 	pktbuf_write_generic(buf, PKT_SSLREQ, "")
117 
118 /*
119  * Shortcut for creating DataRow in memory.
120  */
121 
122 #define BUILD_DataRow(reslen, dst, dstlen, args...) do { \
123 	PktBuf _buf; \
124 	pktbuf_static(&_buf, dst, dstlen); \
125 	pktbuf_write_DataRow(&_buf, ## args); \
126 	reslen = _buf.failed ? -1 : _buf.write_pos; \
127 } while (0)
128 
129 /*
130  * Shortcuts for immediate send of one packet.
131  */
132 
133 #define SEND_wrap(buflen, pktfn, res, sk, args...) do { \
134 	uint8_t _data[buflen]; PktBuf _buf; \
135 	pktbuf_static(&_buf, _data, sizeof(_data)); \
136 	pktfn(&_buf, ## args); \
137 	res = pktbuf_send_immediate(&_buf, sk); \
138 } while (0)
139 
140 #define SEND_RowDescription(res, sk, args...) \
141 	SEND_wrap(512, pktbuf_write_RowDescription, res, sk, ## args)
142 
143 #define SEND_generic(res, sk, args...) \
144 	SEND_wrap(512, pktbuf_write_generic, res, sk, ## args)
145 
146 #define SEND_ReadyForQuery(res, sk) \
147 	SEND_wrap(8, pktbuf_write_ReadyForQuery, res, sk)
148 
149 #define SEND_CancelRequest(res, sk, key) \
150 	SEND_wrap(16, pktbuf_write_CancelRequest, res, sk, key)
151 
152 #define SEND_PasswordMessage(res, sk, psw) \
153 	SEND_wrap(MAX_PASSWORD + 8, pktbuf_write_PasswordMessage, res, sk, psw)
154 
155 #define SEND_SASLInitialResponseMessage(res, sk, mech, cir) \
156 	SEND_wrap(512, pkgbuf_write_SASLInitialResponseMessage, res, sk, mech, cir)
157 
158 #define SEND_SASLResponseMessage(res, sk, cr) \
159 	SEND_wrap(512, pkgbuf_write_SASLResponseMessage, res, sk, cr)
160 
161 void pktbuf_cleanup(void);
162