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