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 209 210 211 212 213 214 215 216 217
|
/*
* PgBouncer - Lightweight connection pooler for PostgreSQL.
*
* Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Safe & easy creation of PostgreSQL packets.
*/
#include "common/protocol.h"
typedef struct PktBuf PktBuf;
struct PktBuf {
uint8_t *buf;
int buf_len;
int write_pos;
int pktlen_pos;
int send_pos;
struct event *ev;
PgSocket *queued_dst;
bool failed : 1;
bool sending : 1;
bool fixed_buf : 1;
};
/*
* pktbuf creation
*/
PktBuf *pktbuf_dynamic(int start_len) _MUSTCHECK;
void pktbuf_static(PktBuf *buf, uint8_t *data, int len);
void pktbuf_free(PktBuf *buf);
void pktbuf_reset(struct PktBuf *pkt);
struct PktBuf *pktbuf_temp(void);
/*
* sending
*/
bool pktbuf_send_immediate(PktBuf *buf, PgSocket *sk) _MUSTCHECK;
bool pktbuf_send_queued(PktBuf *buf, PgSocket *sk) _MUSTCHECK;
/*
* low-level ops
*/
void pktbuf_start_packet(PktBuf *buf, int type);
void pktbuf_put_char(PktBuf *buf, char val);
void pktbuf_put_uint16(PktBuf *buf, uint16_t val);
void pktbuf_put_uint32(PktBuf *buf, uint32_t val);
void pktbuf_put_uint64(PktBuf *buf, uint64_t val);
void pktbuf_put_string(PktBuf *buf, const char *str);
void pktbuf_put_bytes(PktBuf *buf, const void *data, int len);
void pktbuf_finish_packet(PktBuf *buf);
#define pktbuf_written(buf) ((buf)->write_pos)
/*
* Packet writing
*/
void pktbuf_write_generic(PktBuf *buf, int type, const char *fmt, ...);
void pktbuf_write_RowDescription(PktBuf *buf, const char *tupdesc, ...);
void pktbuf_write_DataRow(PktBuf *buf, const char *tupdesc, ...);
void pktbuf_write_ExtQuery(PktBuf *buf, const char *query, int nargs, ...);
/*
* Shortcuts for actual packets.
*/
#define pktbuf_write_ParameterStatus(buf, key, val) \
pktbuf_write_generic(buf, PqMsg_ParameterStatus, "ss", key, val)
#define pktbuf_write_AuthenticationOk(buf) \
pktbuf_write_generic(buf, PqMsg_AuthenticationRequest, "i", 0)
#define pktbuf_write_ReadyForQuery(buf) \
pktbuf_write_generic(buf, PqMsg_ReadyForQuery, "c", 'I')
#define pktbuf_write_CommandComplete(buf, desc) \
pktbuf_write_generic(buf, PqMsg_CommandComplete, "s", desc)
#define pktbuf_write_BackendKeyData(buf, key) \
pktbuf_write_generic(buf, PqMsg_BackendKeyData, "b", key, 8)
#define pktbuf_write_CancelRequest(buf, key) \
pktbuf_write_generic(buf, PKT_CANCEL, "b", key, 8)
#define pktbuf_write_NegotiateProtocolVersion( \
buf, \
unsupported_protocol_extensions_count, \
unsupported_protocol_extensions_bytes, \
unsupported_protocol_extensions_bytes_length) \
pktbuf_write_generic(buf, PqMsg_NegotiateProtocolVersion, "iib", PKT_STARTUP_V3, unsupported_protocol_extensions_count, unsupported_protocol_extensions_bytes, unsupported_protocol_extensions_bytes_length)
#define pktbuf_write_PasswordMessage(buf, psw) \
pktbuf_write_generic(buf, PqMsg_PasswordMessage, "s", psw)
#define pkgbuf_write_SASLInitialResponseMessage(buf, mech, cir) \
pktbuf_write_generic(buf, PqMsg_SASLInitialResponse, "sib", mech, strlen(cir), cir, strlen(cir))
#define pkgbuf_write_SASLResponseMessage(buf, cr) \
pktbuf_write_generic(buf, PqMsg_SASLResponse, "b", cr, strlen(cr))
#define pktbuf_write_Notice(buf, msg) \
pktbuf_write_generic(buf, PqMsg_NoticeResponse, "sscss", "SNOTICE", "C00000", 'M', msg, "");
#define pktbuf_write_SSLRequest(buf) \
pktbuf_write_generic(buf, PKT_SSLREQ, "")
#define pktbuf_write_Parse(buf, stmt, query_and_parameters, query_and_parameters_len) \
pktbuf_write_generic(buf, PqMsg_Parse, "sb", stmt, query_and_parameters, query_and_parameters_len)
#define pktbuf_write_ParseComplete(buf) \
pktbuf_write_generic(buf, PqMsg_ParseComplete, "")
#define pktbuf_write_DescribeStmt(buf, stmt) \
pktbuf_write_generic(buf, PqMsg_Describe, "cs", 'S', stmt)
#define pktbuf_write_CloseStmt(buf, stmt) \
pktbuf_write_generic(buf, PqMsg_Close, "cs", 'S', stmt)
#define pktbuf_write_CloseComplete(buf) \
pktbuf_write_generic(buf, PqMsg_CloseComplete, "")
/*
* Shortcut for creating DataRow in memory.
*/
#define BUILD_DataRow(reslen, dst, dstlen, args...) do { \
PktBuf _buf; \
pktbuf_static(&_buf, dst, dstlen); \
pktbuf_write_DataRow(&_buf, ## args); \
reslen = _buf.failed ? -1 : _buf.write_pos; \
} while (0)
/*
* Shortcuts for immediate send of one packet. These should only be used when
* server and client are not linked yet. Otherwise the data sent by these
* functions might get sent right in the middle of a message send by the other
* side of the link.
*
* NOTE: If the OS socket buffer is full then these functions return failure. So
* only use these functions when that is so unlikely that we don't expect that
* to ever happen in practice.
*/
#define SEND_wrap(buflen, pktfn, res, sk, args...) do { \
uint8_t _data[buflen]; PktBuf _buf; \
pktbuf_static(&_buf, _data, sizeof(_data)); \
pktfn(&_buf, ## args); \
res = pktbuf_send_immediate(&_buf, sk); \
} while (0)
#define SEND_RowDescription(res, sk, args...) \
SEND_wrap(512, pktbuf_write_RowDescription, res, sk, ## args)
#define SEND_generic(res, sk, args...) \
SEND_wrap(512, pktbuf_write_generic, res, sk, ## args)
#define SEND_ReadyForQuery(res, sk) \
SEND_wrap(8, pktbuf_write_ReadyForQuery, res, sk)
#define SEND_CancelRequest(res, sk, key) \
SEND_wrap(16, pktbuf_write_CancelRequest, res, sk, key)
#define SEND_PasswordMessage(res, sk, psw) \
SEND_wrap(MAX_PASSWORD + 8, pktbuf_write_PasswordMessage, res, sk, psw)
#define SEND_SASLInitialResponseMessage(res, sk, mech, cir) \
SEND_wrap(512, pkgbuf_write_SASLInitialResponseMessage, res, sk, mech, cir)
#define SEND_SASLResponseMessage(res, sk, cr) \
SEND_wrap(512, pkgbuf_write_SASLResponseMessage, res, sk, cr)
#define SEND_CloseComplete(res, sk) \
SEND_wrap(5, pktbuf_write_CloseComplete, res, sk)
/*
* Shortcuts for queueing one packet. These should only be used when the server
* and client are linked. They wait with actually sending the data until a
* any partially sent packet from the other side of the link has been fully
* sent.
*/
#define QUEUE_wrap(buflen, pktfn, res, source, target, args...) do { \
uint8_t _data[buflen]; PktBuf _buf; \
pktbuf_static(&_buf, _data, sizeof(_data)); \
pktfn(&_buf, ## args); \
res = sbuf_queue_packet(&source->sbuf, &target->sbuf, &_buf); \
} while (0)
#define QUEUE_ParseComplete(res, source, target) \
QUEUE_wrap(5, pktbuf_write_ParseComplete, res, source, target)
#define QUEUE_DescribeStmt(res, source, target, statement) \
QUEUE_wrap(6 + MAX_SERVER_PREPARED_STMT_NAME, pktbuf_write_DescribeStmt, res, source, target, statement)
#define QUEUE_CloseStmt(res, source, target, statement) \
QUEUE_wrap(6 + MAX_SERVER_PREPARED_STMT_NAME, pktbuf_write_CloseStmt, res, source, target, statement)
#define QUEUE_CloseComplete(res, source, target) \
QUEUE_wrap(5, pktbuf_write_CloseComplete, res, source, target)
void pktbuf_cleanup(void);
|